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;