vaultrs_test/docker.rs
1use dockertest::{Composition, DockerOperations, DockerTest};
2use futures::future::Future;
3
4/// A server configuration which can be converted into a [Composition] to be
5/// ran as a container.
6///
7/// Types implementing this trait should collect all required configuration data
8/// and use [ServerConfig::to_comp] to convert it into a [Composition] to be run
9/// by a [TestInstance]. The associated [Server] for this configuration should
10/// later recieve a copy of this configuration to perform any additional steps
11/// required.
12pub trait ServerConfig {
13 /// Creates a [Composition] from this configuration
14 fn to_comp(&self) -> Composition;
15
16 /// Creates a new [TestInstance] and automatically adds the [Composition]
17 /// from this configuration to it.
18 fn to_instance(&self) -> TestInstance;
19}
20
21/// An instance of a server that is created after it's associated [Composition]
22/// has been brought up.
23///
24/// This trait is the main vehicle for tests to interact with the running
25/// container. It should encompass all logic necessary for tests to successfully
26/// interact with it.
27pub trait Server {
28 type Config;
29 fn new(ops: &DockerOperations, config: &Self::Config) -> Self;
30}
31
32/// A single test instance made up of several [Composition]s which
33/// are brought up for executing tests.
34///
35/// Use the `run` method to run the containers and perform the test logic.
36pub struct TestInstance {
37 pub instance: DockerTest,
38}
39
40impl TestInstance {
41 /// Returns a new [TestInstance] configured with the given [Composition]s.
42 pub fn new(mut servers: Vec<Composition>) -> TestInstance {
43 let mut instance = DockerTest::new();
44 servers.drain(..).for_each(|s| instance.add_composition(s));
45
46 TestInstance { instance }
47 }
48
49 /// Adds a [Composition] to this [TestInstance].
50 pub fn add(&mut self, comp: Composition) {
51 self.instance.add_composition(comp);
52 }
53
54 /// Runs all containers from the associated [Composition]s, verifying they
55 /// are running according to their startup conditions, and then calls the
56 /// passed closure with runtime details.
57 ///
58 /// This is the main method for running the [TestInstance]. All test logic
59 /// should be encompassed within the passed closure. Creating and destroying
60 /// containers happens upon entering/leaving the closure.
61 pub fn run<T, F>(self, fun: T)
62 where
63 T: FnOnce(DockerOperations) -> F + Send + 'static,
64 F: Future<Output = ()> + Send + 'static,
65 {
66 self.instance.run(|ops| async move {
67 (fun)(ops).await;
68 });
69 }
70}