Files
khadhroony-solana-project/crates/ksp-config-lib/unit_tests/composite.rs

255 lines
12 KiB
Rust

// file: crates/ksp-config-lib/unit_tests/composite.rs
// version: 4
const TEST_COMPOSITE_FILENAME: &str = "examples/composite.example.json";
const TEST_COMPOSITE_FILE_ID: &str = "cfg.composite.test";
#[test]
fn fixture_composite_example_resolves_default_document_profile() {
let engine = fixture_example_engine();
let file_id = crate::ConfigFileId::new(TEST_COMPOSITE_FILE_ID);
assert!(engine.is_ok(), "composite test engine should be constructible: {engine:?}");
assert!(file_id.is_ok(), "composite test file_id should be valid: {file_id:?}");
if let (std::result::Result::Ok(engine), std::result::Result::Ok(file_id)) = (engine, file_id) {
let resolved = engine.load_resolved_composite(&file_id, std::option::Option::None);
assert!(resolved.is_ok(), "fixture composite example should resolve: {resolved:?}");
if let std::result::Result::Ok(resolved) = resolved {
assert_eq!(resolved.profile_id(), "local_default");
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::DefaultProfile);
let logging = resolved.component("logging");
assert!(logging.is_some(), "logging component should be resolved");
if let std::option::Option::Some(logging) = logging {
assert_eq!(logging.resolved().file_id().as_str(), crate::FILE_ID_STD_LOGGING);
let logging_document = engine.load_validated_document(logging.resolved().file_id());
assert!(logging_document.is_ok(), "referenced Logging document should validate: {logging_document:?}");
if let std::result::Result::Ok(logging_document) = logging_document {
let default_profile = logging_document.value().get("default_profile").and_then(serde_json::Value::as_str);
assert_eq!(default_profile, std::option::Option::Some(logging.resolved().profile_id()));
}
assert_eq!(logging.resolved().selection_source(), crate::ConfigProfileSelectionSource::DefaultProfile);
assert_eq!(logging.resolved().origin("logs_directory"), std::option::Option::Some(crate::ConfigValueOrigin::Global));
}
}
}
}
#[test]
fn composite_profile_override_marks_referenced_profile_selection_as_composite() {
let engine = fixture_example_engine();
let file_id = crate::ConfigFileId::new(TEST_COMPOSITE_FILE_ID);
assert!(engine.is_ok(), "composite test engine should be constructible: {engine:?}");
assert!(file_id.is_ok(), "composite test file_id should be valid: {file_id:?}");
if let (std::result::Result::Ok(engine), std::result::Result::Ok(file_id)) = (engine, file_id) {
let resolved = engine.load_resolved_composite(&file_id, std::option::Option::Some("local_explicit"));
assert!(resolved.is_ok(), "explicit composite profile should resolve: {resolved:?}");
if let std::result::Result::Ok(resolved) = resolved {
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::Explicit);
let logging = resolved.component("logging");
assert!(logging.is_some(), "logging component should be resolved");
if let std::option::Option::Some(logging) = logging {
assert_eq!(logging.resolved().profile_id(), "local_dev");
assert_eq!(logging.resolved().selection_source(), crate::ConfigProfileSelectionSource::Composite);
}
}
}
}
#[test]
fn unknown_composite_profile_has_profile_not_found_error() {
let engine = fixture_example_engine();
let file_id = crate::ConfigFileId::new(TEST_COMPOSITE_FILE_ID);
assert!(engine.is_ok(), "composite test engine should be constructible: {engine:?}");
assert!(file_id.is_ok(), "composite test file_id should be valid: {file_id:?}");
if let (std::result::Result::Ok(engine), std::result::Result::Ok(file_id)) = (engine, file_id) {
let result = engine.load_resolved_composite(&file_id, std::option::Option::Some("missing"));
assert!(result.is_err(), "unknown composite profile must be rejected: {result:?}");
if let std::result::Result::Err(error) = result {
assert_eq!(error.code(), crate::ERROR_CODE_PROFILE_NOT_FOUND);
}
}
}
#[test]
fn unknown_referenced_file_id_is_rejected_during_composite_validation() {
let fixture = fixture_roots("unknown-reference");
let composite = r#"{
"format_version": 1,
"default_profile": "test",
"profiles": [{
"profile_id": "test",
"documents": [{"component_id": "missing", "file_id": "cfg.std.missing"}]
}]
}"#;
let prepared = prepare_fixture(&fixture, composite);
assert!(prepared.is_ok(), "composite fixture should be writable: {prepared:?}");
if prepared.is_ok() {
let engine = fixture_engine(&fixture);
let file_id = crate::ConfigFileId::new(TEST_COMPOSITE_FILE_ID);
assert!(engine.is_ok(), "fixture engine should be constructible: {engine:?}");
if let (std::result::Result::Ok(engine), std::result::Result::Ok(file_id)) = (engine, file_id) {
let result = engine.load_validated_document(&file_id);
assert!(result.is_err(), "unknown composite reference must be rejected: {result:?}");
if let std::result::Result::Err(error) = result {
assert_eq!(error.code(), crate::ERROR_CODE_COMPOSITE_REFERENCE_INVALID);
}
}
}
cleanup_fixture(&fixture);
}
#[test]
fn duplicate_component_ids_are_rejected_inside_one_composite_profile() {
let fixture = fixture_roots("duplicate-component");
let composite = r#"{
"format_version": 1,
"default_profile": "test",
"profiles": [{
"profile_id": "test",
"documents": [
{"component_id": "logging", "file_id": "cfg.std.logging"},
{"component_id": "logging", "file_id": "cfg.std.logging"}
]
}]
}"#;
let prepared = prepare_fixture(&fixture, composite);
assert!(prepared.is_ok(), "composite fixture should be writable: {prepared:?}");
if prepared.is_ok() {
let engine = fixture_engine(&fixture);
let file_id = crate::ConfigFileId::new(TEST_COMPOSITE_FILE_ID);
assert!(engine.is_ok(), "fixture engine should be constructible: {engine:?}");
if let (std::result::Result::Ok(engine), std::result::Result::Ok(file_id)) = (engine, file_id) {
let result = engine.load_validated_document(&file_id);
assert!(result.is_err(), "duplicate component_id must be rejected: {result:?}");
if let std::result::Result::Err(error) = result {
assert_eq!(error.code(), crate::ERROR_CODE_DOCUMENT_SEMANTIC_INVALID);
}
}
}
cleanup_fixture(&fixture);
}
fn fixture_example_engine() -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
let workspace = workspace_root();
let fixture_root = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("unit_tests/fixtures");
let bootstrap = crate::ConfigBootstrapOptions::from_paths(fixture_root, workspace.join("config/schemas"));
let bootstrap = match bootstrap {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let registry = test_registry(TEST_COMPOSITE_FILENAME);
return match registry {
std::result::Result::Ok(value) => std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, value)),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
fn fixture_engine(fixture: &FixtureRoots) -> ksp_core_lib::Result<crate::ConfigDocumentEngine> {
let bootstrap = crate::ConfigBootstrapOptions::from_paths(fixture.config.as_path(), fixture.schemas.as_path());
let bootstrap = match bootstrap {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let registry = test_registry("composite.test.json");
return match registry {
std::result::Result::Ok(value) => std::result::Result::Ok(crate::ConfigDocumentEngine::new(bootstrap, value)),
std::result::Result::Err(error) => std::result::Result::Err(error),
};
}
fn test_registry(composite_filename: &'static str) -> ksp_core_lib::Result<crate::ConfigFileRegistry> {
let logging = crate::registry::ConfigFileDescriptor::new(
crate::FILE_ID_STD_LOGGING,
crate::ConfigFileKind::Config,
crate::DEFAULT_STD_LOGGING_FILENAME,
std::option::Option::Some(crate::FILE_ID_SCHEMA_STD_LOGGING),
);
let logging = match logging {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let logging_schema = crate::registry::ConfigFileDescriptor::new(
crate::FILE_ID_SCHEMA_STD_LOGGING,
crate::ConfigFileKind::Schema,
crate::DEFAULT_STD_LOGGING_SCHEMA_FILENAME,
std::option::Option::None,
);
let logging_schema = match logging_schema {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let composite_schema = crate::registry::ConfigFileDescriptor::new(
crate::FILE_ID_SCHEMA_COMPOSITE,
crate::ConfigFileKind::Schema,
crate::DEFAULT_COMPOSITE_SCHEMA_FILENAME,
std::option::Option::None,
);
let composite_schema = match composite_schema {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let composite = crate::registry::ConfigFileDescriptor::new(
TEST_COMPOSITE_FILE_ID,
crate::ConfigFileKind::Config,
composite_filename,
std::option::Option::Some(crate::FILE_ID_SCHEMA_COMPOSITE),
);
let composite = match composite {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return crate::build_registry([logging, logging_schema, composite_schema, composite]);
}
fn prepare_fixture(fixture: &FixtureRoots, composite: &str) -> std::io::Result<()> {
cleanup_fixture(fixture);
let config = std::fs::create_dir_all(fixture.config.as_path());
if let std::result::Result::Err(error) = config {
return std::result::Result::Err(error);
}
let schemas = std::fs::create_dir_all(fixture.schemas.as_path());
if let std::result::Result::Err(error) = schemas {
return std::result::Result::Err(error);
}
let workspace = workspace_root();
let stable_logging = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("unit_tests/fixtures/std.logging.json");
let logging = std::fs::copy(stable_logging, fixture.config.join(crate::DEFAULT_STD_LOGGING_FILENAME));
if let std::result::Result::Err(error) = logging {
return std::result::Result::Err(error);
}
let logging_schema =
std::fs::copy(workspace.join("config/schemas/std.logging.schema.json"), fixture.schemas.join(crate::DEFAULT_STD_LOGGING_SCHEMA_FILENAME));
if let std::result::Result::Err(error) = logging_schema {
return std::result::Result::Err(error);
}
let composite_schema =
std::fs::copy(workspace.join("config/schemas/composite.schema.json"), fixture.schemas.join(crate::DEFAULT_COMPOSITE_SCHEMA_FILENAME));
if let std::result::Result::Err(error) = composite_schema {
return std::result::Result::Err(error);
}
return std::fs::write(fixture.config.join("composite.test.json"), composite);
}
fn workspace_root() -> std::path::PathBuf {
return std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
}
struct FixtureRoots {
root: std::path::PathBuf,
config: std::path::PathBuf,
schemas: std::path::PathBuf,
}
fn fixture_roots(name: &str) -> FixtureRoots {
let root = std::env::temp_dir().join(format!("ksp-config-composite-{name}-{}", std::process::id()));
return FixtureRoots { config: root.join("config"), schemas: root.join("schemas"), root };
}
fn cleanup_fixture(fixture: &FixtureRoots) {
let removal = std::fs::remove_dir_all(fixture.root.as_path());
if let std::result::Result::Err(error) = removal
&& error.kind() != std::io::ErrorKind::NotFound
{
eprintln!("unable to cleanup Config composite fixture {}: {error}", fixture.root.display());
}
}