1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
#![allow(warnings)]
//! HTTP mocking library that allows you to simulate responses from HTTP based services.
//!
//! # Features
//! * Simple, expressive, fluent API.
//! * Many built-in helpers for easy request matching.
//! * Parallel test execution.
//! * Extensible request matching.
//! * Fully asynchronous core with synchronous and asynchronous APIs.
//! * [Advanced verification and debugging support](https://web.archive.org/web/20201202160613/https://dev.to/alexliesenfeld/rust-http-testing-with-httpmock-2mi0#verification)
//! * [Network delay simulation](https://github.com/alexliesenfeld/httpmock/blob/master/tests/examples/delay_tests.rs).
//! * Support for [Regex](https://docs.rs/regex/) matching, JSON, [serde](https://crates.io/crates/serde), cookies, and more.
//! * Standalone mode with an accompanying [Docker image](https://hub.docker.com/r/alexliesenfeld/httpmock).
//! * Support for [mock specification based on YAML files](https://github.com/alexliesenfeld/httpmock/blob/master/src/lib.rs#L185-L201).
//!
//! # Getting Started
//! Add `httpmock` to `Cargo.toml`:
//!
//! ```toml
//! [dev-dependencies]
//! httpmock = "0.7.0-rc.1"
//! ```
//!
//! You can then use `httpmock` as follows:
//! ```
//! use httpmock::prelude::*;
//!
//! // Start a lightweight mock server.
//! let server = MockServer::start();
//!
//! // Create a mock on the server.
//! let hello_mock = server.mock(|when, then| {
//! when.method(GET)
//! .path("/translate")
//! .query_param("word", "hello");
//! then.status(200)
//! .header("content-type", "text/html")
//! .body("ohi");
//! });
//!
//! // Send an HTTP request to the mock server. This simulates your code.
//! let response = isahc::get(server.url("/translate?word=hello")).unwrap();
//!
//! // Ensure the specified mock was called exactly one time (or fail with a detailed error description).
//! hello_mock.assert();
//! // Ensure the mock server did respond as specified.
//! assert_eq!(response.status(), 200);
//! ```
//! # Usage
//! To be able to configure mocks, you first need to start a mock server by calling
//! [MockServer::start](struct.MockServer.html#method.start).
//! This will spin up a lightweight HTTP
//! mock server in the background and wait until the server is ready to accept requests.
//!
//! You can then create a [Mock](struct.Mock.html) object on the server by using the
//! [MockServer::mock](struct.MockServer.html#method.mock) method. This method expects a closure
//! with two parameters, that we will refer to as the `when` and `then` parameter:
//! - The `when` parameter is of type [When](struct.When.html) and holds all request characteristics.
//! The mock server will only respond to HTTP requests that meet all the criteria. Otherwise it
//! will respond with HTTP status code `404` and an error message.
//! - The `then` parameter is of type [Then](struct.Then.html) and holds all values that the mock
//! server will respond with.
//!
//! # Sync / Async
//! The internal implementation of `httpmock` is completely asynchronous. It provides you a
//! synchronous and an asynchronous API though. If you want to schedule awaiting operations manually, then
//! you can use the `async` variants that exist for every potentially blocking operation. For
//! example, there is [MockServer::start_async](struct.MockServer.html#method.start_async) as an
//! asynchronous counterpart to [MockServer::start](struct.MockServer.html#method.start). You can
//! find similar methods throughout the entire library.
//!
//! # Parallelism
//! To balance execution speed and resource consumption, [MockServer](struct.MockServer.html)s
//! are kept in a server pool internally. This allows to run tests in parallel without overwhelming
//! the executing machine by creating too many HTTP servers. A test will be blocked if it tries to
//! use a [MockServer](struct.MockServer.html) (e.g. by calling
//! [MockServer::start](struct.MockServer.html#method.start)) while the server pool is empty
//! (i.e. all servers are occupied by other tests).
//!
//! [MockServer](struct.MockServer.html)s are never recreated but recycled/reset.
//! The pool is filled on demand up to a maximum number of 25 servers.
//! You can override this number by using the environment variable `HTTPMOCK_MAX_SERVERS`.
//!
//! # Debugging
//! `httpmock` logs against the [log](https://crates.io/crates/log) crate. This allows you to
//! see detailed log output that contains information about `httpmock`s behaviour.
//! You can use this log output to investigate
//! issues, such as to find out why a request does not match a mock definition.
//!
//! The most useful log level is `debug`, but you can also go down to `trace` to see even more
//! information.
//!
//! **Attention**: To be able to see the log output, you need to add the `--nocapture` argument
//! when starting test execution!
//!
//! *Hint*: If you use the `env_logger` backend, you need to set the `RUST_LOG` environment variable to
//! `httpmock=debug`.
//!
//! # API Alternatives
//! This library provides two functionally interchangeable DSL APIs that allow you to create
//! mocks on the server. You can choose the one you like best or use both side-by-side. For a
//! consistent look, it is recommended to stick to one of them, though.
//!
//! ## When/Then API
//! This is the default API of `httpmock`. It is concise and easy to read. The main goal
//! is to reduce overhead emposed by this library to a bare minimum. It works well with
//! formatting tools, such as [rustfmt](https://crates.io/crates/rustfmt) (i.e. `cargo fmt`),
//! and can fully benefit from IDE support.
//!
//! ### Example
//! ```
//! let server = httpmock::MockServer::start();
//!
//! let greeting_mock = server.mock(|when, then| {
//! when.path("/hi");
//! then.status(200);
//! });
//!
//! let response = isahc::get(server.url("/hi")).unwrap();
//!
//! greeting_mock.assert();
//! ```
//! Note that `when` and `then` are variables. This allows you to rename them to something you
//! like better (such as `expect`/`respond_with`).
//!
//! Relevant elements for this API are [MockServer::mock](struct.MockServer.html#method.mock), [When](struct.When.html) and [Then](struct.Then.html).
//!
//! # Examples
//! You can find examples in the test directory in this crates Git repository:
//! [this crates test directory](https://github.com/alexliesenfeld/httpmock/blob/master/tests ).
//!
//! # Standalone Mode
//! You can use `httpmock` to run a standalone mock server that runs in a separate process.
//! This allows it to be available to multiple applications, not only inside your unit and integration
//! tests. This is useful if you want to use `httpmock` in system (or even end-to-end) tests, that
//! require mocked services. With this feature, `httpmock` is a universal HTTP mocking tool that is
//! useful in all stages of the development lifecycle.
//!
//! ## Using a Standalone Mock Server
//! Although you can build the mock server in standalone mode yourself, it is easiest to use the
//! accompanying [Docker image](https://hub.docker.com/r/alexliesenfeld/httpmock).
//!
//! To be able to use the standalone server from within your tests, you need to change how an
//! instance of the [MockServer](struct.MockServer.html) instance is created.
//! Instead of using [MockServer::start](struct.MockServer.html#method.start),
//! you need to connect to a remote server by using one of the `connect` methods (such as
//! [MockServer::connect](struct.MockServer.html#method.connect) or
//! [MockServer::connect_from_env](struct.MockServer.html#method.connect_from_env)). **Note**:
//! These are only available with the `remote` feature **enabled**.
//!
//! ```
//! use httpmock::prelude::*;
//! use isahc::get;
//!
//! #[test]
//! fn simple_test() {
//! // Arrange
//! let server = MockServer::connect("some-host:5000");
//!
//! let hello_mock = server.mock(|when, then|{
//! when.path("/hello/standalone");
//! then.status(200);
//! });
//!
//! // Act
//! let response = get(server.url("/hello/standalone")).unwrap();
//!
//! // Assert
//! hello_mock.assert();
//! assert_eq!(response.status(), 200);
//! }
//! ```
//!
//! ## Standalone Parallelism
//! To prevent interference with other tests, test functions are forced to use the standalone
//! mock server sequentially.
//! This means that test functions may be blocked when connecting to the remote server until
//! it becomes free again.
//! This is in contrast to tests that use a local mock server.
//!
//! ## Limitations of the Standalone Mode
//! At this time, it is not possible to use custom request matchers in combination with standalone
//! mock servers (see [When::matches](struct.When.html#method.matches) or
//! [Mock::expect_match](struct.Mock.html#method.expect_match)).
//!
//! ## Standalone Mode with YAML Mock Definition Files
//! The standalone server can also be used to read mock definitions from YAML files on startup once
//! and serve the mocked endpoints until the server is shut down again. These `static` mocks
//! cannot be deleted at runtime (even by Rust-based tests that use the mock server) and exist
//! for the entire uptime of the mock server.
//!
//! The definition files follow the standard `httpmock` API that you would also use in regular
//! Rust tests. Please find an example mock definition file in the `httpmock` Github repository
//! [here in this crates test directory](https://github.com/alexliesenfeld/httpmock/blob/master/tests/resources/static_yaml_mock.yaml).
//!
//! You can start the mock server with static mock support as follows:
//! * If you use the [Docker image from this creates repository](https://github.com/alexliesenfeld/httpmock/blob/master/Dockerfile)
//! or from [Dockerhub](https://hub.docker.com/r/alexliesenfeld/httpmock), you just need to mount a
//! volume with all your mock specification files to the `/mocks` directory within the container.
//! * If you build `httpmock` from source and use the binary, then you can pass the path to
//! the directory containing all your mock specification files using the `--static-mock-dir`
//! parameter. Example: `httpmock --expose --static-mock-dir=/mocks`.
//!
//! # License
//! `httpmock` is free software: you can redistribute it and/or modify it under the terms
//! of the MIT Public License.
//!
//! This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//! without even the implied
//! warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MIT Public
//! License for more details.
#[macro_use]
extern crate lazy_static;
use std::borrow::BorrowMut;
use std::net::ToSocketAddrs;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use api::MockServerAdapter;
use common::util::Join;
pub use api::{Method, Mock, MockExt, MockServer, Regex, Then, When};
mod api;
mod common;
mod server;
pub mod standalone;
pub mod prelude {
#[doc(no_inline)]
pub use crate::{
api::MockServer, common::data::HttpMockRequest, Method::DELETE, Method::GET,
Method::OPTIONS, Method::POST, Method::PUT, Regex,
};
}