apollo_router/plugin/test/
service.rs

1#![allow(dead_code, unreachable_pub)]
2#![allow(missing_docs)] // FIXME
3
4#[cfg(test)]
5use std::sync::Arc;
6
7use futures::Future;
8use http::Request as HyperRequest;
9use http::Response as HyperResponse;
10
11use crate::services::ExecutionRequest;
12use crate::services::ExecutionResponse;
13#[cfg(test)]
14use crate::services::HasSchema;
15use crate::services::RouterRequest;
16use crate::services::RouterResponse;
17use crate::services::SubgraphRequest;
18use crate::services::SubgraphResponse;
19use crate::services::SupergraphRequest;
20use crate::services::SupergraphResponse;
21use crate::services::connector;
22use crate::services::router::Body;
23#[cfg(test)]
24use crate::spec::Schema;
25
26/// Build a mock service handler for the router pipeline.
27macro_rules! mock_service {
28    ($name:ident, $request_type:ty, $response_type:ty) => {
29        paste::item! {
30            mockall::mock! {
31                #[derive(Debug)]
32                #[allow(dead_code)]
33                pub [<$name Service>] {
34                    pub fn call(&mut self, req: $request_type) -> Result<$response_type, tower::BoxError>;
35                }
36
37                #[allow(dead_code)]
38                impl Clone for [<$name Service>] {
39                    fn clone(&self) -> [<Mock $name Service>];
40                }
41            }
42
43            // mockall does not handle well the lifetime on Context
44            impl tower::Service<$request_type> for [<Mock $name Service>] {
45                type Response = $response_type;
46                type Error = tower::BoxError;
47                type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
48
49                fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), tower::BoxError>> {
50                    std::task::Poll::Ready(Ok(()))
51                }
52                fn call(&mut self, req: $request_type) -> Self::Future {
53                    let r  = self.call(req);
54                    Box::pin(async move { r })
55                }
56            }
57        }
58    };
59}
60
61macro_rules! mock_async_service {
62    ($name:ident, $request_type:tt < $req_generic:tt > , $response_type:tt < $res_generic:tt >) => {
63        paste::item! {
64            mockall::mock! {
65                #[derive(Debug)]
66                #[allow(dead_code)]
67                pub [<$name Service>] {
68                    pub fn call(&mut self, req: $request_type<$req_generic>) -> impl Future<Output = Result<$response_type<$res_generic>, tower::BoxError>> + Send + 'static;
69                }
70
71                #[allow(dead_code)]
72                impl Clone for [<$name Service>] {
73                    fn clone(&self) -> [<Mock $name Service>];
74                }
75            }
76
77
78            // mockall does not handle well the lifetime on Context
79            impl tower::Service<$request_type<$req_generic>> for [<Mock $name Service>] {
80                type Response = $response_type<$res_generic>;
81                type Error = tower::BoxError;
82                type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
83
84                fn poll_ready(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), tower::BoxError>> {
85                    std::task::Poll::Ready(Ok(()))
86                }
87                fn call(&mut self, req: $request_type<$req_generic>) -> Self::Future {
88                    Box::pin(self.call(req))
89                }
90            }
91        }
92    };
93}
94
95#[cfg(test)]
96impl HasSchema for MockSupergraphService {
97    fn schema(&self) -> Arc<crate::spec::Schema> {
98        Arc::new(
99            Schema::parse(
100                include_str!("../../testdata/supergraph.graphql"),
101                &Default::default(),
102            )
103            .unwrap(),
104        )
105    }
106}
107
108mock_service!(Router, RouterRequest, RouterResponse);
109mock_service!(Supergraph, SupergraphRequest, SupergraphResponse);
110mock_service!(Execution, ExecutionRequest, ExecutionResponse);
111mock_service!(Subgraph, SubgraphRequest, SubgraphResponse);
112mock_service!(
113    Connector,
114    connector::request_service::Request,
115    connector::request_service::Response
116);
117mock_async_service!(HttpClient, HyperRequest<Body>, HyperResponse<Body>);
118
119// This type is introduced to update internal uses of mocked http services, because the HttpClientService
120// defined above is part of the public API
121// TODO Router 2: remove this type and replace HttpClientService
122#[cfg(test)]
123pub(crate) use internal::MockInternalHttpClientService;
124#[cfg(test)]
125mod internal {
126    use futures::Future;
127    use http::Request as HyperRequest;
128    use http::Response as HyperResponse;
129
130    use crate::services::router::body::RouterBody;
131
132    mock_async_service!(
133        InternalHttpClient,
134        HyperRequest<RouterBody>,
135        HyperResponse<RouterBody>
136    );
137}