Skip to content

Commit 34f43e6

Browse files
committed
Add book and actions workflow
Signed-off-by: declark1 <[email protected]>
1 parent 29d09ed commit 34f43e6

27 files changed

+486
-3
lines changed

.github/workflows/deploy.yml

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: Deploy Book
2+
on:
3+
push:
4+
branches:
5+
- main
6+
jobs:
7+
deploy:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
contents: write # To push a branch
11+
pages: write # To push to a GitHub Pages site
12+
id-token: write # To update the deployment status
13+
steps:
14+
- uses: actions/checkout@v4
15+
with:
16+
fetch-depth: 0
17+
- name: Install latest mdbook
18+
run: |
19+
tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
20+
url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
21+
mkdir mdbook
22+
curl -sSL $url | tar -xz --directory=./mdbook
23+
echo `pwd`/mdbook >> $GITHUB_PATH
24+
- name: Build Book
25+
run: |
26+
cd book
27+
mdbook build
28+
- name: Setup Pages
29+
uses: actions/configure-pages@v4
30+
- name: Upload artifact
31+
uses: actions/upload-pages-artifact@v3
32+
with:
33+
# Upload entire repository
34+
path: 'book'
35+
- name: Deploy to GitHub Pages
36+
id: deployment
37+
uses: actions/deploy-pages@v4

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ debug/
33
.DS_Store
44
.idea
55
.vscode
6-
Cargo.lock
6+
Cargo.lock
7+
book/book

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
![default-monochrome](https://github.com/user-attachments/assets/dcf68c3e-4c16-4a96-a6d3-2af4710692c6)
22

3-
A **minimal** crate for mocking HTTP and gRPC servers in Rust, with native support for streaming.
3+
mocktail is a **minimal** crate for mocking HTTP and gRPC servers in Rust, with native support for streaming.
44

55
[![Crates.io](https://img.shields.io/crates/v/mocktail)](https://crates.io/crates/mocktail)
66
[![Documentation](https://docs.rs/mocktail/badge.svg)](https://docs.rs/mocktail)
@@ -15,9 +15,10 @@ A **minimal** crate for mocking HTTP and gRPC servers in Rust, with native suppo
1515
# Features
1616
- Mocks HTTP and gRPC servers
1717
- Mocks defined in Rust using a simple, ergonomic API
18-
- Supports HTTP streaming
18+
- Provides first-class support for streaming
1919
- Supports gRPC unary, client-streaming, server-streaming, and bidirectional-streaming methods
2020
- Match requests to mock responses using built-in matchers or custom matchers
21+
- Fully asynchronous
2122

2223
# Getting Started
2324
1. Add `mocktail` to `Cargo.toml` as a development dependency:

book/book.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[book]
2+
title = "mocktail"
3+
language = "en"
4+
multilingual = false
5+
src = "src"
6+
7+
[output.html]
8+
default-theme = "ayu"
9+
preferred-dark-theme = "ayu"
10+
git-repository-url = "https://github.com/IBM/mocktail/book"
11+
12+
[output.html.playground]
13+
runnable = false
14+
editable = false
15+
copyable = true

book/src/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# CHANGELOG

book/src/SUMMARY.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Summary
2+
3+
[Introduction](./introduction.md)
4+
5+
# User Guide
6+
- [Getting Started](./getting-started.md)
7+
- [Concepts](./concepts.md)
8+
- [Mock Builder](./concepts/mock-builder.md)
9+
- [When](./concepts/mock-builder/when.md)
10+
- [Then](./concepts/mock-builder/then.md)
11+
- [Matchers](./concepts/matchers.md)
12+
- [Method](./concepts/matchers/method.md)
13+
- [Path](./concepts/matchers/path.md)
14+
- [Body](./concepts/matchers/body.md)
15+
- [Headers](./concepts/matchers/headers.md)
16+
- [Query Params](./concepts/matchers/query-params.md)
17+
- [Any](./concepts/matchers/any.md)
18+
- [Custom](./concepts/matchers/custom.md)
19+
- [Mock Set](./concepts/mock-set.md)
20+
- [Priority](./concepts/priority.md)
21+
- [Mock Server](./concepts/mock-server.md)
22+
- [Defining Mocks](./defining-mocks.md)
23+
- [Miscellaneous](./misc.md)
24+
- [FAQ](./faq.md)
25+
- [CHANGELOG](./CHANGELOG.md)
26+
- [Contributing](./contributing.md)

book/src/concepts.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Concepts

book/src/concepts/matchers.md

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Matchers
2+
3+
`Matcher` is a trait used to implement logic for matching a request to a mock. A mock consists of a set of matchers that must all evaluate `true` for a given request to be considered a match.
4+
5+
```rust
6+
pub trait Matcher: std::fmt::Debug + Send + Sync + 'static {
7+
/// Matcher name.
8+
fn name(&self) -> &str;
9+
/// Evaluates a match condition.
10+
fn matches(&self, req: &Request) -> bool;
11+
}
12+
```
13+
Several matchers are provided out of the box for common use cases:
14+
- MethodMatcher
15+
- PathMatcher
16+
- PathPrefixMatcher
17+
- BodyMatcher
18+
- HeadersMatcher
19+
- HeadersExactMatcher
20+
- HeaderMatcher
21+
- HeaderExistsMatcher
22+
- QueryParamsMatcher
23+
- QueryParamMatcher
24+
- AnyMatcher
25+
26+
Matcher types are not used directly; `When` has methods corresponding to all matchers plus additional convenience methods for body type variants, method variants, etc.
27+
28+
We are still expanding the list of matchers and welcome PRs to implement matchers for common use cases.
29+
30+
Custom matchers can be implemented with the `Matcher` trait. `When::matcher()` can be used to plug custom `Matcher` implementations.

book/src/concepts/matchers/any.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Any
2+
3+
## Any
4+
5+
Matches any request. Should not be combined with other matchers.
6+
7+
### `When` method
8+
- `any()`

book/src/concepts/matchers/body.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Body
2+
3+
## Body
4+
5+
Matches a request by body.
6+
7+
### `When` methods:
8+
- `body()` *(primary)*
9+
- `empty()`
10+
- `bytes()`
11+
- `bytes_stream()`
12+
- `text()`
13+
- `text_stream()`
14+
- `json()`
15+
- `json_lines_stream()`
16+
- `pb()`
17+
- `pb_stream()`

book/src/concepts/matchers/custom.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Custom
2+
3+
## Custom
4+
5+
Matches a request by a custom `Matcher` implementation.
6+
7+
### `When` method:
8+
- `matcher()`

book/src/concepts/matchers/headers.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Headers
2+
3+
## Headers
4+
5+
Matches a request by headers. Returns `true` if the request headers are a *superset* of the headers, i.e. contains *at least* all of the headers.
6+
7+
### `When` method:
8+
- `headers()`
9+
10+
## Headers Exact
11+
12+
Matches a request by exact headers. Returns `true` if the request headers are *equal to* the headers.
13+
14+
### `When` method:
15+
- `headers_exact()`
16+
17+
## Header
18+
19+
Matches a request by header. Returns `true` if the request contains a header *equal to* the header.
20+
21+
### `When` method:
22+
- `header()`
23+
24+
## Header Exists
25+
26+
Matches a request by header exists. Returns `true` if the request contains a header with the header name.
27+
28+
### `When` method:
29+
- `header_exists()`

book/src/concepts/matchers/method.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Method
2+
3+
## Method
4+
5+
Matches a request by HTTP method.
6+
7+
### `When` methods:
8+
- `method()` *(primary)*
9+
- `get()`
10+
- `post()`
11+
- `put()`
12+
- `head()`
13+
- `delete()`

book/src/concepts/matchers/path.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Path
2+
3+
## Path
4+
5+
Matches a request by path.
6+
7+
### `When` method:
8+
- `path()`
9+
10+
## Path Prefix
11+
12+
Matches a request by path prefix. Returns `true` if the request path starts with prefix.
13+
14+
### `When` method:
15+
- `path_prefix()`
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Query Params
2+
3+
## Query Params
4+
5+
Matches a request by query params. Returns `true` if the request query params are *equal to* the query params.
6+
7+
### `When` method:
8+
- `query_params()`
9+
10+
## Query Param
11+
12+
Matches a request by query param. Returns `true` if the request contains a query param *equal to* the query param.
13+
14+
### `When` method:
15+
- `query_param()`
16+
17+
## Query Param Exists
18+
19+
Matches a request by query param exists. Returns `true` if the request contains a query param with the query key.
20+
21+
### `When` method:
22+
- `query_param_exists()`

book/src/concepts/mock-builder.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Mock Builder
2+
3+
"Mock builder" refers to a closure with `When` and `Then` parameters used to build the request match conditions and response, respectively.
4+
5+
```rust
6+
// A mock that returns the text "yo!" to any request
7+
let mock = Mock::new(|when, then| {
8+
when.any(); // builds a set of request match conditions
9+
then.text("yo!"); // builds the response to return when conditions are matched
10+
})
11+
```
12+
13+
Together, they build a `Mock`, which consists of a set of request match conditions, a response, and a priority:
14+
15+
```rust
16+
pub struct Mock {
17+
/// A set of request match conditions.
18+
pub matchers: Vec<Box<dyn Matcher>>,
19+
/// A mock response.
20+
pub response: Response,
21+
/// Priority.
22+
pub priority: u8, // defaults to 5 (more on this later)
23+
}
24+
```
25+
26+
Since `when` and `then` are just variables of types `When` and `Then`, you can name them however you'd like, e.g. the following also works.
27+
28+
```rust
29+
// A mock that returns the text "index" to get requests on the / endpoint
30+
let mock = Mock::new(|req, res| {
31+
req.get().path("/");
32+
res.text("index");
33+
})
34+
```
35+
36+
We experimented with several different APIs and found this closure-builder pattern to feel the most ergonomic and nice to use.
37+
38+
The mock builder closure is exposed via 3 methods, allowing flexible usage patterns:
39+
40+
1. `Mock::new(|when, then|...)` to build a standalone mock
41+
2. `MockSet::mock(|when, then|...)` shorthand to build a mock and insert it into the mock set
42+
3. `MockServer::mock(|when, then|...)` shorthand to build a mock and insert it into the server's mock set
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Then
2+
3+
`Then` is a builder used to build responses.
4+
5+
### Body methods:
6+
- `body()` *(primary)*
7+
- `empty()`
8+
- `bytes()`
9+
- `bytes_stream()`
10+
- `text()`
11+
- `text_stream()`
12+
- `json()`
13+
- `json_lines_stream()`
14+
- `pb()`
15+
- `pb_stream()`
16+
17+
### Headers method:
18+
- `headers()`
19+
20+
### Status methods:
21+
- `status()` *(primary)*
22+
- `message()`
23+
- `error()`
24+
- `ok()`
25+
- `bad_request()`
26+
- `internal_server_error()`
27+
- `not_found()`
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# When
2+
3+
`When` is a builder used to build request match conditions.
4+
5+
### Method methods:
6+
- `method()` *(primary)*
7+
- `get()`
8+
- `post()`
9+
- `put()`
10+
- `head()`
11+
- `delete()`
12+
13+
### Path methods:
14+
- `path()`
15+
- `path_prefix()`
16+
17+
### Body methods:
18+
- `body()` *(primary)*
19+
- `empty()`
20+
- `bytes()`
21+
- `bytes_stream()`
22+
- `text()`
23+
- `text_stream()`
24+
- `json()`
25+
- `json_lines_stream()`
26+
- `pb()`
27+
- `pb_stream()`
28+
29+
### Header methods:
30+
- `headers()`
31+
- `headers_exact()`
32+
- `header()`
33+
- `header_exists()`
34+
35+
36+
### Query Param methods:
37+
- `query_params()`
38+
- `query_param()`
39+
- `query_param_exists()`
40+
41+
42+
### Other methods:
43+
- `any()`
44+
- `matcher()` *(for custom `Matcher` implementations)*

0 commit comments

Comments
 (0)