From 7afbd7dc2ea28921ac33c136796b4762195be8c8 Mon Sep 17 00:00:00 2001 From: Gary Pennington Date: Thu, 9 Dec 2021 11:17:51 +0000 Subject: [PATCH] Add a basic health check to the router (#252) * Add a basic health check to the router Provide a health check endpoint which behaves in the same way as the health check on the gateway. At this point in time it always returns pass because we don't have a different health status to set. resolves: #54 --- ...tests__it_provides_health_status_body.snap | 6 +++ ...sts__it_provides_health_status_header.snap | 6 +++ apollo-router/src/warp_http_server_factory.rs | 50 ++++++++++++++++++- 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_body.snap create mode 100644 apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_header.snap diff --git a/apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_body.snap b/apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_body.snap new file mode 100644 index 000000000..3bc3c21cb --- /dev/null +++ b/apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_body.snap @@ -0,0 +1,6 @@ +--- +source: apollo-router/src/warp_http_server_factory.rs +expression: "String::from_utf8_lossy(res.body())" + +--- +"{\"status\":\"pass\"}" diff --git a/apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_header.snap b/apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_header.snap new file mode 100644 index 000000000..41b497b89 --- /dev/null +++ b/apollo-router/src/snapshots/apollo_router__warp_http_server_factory__tests__it_provides_health_status_header.snap @@ -0,0 +1,6 @@ +--- +source: apollo-router/src/warp_http_server_factory.rs +expression: "hdrs[\"content-type\"].to_str().unwrap()" + +--- +application/json diff --git a/apollo-router/src/warp_http_server_factory.rs b/apollo-router/src/warp_http_server_factory.rs index b38153d7c..bc820d207 100644 --- a/apollo-router/src/warp_http_server_factory.rs +++ b/apollo-router/src/warp_http_server_factory.rs @@ -6,6 +6,7 @@ use bytes::Bytes; use futures::{channel::oneshot, prelude::*}; use hyper::server::conn::Http; use opentelemetry::propagation::Extractor; +use std::collections::HashMap; use std::pin::Pin; use std::sync::Arc; use tokio::net::TcpListener; @@ -61,7 +62,8 @@ impl HttpServerFactory for WarpHttpServerFactory { .map(tracing::Dispatch::new) .unwrap_or_default(); - let routes = get_graphql_request_or_redirect(Arc::clone(&router)) + let routes = get_health_request() + .or(get_graphql_request_or_redirect(Arc::clone(&router))) .or(post_graphql_request(router)) .with(cors); @@ -229,6 +231,19 @@ fn redirect_to_studio(host: Option) -> Box { } } +fn get_health_request() -> impl Filter,), Error = Rejection> + Clone { + warp::get() + .and(warp::path(".well-known")) + .and(warp::path("apollo")) + .and(warp::path("server-health")) + .and_then(move || async { + let mut result = HashMap::new(); + result.insert("status", "pass"); + let reply = Box::new(warp::reply::json(&result)) as Box; + Ok::<_, Rejection>(reply) + }) +} + fn post_graphql_request( router: Arc, ) -> impl Filter,), Error = Rejection> + Clone @@ -337,6 +352,7 @@ impl<'a> Extractor for HeaderMapCarrier<'a> { mod tests { use super::*; use crate::configuration::Cors; + use insta::{assert_json_snapshot, assert_snapshot}; use mockall::{mock, predicate::*}; use reqwest::header::{ ACCEPT, ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS, @@ -676,4 +692,36 @@ mod tests { .iter() .for_each(|accepts| assert!(!prefers_html(accepts.to_string()))); } + + #[test(tokio::test)] + async fn it_provides_health_status_body() -> Result<(), FederatedServerError> { + let filter = get_health_request(); + + let res = warp::test::request() + .path("/.well-known/apollo/server-health") + .reply(&filter) + .await; + + assert_eq!(res.status(), 200); + assert_json_snapshot!(String::from_utf8_lossy(res.body())); + + Ok(()) + } + + #[test(tokio::test)] + async fn it_provides_health_status_header() -> Result<(), FederatedServerError> { + let filter = get_health_request(); + + let res = warp::test::request() + .path("/.well-known/apollo/server-health") + .reply(&filter) + .await; + + let hdrs = res.headers(); + + assert_eq!(res.status(), 200); + assert_snapshot!(hdrs["content-type"].to_str().unwrap()); + + Ok(()) + } }