juniper/juniper_axum/tests/http_test_suite.rs
Benno Tielen 761710205a
Provide axum integration (#1088, #986, #1184)
- create `juniper_axum` crate in Cargo workspace
- implement `graphql` default `axum` handler for processing GraphQL requests
- implement `extract::JuniperRequest` and `response::JuniperResponse` for custom processing GraphQL requests
- implement `subscriptions::graphql_transport_ws()` default `axum` handler for processing the new `graphql-transport-ws` GraphQL over WebSocket Protocol
- implement `subscriptions::graphql_ws()` default `axum` handler for processing the legacy `graphql-ws` GraphQL over WebSocket Protocol
- implement `subscriptions::serve_graphql_transport_ws()` function for custom processing the new `graphql-transport-ws` GraphQL over WebSocket Protocol
- implement `subscriptions::serve_graphql_ws()` function for custom processing the legacy `graphql-ws` GraphQL over WebSocket Protocol
- provide `examples/simple.rs` of default `juniper_axum` integration
- provide `examples/custom.rs` of custom `juniper_axum` integration

Additionally:
- fix `junper_actix` crate MSRV to 1.73
- add `test_post_with_variables()` case to integration `juniper::http::tests`

Co-authored-by: ilslv <ilya.solovyiov@gmail.com>
Co-authored-by: Christian Legnitto <LegNeato@users.noreply.github.com>
Co-authored-by: Kai Ren <tyranron@gmail.com>
2023-11-09 11:57:00 +01:00

112 lines
3.3 KiB
Rust

use std::sync::Arc;
use axum::{
http::Request,
response::Response,
routing::{get, post},
Extension, Router,
};
use hyper::{service::Service, Body};
use juniper::{
http::tests::{run_http_test_suite, HttpIntegration, TestResponse},
tests::fixtures::starwars::schema::{Database, Query},
EmptyMutation, EmptySubscription, RootNode,
};
use juniper_axum::{extract::JuniperRequest, response::JuniperResponse};
type Schema = RootNode<'static, Query, EmptyMutation<Database>, EmptySubscription<Database>>;
struct TestApp(Router);
impl TestApp {
fn new() -> Self {
#[axum::debug_handler]
async fn graphql(
Extension(schema): Extension<Arc<Schema>>,
Extension(database): Extension<Database>,
JuniperRequest(request): JuniperRequest,
) -> JuniperResponse {
JuniperResponse(request.execute(&*schema, &database).await)
}
let schema = Schema::new(Query, EmptyMutation::new(), EmptySubscription::new());
let database = Database::new();
Self(
Router::new()
.route("/", get(graphql))
.route("/", post(graphql))
.layer(Extension(Arc::new(schema)))
.layer(Extension(database)),
)
}
fn make_request(&self, req: Request<Body>) -> TestResponse {
let mut app = self.0.clone();
let task = app.call(req);
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap()
.block_on(async move {
// PANIC: Unwrapping is OK here, because `task` is `Infallible`.
let resp = task.await.unwrap();
into_test_response(resp).await
})
}
}
impl HttpIntegration for TestApp {
fn get(&self, url: &str) -> TestResponse {
let req = Request::get(url).body(Body::empty()).unwrap();
self.make_request(req)
}
fn post_json(&self, url: &str, body: &str) -> TestResponse {
let req = Request::post(url)
.header("content-type", "application/json")
.body(Body::from(body.to_string()))
.unwrap();
self.make_request(req)
}
fn post_graphql(&self, url: &str, body: &str) -> TestResponse {
let req = Request::post(url)
.header("content-type", "application/graphql")
.body(Body::from(body.to_string()))
.unwrap();
self.make_request(req)
}
}
/// Converts the provided [`Response`] into to a [`TestResponse`].
async fn into_test_response(resp: Response) -> TestResponse {
let status_code = resp.status().as_u16().into();
let content_type: String = resp
.headers()
.get("content-type")
.map(|header| {
String::from_utf8(header.as_bytes().into())
.unwrap_or_else(|e| panic!("not UTF-8 header: {e}"))
})
.unwrap_or_default();
let body = hyper::body::to_bytes(resp.into_body())
.await
.unwrap_or_else(|e| panic!("failed to represent `Body` as `Bytes`: {e}"));
let body = String::from_utf8(body.into()).unwrap_or_else(|e| panic!("not UTF-8 body: {e}"));
TestResponse {
status_code,
content_type,
body: Some(body),
}
}
#[test]
fn test_axum_integration() {
run_http_test_suite(&TestApp::new())
}