From 6db560bf7cc4bf55ad0fc19a74beb7febb1e643a Mon Sep 17 00:00:00 2001 From: stormshield-gt <143998166+stormshield-gt@users.noreply.github.com.> Date: Thu, 14 Mar 2024 12:11:58 +0100 Subject: [PATCH] add test for sys init in case of success --- src/api/sys/responses.rs | 6 +- tests/sys.rs | 66 +++++++++++++++++-- tests/vault_prod_container.rs | 115 ++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 7 deletions(-) create mode 100644 tests/vault_prod_container.rs diff --git a/src/api/sys/responses.rs b/src/api/sys/responses.rs index ae9ad09..d27771f 100644 --- a/src/api/sys/responses.rs +++ b/src/api/sys/responses.rs @@ -82,9 +82,9 @@ pub struct ReadHealthResponse { /// [StartInitializationRequest][crate::api::sys::requests::StartInitializationRequest] #[derive(Deserialize, Debug, Serialize)] pub struct StartInitializationResponse { - keys: Vec, - keys_base64: Vec, - root_token: String, + pub keys: Vec, + pub keys_base64: Vec, + pub root_token: String, } /// Response from executing diff --git a/tests/sys.rs b/tests/sys.rs index 4d92905..0026dca 100644 --- a/tests/sys.rs +++ b/tests/sys.rs @@ -1,10 +1,14 @@ mod common; +mod vault_prod_container; -use common::{VaultServer, VaultServerHelper}; +use std::collections::HashMap; + +use common::{VaultServer, VaultServerHelper, PORT, VERSION}; +use dockertest_server::Test; use test_log::test; use vaultrs::{ api::{sys::requests::ListMountsRequest, ResponseWrapper}, - client::Client, + client::{Client, VaultClient, VaultClientSettingsBuilder}, error::ClientError, sys, }; @@ -23,7 +27,7 @@ fn test() { test_health(&client).await; // Test initialization - test_start_initialization(&client).await; + test_start_initialization_failure(&client).await; // Test status test_status(&client).await; @@ -47,6 +51,22 @@ fn test() { }); } +#[test] +fn sys_init() { + let test = new_prod_test(); + test.run(|instance| async move { + let server: vault_prod_container::VaultServer = instance.server(); + let client = VaultClient::new( + VaultClientSettingsBuilder::default() + .address(server.external_url()) + .build() + .unwrap(), + ) + .unwrap(); + test_start_initialization(&client).await; + }); +} + async fn test_wrap(client: &impl Client) { let endpoint = ListMountsRequest::builder().build().unwrap(); let wrap_resp = endpoint.wrap(client).await; @@ -68,7 +88,7 @@ async fn test_health(client: &impl Client) { assert!(resp.is_ok()); } -async fn test_start_initialization(client: &impl Client) { +async fn test_start_initialization_failure(client: &impl Client) { let resp = sys::start_initialization(client, 1, 1, None) .await .unwrap_err(); @@ -78,6 +98,11 @@ async fn test_start_initialization(client: &impl Client) { assert_eq!(code, 400); } +async fn test_start_initialization(client: &impl Client) { + let resp = sys::start_initialization(client, 1, 1, None).await.unwrap(); + assert_eq!(resp.keys.len(), 1); +} + async fn test_seal(client: &impl Client) { let resp = sys::seal(client).await; assert!(resp.is_ok()); @@ -148,3 +173,36 @@ mod policy { assert!(resp.is_ok()); } } + +// Sets up a new test using the vault production server. +pub fn new_prod_test() -> Test { + let mut test = Test::default(); + let vault_config = serde_json::json!({ + "listener": [ + { + "tcp": { + "address": "0.0.0.0:8300", + "tls_disable": "true" + } + } + ], + "storage": [ + { + "file": { + "path": "/vault/file" + } + } + ], + "disable_mlock": true + + }); + let env = HashMap::from([("VAULT_LOCAL_CONFIG".to_string(), vault_config.to_string())]); + let config = vault_prod_container::VaultServerConfig::builder() + .port(PORT) + .version(VERSION.into()) + .env(env) + .build() + .unwrap(); + test.register(config); + test +} diff --git a/tests/vault_prod_container.rs b/tests/vault_prod_container.rs new file mode 100644 index 0000000..6a8aefc --- /dev/null +++ b/tests/vault_prod_container.rs @@ -0,0 +1,115 @@ +// This file is copied from https://github.com/jmgilman/dockertest-server/blob/master/src/servers/hashi/vault.rs +// because of the LOG_MSG condition is only applicable to vault dev server. + +use derive_builder::Builder; +use dockertest::{waitfor, Source}; +use dockertest_server::{Config, ContainerConfig, Server}; +use std::collections::HashMap; + +const IMAGE: &str = "vault"; +const PORT: u32 = 8300; +const LOG_MSG: &str = "Vault server started!"; +const SOURCE: Source = Source::DockerHub; + +/// Configuration for creating a Hashicorp Vault server. +/// +/// A token with root permissions will automatically be generated using the +/// `token` field. If it's omitted the token will automatically be generated. +/// +/// By default the Vault server listens on port 8200 for HTTP requests. This +/// is exposed on the container by default, but the exposed port can be +/// controlled by setting the `port` field. +/// +/// See the [Dockerhub](https://hub.docker.com/_/vault) page for more +/// information on the arguments and environment variables that can be used to +/// configure the server. +#[derive(Clone, Default, Builder)] +#[builder(default)] +pub struct VaultServerConfig { + #[builder(default = "vec![String::from(\"server\")]")] + pub args: Vec, + #[builder(default = "HashMap::new()")] + pub env: HashMap, + #[builder(default = "dockertest_server::server::new_handle(IMAGE)")] + pub handle: String, + #[builder(default = "8200")] + pub port: u32, + #[builder(default = "15")] + pub timeout: u16, + #[builder(default = "String::from(\"latest\")")] + pub version: String, +} + +impl VaultServerConfig { + pub fn builder() -> VaultServerConfigBuilder { + VaultServerConfigBuilder::default() + } +} + +impl Config for VaultServerConfig { + fn into_composition(self) -> dockertest::Composition { + let ports = vec![(PORT, self.port)]; + + let timeout = self.timeout; + let wait = Box::new(waitfor::MessageWait { + message: LOG_MSG.into(), + source: waitfor::MessageSource::Stdout, + timeout, + }); + + ContainerConfig { + args: self.args, + env: self.env, + handle: self.handle, + name: IMAGE.into(), + source: SOURCE, + version: self.version, + ports: Some(ports), + wait: Some(wait), + bind_mounts: HashMap::new(), + } + .into() + } + + fn handle(&self) -> &str { + self.handle.as_str() + } +} + +/// A running instance of a Vault server. +/// +/// The server URL which is accessible from the local host can be found in `local_address`. +/// Other running containers which need access to this server should use the +/// `address` field instead. +pub struct VaultServer { + pub external_port: u32, + pub internal_port: u32, + pub ip: String, +} + +impl VaultServer { + fn format_address(&self, host: &str, port: u32) -> String { + format!("{}:{}", host, port) + } + + fn format_url(&self, host: &str, port: u32) -> String { + format!("http://{}", self.format_address(host, port)) + } + + /// The external HTTP address + pub fn external_url(&self) -> String { + self.format_url("localhost", self.external_port) + } +} + +impl Server for VaultServer { + type Config = VaultServerConfig; + + fn new(config: &Self::Config, container: &dockertest::RunningContainer) -> Self { + VaultServer { + external_port: config.port, + internal_port: PORT, + ip: container.ip().to_string(), + } + } +}