132 lines
5.1 KiB
Rust
132 lines
5.1 KiB
Rust
use std::env;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
|
|
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
|
|
use tempfile::TempDir;
|
|
|
|
const CONFIG_DIRECTORY: &str = "crates/service/job/test_job/config";
|
|
const BACKUP_DIRECTORY: &str = "secrets/artcraft-backup";
|
|
const CHILD_PROCESS: &str = "BOOTSTRAP_CONFIG_TEST_CHILD";
|
|
const VALUE: &str = "BOOTSTRAP_CONFIG_TEST_VALUE";
|
|
const MISSING_VALUE: &str = "BOOTSTRAP_CONFIG_TEST_MISSING_VALUE";
|
|
const COMMON_VALUE: &str = "BOOTSTRAP_CONFIG_TEST_COMMON_VALUE";
|
|
|
|
mod development {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn loads_checkout_configs_and_backup_secrets_from_roots_and_subdirectories() {
|
|
for name in ["artcraft", "artcraft-services"] {
|
|
let (_temporary, root) = checkout(name);
|
|
write_config(&root, CONFIG_DIRECTORY, "common", &format!("{COMMON_VALUE}=common\n"));
|
|
write_config(&root, BACKUP_DIRECTORY, "development-secrets", &format!("{VALUE}=backup\n"));
|
|
|
|
// The other checkout must not supply this process's secrets.
|
|
let sibling_name = if name == "artcraft" { "artcraft-services" } else { "artcraft" };
|
|
let sibling = root.parent().unwrap().join(sibling_name);
|
|
write_config(&sibling, BACKUP_DIRECTORY, "development-secrets", &format!("{VALUE}=wrong-checkout\n"));
|
|
|
|
// Nested directories can themselves be named artcraft without being the repo root.
|
|
let nested = root.join("crates/api_clients/artcraft/test_client");
|
|
fs::create_dir_all(&nested).unwrap();
|
|
for directory in [&root, &root.join(CONFIG_DIRECTORY), &nested] {
|
|
run_bootstrap(directory, "development", "backup", "common", false);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn environment_and_local_configs_take_precedence_but_backup_fills_missing_values() {
|
|
let (_temporary, root) = checkout("artcraft-services");
|
|
write_config(&root, CONFIG_DIRECTORY, "development-secrets", &format!("{VALUE}=local\n"));
|
|
write_config(&root, BACKUP_DIRECTORY, "development-secrets",
|
|
&format!("{VALUE}=backup\n{MISSING_VALUE}=backup-only\n"));
|
|
|
|
run_bootstrap(&root, "development", "local", "", true);
|
|
run_bootstrap(&root, "development", "environment", "", true);
|
|
}
|
|
}
|
|
|
|
mod deployment {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn production_does_not_read_development_secrets() {
|
|
let (_temporary, root) = checkout("artcraft-services");
|
|
write_config(&root, CONFIG_DIRECTORY, "production", &format!("{VALUE}=production\n"));
|
|
write_config(&root, BACKUP_DIRECTORY, "development-secrets", &format!("{MISSING_VALUE}=backup-only\n"));
|
|
|
|
run_bootstrap(&root.join(CONFIG_DIRECTORY), "production", "production", "", false);
|
|
}
|
|
|
|
#[test]
|
|
fn configured_paths_still_work_outside_named_checkouts() {
|
|
let temporary = TempDir::new().unwrap();
|
|
let root = temporary.path().join("deployment");
|
|
write_config(&root, "config", "development-secrets", &format!("{VALUE}=deployment\n"));
|
|
write_config(&root, BACKUP_DIRECTORY, "development-secrets", &format!("{MISSING_VALUE}=backup-only\n"));
|
|
|
|
run_bootstrap(&root, "development", "deployment", "", false);
|
|
}
|
|
}
|
|
|
|
// Run bootstrap in a subprocess so environment and logger changes cannot affect other tests.
|
|
#[test]
|
|
fn bootstrap_child_process() {
|
|
if env::var_os(CHILD_PROCESS).is_none() {
|
|
return;
|
|
}
|
|
|
|
bootstrap(BootstrapArgs {
|
|
app_name: "bootstrap-test",
|
|
default_logging_override: None,
|
|
config_search_directories: &[".", "./config", CONFIG_DIRECTORY],
|
|
ignore_legacy_dot_env_file: true,
|
|
}).unwrap();
|
|
|
|
assert_eq!(env::var(VALUE).unwrap(), env::var("EXPECTED_VALUE").unwrap());
|
|
assert_eq!(env::var(COMMON_VALUE).unwrap_or_default(), env::var("EXPECTED_COMMON_VALUE").unwrap());
|
|
if env::var("EXPECT_BACKUP_VALUE").unwrap() == "true" {
|
|
assert_eq!(env::var(MISSING_VALUE).unwrap(), "backup-only");
|
|
} else {
|
|
assert!(env::var_os(MISSING_VALUE).is_none());
|
|
}
|
|
}
|
|
|
|
fn run_bootstrap(directory: &Path, environment: &str, expected: &str, expected_common: &str, expect_backup: bool) {
|
|
let mut command = Command::new(env::current_exe().unwrap());
|
|
command.args(["--exact", "bootstrap_child_process", "--nocapture"])
|
|
.current_dir(directory)
|
|
.env_clear()
|
|
.env(CHILD_PROCESS, "1")
|
|
.env("RUST_LOG", "error")
|
|
.env("SERVER_ENVIRONMENT", environment)
|
|
.env("EXPECTED_VALUE", expected)
|
|
.env("EXPECTED_COMMON_VALUE", expected_common)
|
|
.env("EXPECT_BACKUP_VALUE", expect_backup.to_string());
|
|
|
|
if expected == "environment" {
|
|
command.env(VALUE, "environment");
|
|
}
|
|
|
|
let output = command.output().unwrap();
|
|
assert!(output.status.success(), "bootstrap failed in {directory:?}:\n{}\n{}",
|
|
String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
|
|
}
|
|
|
|
fn checkout(name: &str) -> (TempDir, PathBuf) {
|
|
let temporary = TempDir::new().unwrap();
|
|
let root = temporary.path().join(name);
|
|
fs::create_dir_all(root.join(CONFIG_DIRECTORY)).unwrap();
|
|
fs::write(root.join("Cargo.toml"), "[workspace]\n").unwrap();
|
|
(temporary, root)
|
|
}
|
|
|
|
fn write_config(root: &Path, directory: &str, suffix: &str, contents: &str) {
|
|
let directory = root.join(directory);
|
|
fs::create_dir_all(&directory).unwrap();
|
|
fs::write(directory.join(format!("bootstrap-test.{suffix}.env")), contents).unwrap();
|
|
}
|