From 13d51250bafbdcedf5578e31275d1b18046623b2 Mon Sep 17 00:00:00 2001 From: Mofeng <52260316+DiamondMofeng@users.noreply.github.com> Date: Thu, 1 Dec 2022 19:11:58 +0800 Subject: [PATCH] feat: add http `/health` api (#676) * feat: add http `/health` api * feat: add `/health` api test suit in http intergration test --- src/servers/src/http.rs | 5 +++++ src/servers/src/http/handler.rs | 14 ++++++++++++ src/servers/tests/http/http_handler_test.rs | 15 +++++++++++++ tests-integration/tests/http.rs | 24 +++++++++++++++++++++ 4 files changed, 58 insertions(+) diff --git a/src/servers/src/http.rs b/src/servers/src/http.rs index d7bb2a5239..c12403bff2 100644 --- a/src/servers/src/http.rs +++ b/src/servers/src/http.rs @@ -380,6 +380,11 @@ impl HttpServer { router = router.route("/metrics", routing::get(handler::metrics)); + router = router.route( + "/health", + routing::get(handler::health).post(handler::health), + ); + router // middlewares .layer( diff --git a/src/servers/src/http/handler.rs b/src/servers/src/http/handler.rs index 77c68d38d8..a730d59ff4 100644 --- a/src/servers/src/http/handler.rs +++ b/src/servers/src/http/handler.rs @@ -67,3 +67,17 @@ pub async fn metrics(Query(_params): Query>) -> String { "Prometheus handle not initialized.".to_owned() } } + +#[derive(Debug, Serialize, Deserialize, JsonSchema)] +pub struct HealthQuery {} + +#[derive(Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub struct HealthResponse {} + +/// Handler to export healthy check +/// +/// Currently simply return status "200 OK" (default) with an empty json payload "{}" +#[axum_macros::debug_handler] +pub async fn health(Query(_params): Query) -> Json { + Json(HealthResponse {}) +} diff --git a/src/servers/tests/http/http_handler_test.rs b/src/servers/tests/http/http_handler_test.rs index ddec8eca54..f15a96dac0 100644 --- a/src/servers/tests/http/http_handler_test.rs +++ b/src/servers/tests/http/http_handler_test.rs @@ -135,3 +135,18 @@ fn create_query() -> Query { database: None, }) } + +/// Currently the payload of response should be simply an empty json "{}"; +#[tokio::test] +async fn test_health() { + let expected_json = http_handler::HealthResponse {}; + let expected_json_str = "{}".to_string(); + + let query = http_handler::HealthQuery {}; + let Json(json) = http_handler::health(Query(query)).await; + assert_eq!(json, expected_json); + assert_eq!( + serde_json::ser::to_string(&json).unwrap(), + expected_json_str + ); +} diff --git a/tests-integration/tests/http.rs b/tests-integration/tests/http.rs index 37c2ba7393..8d074bba67 100644 --- a/tests-integration/tests/http.rs +++ b/tests-integration/tests/http.rs @@ -15,6 +15,7 @@ use axum::http::StatusCode; use axum_test_helper::TestClient; use serde_json::json; +use servers::http::handler::HealthResponse; use servers::http::{JsonOutput, JsonResponse}; use tests_integration::test_util::{setup_test_app, setup_test_app_with_frontend, StorageType}; @@ -50,6 +51,7 @@ macro_rules! http_tests { test_sql_api, test_metrics_api, test_scripts_api, + test_health_api, ); )* }; @@ -228,3 +230,25 @@ def test(n): guard.remove_all().await; } + +pub async fn test_health_api(store_type: StorageType) { + common_telemetry::init_default_ut_logging(); + let (app, _guard) = setup_test_app_with_frontend(store_type, "health_api").await; + let client = TestClient::new(app); + + // we can call health api with both `GET` and `POST` method. + let res_post = client.post("/health").send().await; + assert_eq!(res_post.status(), StatusCode::OK); + let res_get = client.get("/health").send().await; + assert_eq!(res_get.status(), StatusCode::OK); + + // both `GET` and `POST` method return same result + let body_text = res_post.text().await; + assert_eq!(body_text, res_get.text().await); + + // currently health api simply returns an empty json `{}`, which can be deserialized to an empty `HealthResponse` + assert_eq!(body_text, "{}"); + + let body = serde_json::from_str::(&body_text).unwrap(); + assert_eq!(body, HealthResponse {}); +}