#![allow(clippy::unwrap_used)]
use std::sync::Arc;
use axum::{
Router,
body::Body,
routing::{get, post},
};
use fraiseql_core::{runtime::Executor, schema::CompiledSchema};
use fraiseql_server::routes::{
api::{
query::{explain_handler, stats_handler, validate_handler},
schema::{export_json_handler, export_sdl_handler},
},
graphql::AppState,
health::health_handler,
introspection::introspection_handler,
};
use fraiseql_test_utils::{
failing_adapter::FailingAdapter,
schema_builder::{TestQueryBuilder, TestSchemaBuilder, TestTypeBuilder},
};
use http::{Request, StatusCode};
use tower::ServiceExt;
pub fn make_test_state() -> AppState<FailingAdapter> {
let schema = CompiledSchema::new();
let adapter = Arc::new(FailingAdapter::new());
AppState::new(Arc::new(Executor::new(schema, adapter)))
}
pub fn make_populated_test_state() -> AppState<FailingAdapter> {
use fraiseql_core::schema::FieldType;
let mut schema = TestSchemaBuilder::new()
.with_type(
TestTypeBuilder::new("User", "v_user")
.with_description("A user in the system")
.with_simple_field("id", FieldType::Id)
.with_simple_field("name", FieldType::String)
.build(),
)
.with_query(TestQueryBuilder::new("user", "User").no_sql_source().build())
.build();
schema.schema_sdl = Some(
"type Query {\n user(id: ID!): User\n}\n\ntype User {\n id: ID!\n name: String!\n}\n\ntype Mutation {\n createUser(name: String!): User\n}\n".to_string(),
);
let adapter = Arc::new(FailingAdapter::new());
AppState::new(Arc::new(Executor::new(schema, adapter)))
}
pub fn make_test_state_with(
adapter: FailingAdapter,
schema: CompiledSchema,
) -> AppState<FailingAdapter> {
AppState::new(Arc::new(Executor::new(schema, Arc::new(adapter))))
}
pub fn health_router(state: AppState<FailingAdapter>) -> Router {
Router::new()
.route("/health", get(health_handler::<FailingAdapter>))
.route("/introspection", get(introspection_handler::<FailingAdapter>))
.with_state(state)
}
pub fn api_router(state: AppState<FailingAdapter>) -> Router {
Router::new()
.route("/api/v1/query/explain", post(explain_handler::<FailingAdapter>))
.route("/api/v1/query/validate", post(validate_handler::<FailingAdapter>))
.route("/api/v1/query/stats", get(stats_handler::<FailingAdapter>))
.route("/api/v1/schema.graphql", get(export_sdl_handler::<FailingAdapter>))
.route("/api/v1/schema.json", get(export_json_handler::<FailingAdapter>))
.with_state(state)
}
pub async fn get_json(router: &Router, uri: &str) -> (StatusCode, serde_json::Value) {
let response = router
.clone()
.oneshot(Request::builder().uri(uri).body(Body::empty()).unwrap())
.await
.unwrap();
let status = response.status();
let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap();
let json: serde_json::Value = serde_json::from_slice(&body).unwrap();
(status, json)
}
pub async fn get_text(router: &Router, uri: &str) -> (StatusCode, String) {
let response = router
.clone()
.oneshot(Request::builder().uri(uri).body(Body::empty()).unwrap())
.await
.unwrap();
let status = response.status();
let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap();
(status, String::from_utf8(body.to_vec()).unwrap())
}
pub async fn post_json(
router: &Router,
uri: &str,
body: serde_json::Value,
) -> (StatusCode, serde_json::Value) {
let response = router
.clone()
.oneshot(
Request::builder()
.method("POST")
.uri(uri)
.header("content-type", "application/json")
.body(Body::from(serde_json::to_vec(&body).unwrap()))
.unwrap(),
)
.await
.unwrap();
let status = response.status();
let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap();
let json: serde_json::Value = serde_json::from_slice(&body).unwrap();
(status, json)
}