grafbase_sdk_mock/
server.rs1use std::{
2 net::{Ipv4Addr, SocketAddrV4},
3 sync::Arc,
4};
5
6use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
7use axum::{Router, extract::State, response::IntoResponse, routing::post};
8use url::Url;
9
10pub struct MockGraphQlServer {
12 shutdown: Option<tokio::sync::oneshot::Sender<()>>,
13 state: AppState,
14 url: Url,
15 name: String,
16}
17
18impl Drop for MockGraphQlServer {
19 fn drop(&mut self) {
20 if let Some(shutdown) = self.shutdown.take() {
21 shutdown.send(()).ok();
22 }
23 }
24}
25
26#[derive(Clone)]
27struct AppState {
28 schema: Arc<(async_graphql::dynamic::Schema, String)>,
29}
30
31impl MockGraphQlServer {
32 pub(crate) async fn new(name: String, schema: Arc<(async_graphql::dynamic::Schema, String)>) -> Self {
33 let state = AppState { schema };
34
35 let app = Router::new()
36 .route("/", post(graphql_handler))
37 .with_state(state.clone());
38
39 let (shutdown_sender, shutdown_receiver) = tokio::sync::oneshot::channel::<()>();
40
41 let listen_address = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0);
42 let listener = tokio::net::TcpListener::bind(listen_address).await.unwrap();
43
44 let listen_address = listener.local_addr().unwrap();
45
46 tokio::spawn(async move {
47 axum::serve(listener, app)
48 .with_graceful_shutdown(async move {
49 shutdown_receiver.await.ok();
50 })
51 .await
52 .unwrap();
53 });
54
55 let url = format!("http://{listen_address}").parse().unwrap();
56
57 MockGraphQlServer {
58 shutdown: Some(shutdown_sender),
59 url,
60 state,
61 name,
62 }
63 }
64
65 pub fn url(&self) -> &Url {
67 &self.url
68 }
69
70 pub fn schema(&self) -> &str {
72 &self.state.schema.1
73 }
74
75 pub fn name(&self) -> &str {
77 &self.name
78 }
79}
80
81async fn graphql_handler(State(state): State<AppState>, req: GraphQLRequest) -> axum::response::Response {
82 let req = req.into_inner();
83 let response: GraphQLResponse = state.schema.0.execute(req).await.into();
84
85 response.into_response()
86}