wiremock_grpc/wiremock/
codegen.rs

1/// Generate mock server code for the given `prefix` and `type`.
2///
3/// For each gRPC server you need to generate codes using this macro.
4///
5/// # Arguments
6/// * `prefix` - The prefix of the RPC (eg. `hello.Greeter` if the RPC is `/helloworld.Greeter/SayHello`)
7/// * `type` - Type of the generated server. This [`Deref`](core::ops::Deref) to [`GrpcServer`](crate::wiremock::grpc_server::GrpcServer). You will be interacting with this type in your test.
8///
9/// # Example
10/// ```no_run
11/// mod wiremock_gen {
12///     // hello.Greeter: is the prefix of all rpc,
13///     // MyMockServer: name of the generated Server,
14///     wiremock_grpc::generate!("hello.Greeter", MyMockServer);
15/// }
16/// use wiremock_gen::*;  // this imports generated
17/// use wiremock_grpc::*; // this imports MockBuilder
18///
19/// # async fn example() {
20/// // ... Later in your test (MyMockServer is generated above)
21/// let mut server = MyMockServer::start_default().await;
22/// # }
23/// ```
24#[macro_export]
25#[deprecated(
26    since = "0.4.0",
27    note = "Use `generate_svc!` instead for type-safe API"
28)]
29macro_rules! generate {
30    ($prefix:literal, $type: ident) => {
31        use ::wiremock_grpc::tonic::{
32            codegen::{http, Body, StdError},
33            Code,
34        };
35        use std::{
36            net::SocketAddr,
37            ops::{Deref, DerefMut},
38            task::Poll,
39        };
40
41        use wiremock_grpc::*;
42
43        /// A running gRPC server that binds to service with prefix: `
44        #[doc = $prefix]
45        /// `
46        /// # Example
47        /// ```no_run
48        /// let mut server =
49        #[doc = stringify!($type)]
50        /// ::start_default().await;
51        /// ```
52        /// More documentations in [`crate`]
53        #[derive(Clone)]
54        pub struct $type(pub(crate) GrpcServer);
55
56        impl Deref for $type {
57            type Target = GrpcServer;
58
59            fn deref(&self) -> &Self::Target {
60                &self.0
61            }
62        }
63
64        impl DerefMut for $type {
65            fn deref_mut(&mut self) -> &mut Self::Target {
66                &mut self.0
67            }
68        }
69
70        impl<B> tonic::codegen::Service<tonic::codegen::http::Request<B>> for $type
71        where
72            B: ::wiremock_grpc::http_body::Body + Send + 'static,
73            B::Error: Into<tonic::codegen::StdError> + Send + 'static,
74        {
75            type Response = tonic::codegen::http::Response<tonic::body::Body>;
76            type Error = std::convert::Infallible;
77            type Future = tonic::codegen::BoxFuture<Self::Response, Self::Error>;
78
79            fn poll_ready(
80                &mut self,
81                _cx: &mut std::task::Context<'_>,
82            ) -> Poll<Result<(), Self::Error>> {
83                Poll::Ready(Ok(()))
84            }
85
86            fn call(&mut self, req: tonic::codegen::http::Request<B>) -> Self::Future {
87                self.0.handle_request(req)
88            }
89        }
90
91        impl tonic::server::NamedService for $type {
92            const NAME: &'static str = $prefix;
93        }
94
95        impl $type {
96            /// Start the server and listens to an available port.
97            ///
98            /// The port can be accessed using `address()`
99            /// ```no_run
100            /// let server = MyMockServer::start_default();
101            /// let address = server.address();
102            /// let port : u16 = address.port();
103            /// ```
104            pub async fn start_default() -> Self {
105                let port = GrpcServer::find_unused_port()
106                    .await
107                    .expect("Unable to find an open port");
108
109                Self(GrpcServer::new(port)).start_internal().await
110            }
111
112            /// Start the server with a specified port.
113            ///
114            /// ## Panics
115            /// * When the the port is not available.
116            pub async fn start(port: u16) -> Self {
117                Self(GrpcServer::new(port)).start_internal().await
118            }
119
120            /// Start the server with a specified address.
121            ///
122            /// ## Panics
123            /// * When the the address is not available.
124            pub async fn start_with_addr(addr: SocketAddr) -> Self {
125                Self(GrpcServer::with_addr(addr)).start_internal().await
126            }
127
128            async fn start_internal(&mut self) -> Self {
129                let address = self.address().clone();
130                let thread = tokio::spawn(
131                    tonic::transport::Server::builder()
132                        .add_service(self.clone())
133                        .serve(address),
134                );
135                self._start(thread).await;
136                self.to_owned()
137            }
138        }
139    };
140}