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
#![deny(missing_docs)]
#![deny(warnings)]
#![deny(rust_2018_idioms)]
#![deny(intra_doc_link_resolution_failure)]

//! _dockertest_ is a testing and automation abstraction for Docker.
//!
//! The primary utility for this crate is to easily employ docker in test infrastructure,
//! with the following key features:
//! * Ensure that the docker container is running prior to test code.
//!  * Support multiple containers per test.
//!  * Support multiple containers from same image, with different configurations.
//! * Retrieve [Image] from remote source according to [PullPolicy].
//! * Support multiple [Remote] registries, which can be individually assigned to [Image].
//! * Dictate how each [RunningContainer] is created and operated from an [Image]
//!   through a [Composition].
//!  * This allows us to have muliple containers with the same Image,
//!    but with different start conditions.
//! * Control each [Composition] condition for when it is deemed running through [WaitFor].
//!  * There exists multiple convenient [WaitFor] implementations, however, user-supplied
//!    implementations through the trait can be provided.
//! * Control the [StartPolicy] of each [Composition]. For inter-dependant
//!   containers, a Strict policy can be sat, and they will be started in succession until
//!   their [WaitFor] condition is met, according to the order they where added to [DockerTest].
//!
//! Once the [DockerTest] test is `run`, the provided closure will be ran once
//! all predicates for each supplied [Composition] has successfully been fulfilled.
//! The closure is provided with one [DockerOperations] parameter, allowing the test body
//! to interact with [DockerTest] and each individual [RunningContainer].
//! The reference to each [RunningContainer] is queried through a handle, which is the user-provided
//! container name, specified in [Composition] through [with_container_name]. See the Handle
//! section.
//!
//! # Handle - referencing the same container throughout your test
//!
//! _dockertest_ assigns a `handle` to each [Composition], which carries over to a
//! [RunningContainer]. When writing a test, one will reference the intended object through its
//! handle.
//!
//! By default, the handle is auto-assigned to be the repository name of the [Composition].
//!
//! The user may change the handle by changing the container name (as seen from the user
//! - the final container name will be disambiguated for each _dockertest_) through the
//! [with_container_name] builder method on [Composition].
//!
//! If the test includes multiple [Composition]s with the same handle,
//! attempting to reference one that has multiple occurrences will fail the test at runtime.
//!
//! # WaitFor - Control how to determine when the container is ready
//!
//! Each [Composition] require a trait object of [WaitFor] whose method [wait_for_ready]
//! must resolve until the container can become a [RunningContainer].
//! This trait may be implemented and supplied to [Composition] through [with_wait_for].
//!
//! The batteries included implementations are:
//! * [RunningWait] - wait for the container to report _running_ status.
//! * [ExitedWait] - wait for the container to report _exited_ status.
//! * [NoWait] - don't wait for anything
//! * [MessageWait] - wait for the following message to appear in the log stream.
//!
//! # Prune policy
//!
//! By default, _dockertest_ will stop and remove all containers and created volumes
//! regardless of execution result. You can control this policy by setting the environment variable
//! `DOCKERTEST_PRUNE`:
//! * "always": [default] remove everything
//! * "never": leave all containers running
//! * "stop_on_failure": stop containers on execution failure
//! * "running_on_failure": leave containers running on execution failure
//!
//! # Viewing logs of test execution
//! _dockertest_ utilizes the `tracing` log infrastructure. To enable this log output,
//! you must perform enable a subscriber to handle the events.
//! This can easily be done by for instance the wrapper crate `test-env-log`, that provides
//! a new impl of the `#[test]` attribute.
//!
//! .Cargo.toml
//! ```no_compile
//! [dev-dependencies]
//! tracing = "0.1.13"
//! tracing-subscriber = "0.2"
//! test-env-log = { version = "0.2", default-features = false, features = ["trace"] }
//! ```
//!
//! .Top of test file
//! ```
//! use test_env_log::test;
//! ```
//!
//! # Example
//!
//! ```rust
//! use diesel::pg::PgConnection;
//! use diesel::prelude::*;
//! use dockertest::waitfor::{MessageSource, MessageWait};
//! use dockertest::{Composition, DockerTest, PullPolicy, Source};
//! use std::rc::Rc;
//!
//! // Define our test
//! let source = Source::DockerHub(PullPolicy::IfNotPresent);
//! let mut test = DockerTest::new().with_default_source(source);
//!
//! // Define our Composition - the Image we will start and end up as our RunningContainer
//! let mut postgres = Composition::with_repository("postgres").with_wait_for(Box::new(MessageWait {
//!     message: "database system is ready to accept connections".to_string(),
//!     source: MessageSource::Stderr,
//!     timeout: 20,
//! }));
//! postgres.env("POSTGRES_PASSWORD", "password");
//! test.add_composition(postgres);
//!
//! // Run the test body
//! test.run(|ops| async move {
//!     let container = ops.handle("postgres");
//!     let conn_string = format!("postgres://postgres:password@{}:{}", container.ip(), 5432);
//!     let pgconn = PgConnection::establish(&conn_string);
//!
//!     // Perform your database operations here
//!     assert!(
//!         pgconn.is_ok(),
//!         "failed to establish connection to postgres docker"
//!     );
//! });
//! ```
//!
//! [Composition]: struct.Composition.html
//! [DockerOperations]: struct.DockerOperations.html
//! [DockerTest]: struct.DockerTest.html
//! [ExitedWait]: waitfor/struct.ExitedWait.html
//! [host_port]: struct.Container.html#method.host_port
//! [Image]: struct.Image.html
//! [MessageWait]: waitfor/struct.MessageWait.html
//! [NoWait]: waitfor/struct.NoWait.html
//! [PendingContainer]: struct.Container.html
//! [PullPolicy]: enum.PullPolicy.html
//! [Remote]: struct.Remote.html
//! [RunningContainer]: struct.RunningContainer.html
//! [RunningWait]: waitfor/struct.RunningWait.html
//! [StartPolicy]: enum.StartPolicy.html
//! [WaitFor]: waitfor/trait.WaitFor.html
//! [wait_for_ready]: waitfor/trait.WaitFor.html#method.wait_for_ready
//! [with_container_name]: struct.Composition.html#method.with_container_name
//! [with_wait_for]: struct.Composition.html#method.with_wait_for

mod composition;
mod container;
mod dockertest;
mod error;
mod image;
pub mod waitfor;

// Private module containing utility functions used for testing purposes
#[cfg(test)]
mod test_utils;

pub use crate::composition::{Composition, StartPolicy};
pub use crate::container::{PendingContainer, RunningContainer};
pub use crate::dockertest::{DockerOperations, DockerTest};
pub use crate::error::DockerTestError;
pub use crate::image::{Image, PullPolicy, Remote, Source};