wiremock_grpc/
lib.rs

1//! # wiremock-grpc
2//!
3//! gRPC mocking to test Rust applications.
4//!
5//! This crate provides an easy way to mock gRPC services in your tests, allowing you to
6//! test client code without running actual gRPC servers. It features a type-safe API
7//! for defining mock behaviors and verifying requests.
8//!
9//! ## Quick Start
10//!
11//! Use the [`generate_svc!`] macro to create a mock server:
12//!
13//! ```no_run
14//! use wiremock_grpc::{generate_svc, MockBuilder};
15//! use tonic::Code;
16//! # mod hello {
17//! #     pub mod greeter_client {
18//! #         pub struct GreeterClient<T>(T);
19//! #         impl<T> GreeterClient<T> {
20//! #             pub fn new(t: T) -> Self { Self(t) }
21//! #             pub async fn say_hello(&mut self, _req: super::HelloRequest)
22//! #                 -> Result<tonic::Response<super::HelloReply>, tonic::Status> {
23//! #                 Ok(tonic::Response::new(super::HelloReply { message: "".into() }))
24//! #             }
25//! #         }
26//! #     }
27//! #     pub use greeter_client::GreeterClient;
28//! #     #[derive(Clone, PartialEq, prost::Message)]
29//! #     pub struct HelloRequest { #[prost(string, tag = "1")] pub name: String }
30//! #     #[derive(Clone, PartialEq, prost::Message)]
31//! #     pub struct HelloReply { #[prost(string, tag = "1")] pub message: String }
32//! # }
33//! # use hello::{GreeterClient, HelloRequest, HelloReply};
34//!
35//! // Generate a mock server (make sure the package, service and the rpc names are exactly as they are named in the proto files)
36//! generate_svc! {
37//!     package hello;
38//!     service Greeter {
39//!         SayHello,
40//!         WeatherInfo,
41//!     }
42//! }
43//!
44//! #[tokio::test]
45//! async fn test_grpc_service() {
46//!     // Start the mock server
47//!     let mut server = GreeterMockServer::start_default().await;
48//!
49//!     // Set up a mock response
50//!     server.setup(
51//!         MockBuilder::when()
52//!             .path_say_hello()  // method generated by generate_svc macro (for each item under "service" block)
53//!             .then()
54//!             .return_status(Code::Ok)
55//!             .return_body(|| HelloReply {
56//!                 message: "Hello from mock!".into(),
57//!             }),
58//!     );
59//!
60//!     // Connect your client and test
61//!     let channel = tonic::transport::Channel::from_shared(
62//!         format!("http://[::1]:{}", server.address().port())
63//!     )
64//!     .unwrap()
65//!     .connect()
66//!     .await
67//!     .unwrap();
68//!
69//!     let mut client = GreeterClient::new(channel);
70//!     let response = client
71//!         .say_hello(HelloRequest { name: "World".into() })
72//!         .await
73//!         .unwrap();
74//!
75//!     assert_eq!("Hello from mock!", response.into_inner().message);
76//! }
77//! ```
78//!
79//! ## Features
80//!
81//! - **Type-safe API**: Generate type-safe `path_*` methods for each RPC using [`generate_svc!`]
82//! - **Header Matching**: Match requests based on gRPC metadata/headers
83//! - **Status Codes**: Return any gRPC status code
84//! - **Custom Bodies**: Return custom response bodies with closures
85//! - **Request Verification**: Track invocations and verify calls were made
86//! - **Flexible Binding**: Start servers on random ports, specific ports, or custom addresses
87//!
88//! ## Custom Server Name
89//!
90//! You can specify a custom name for the generated server:
91//!
92//! ```no_run
93//! # use wiremock_grpc::generate_svc;
94//! generate_svc! {
95//!     package hello;
96//!     service Greeter as MyCustomServer {
97//!         SayHello,
98//!     }
99//! }
100//! # async fn example() {
101//! let server = MyCustomServer::start_default().await;
102//! # }
103//! ```
104//!
105//! ## Header Matching
106//!
107//! Match requests based on gRPC metadata:
108//!
109//! ```no_run
110//! # use wiremock_grpc::{generate_svc, MockBuilder, Then};
111//! # generate_svc! { package hello; service Greeter { SayHello } }
112//! # #[derive(Clone, PartialEq, prost::Message)]
113//! # struct HelloReply { #[prost(string, tag = "1")] message: String }
114//! # async fn example(mut server: GreeterMockServer) {
115//! server.setup(
116//!     MockBuilder::when()
117//!         .path_say_hello()
118//!         .header("x-session-id", "abc123")
119//!         .then()
120//!         .return_body(|| HelloReply {
121//!             message: "Authenticated response".into(),
122//!         }),
123//! );
124//! # }
125//! ```
126//!
127//! ## What [`generate_svc!`] Generates
128//!
129//! The macro generates:
130//! - `{ServiceName}MockServer` - Mock server struct with:
131//!   - `start_default()` - Start on a random available port
132//!   - `start(port)` - Start on a specific port
133//!   - `start_with_addr(addr)` - Start on a specific address
134//!   - `setup()` - Configure mock behaviors
135//!   - `address()` - Get the server's bind address
136//! - `{ServiceName}TypeSafeExt` - Extension trait adding `path_{method_name}` methods to [`WhenBuilder`]
137//!
138//! ## Main Types
139//!
140//! - [`MockBuilder`] - Build mock behaviors with `when()` and `then()` pattern
141//! - [`WhenBuilder`] - Configure request matching (path, headers, etc.)
142//! - [`Then`] - Configure response behavior (status, body, headers)
143//! - [`GrpcServer`] - The underlying mock server (dereferenced by generated servers)
144
145pub mod wiremock;
146
147pub use wiremock::builder::{MockBuilder, Mountable, Then, WhenBuilder};
148pub use wiremock::grpc_server::GrpcServer;
149pub use wiremock::tonic_ext;
150
151pub use wiremock_grpc_macros::generate_svc;
152
153pub extern crate http_body;
154pub extern crate tonic;