remora/crates/remora-domain/tests/golden.rs

137 lines
3.7 KiB
Rust
Raw Normal View History

use remora_domain::{
BucketName, FailureDisposition, JobPhase, MemberPath, RuntimeFailureClass, StorageScope,
Target, TargetPrefix, TargetStoreId, fingerprint,
};
use serde::Deserialize;
use serde_json::Value;
#[derive(Deserialize)]
struct Corpus {
job_phases: Vec<JobPhase>,
runtime_failures: Vec<FailureCase>,
buckets: ValidationCases<String>,
target_prefixes: ValidationCases<CanonicalCase>,
reserved_target_prefixes: Vec<ReservedPrefixCase>,
member_paths: ValidationCases<CanonicalCase>,
scope_coverage: Vec<ScopeCase>,
fingerprints: Vec<FingerprintCase>,
}
#[derive(Deserialize)]
struct FailureCase {
class: RuntimeFailureClass,
disposition: FailureDisposition,
}
#[derive(Deserialize)]
struct ValidationCases<T> {
valid: Vec<T>,
invalid: Vec<String>,
}
#[derive(Deserialize)]
struct CanonicalCase {
input: String,
canonical: String,
}
#[derive(Deserialize)]
struct FingerprintCase {
value: Value,
canonical: String,
sha256: String,
}
#[derive(Deserialize)]
struct ScopeCase {
scope: [String; 3],
target: [String; 3],
covers: bool,
}
#[derive(Deserialize)]
struct ReservedPrefixCase {
input: String,
reserved: Vec<String>,
}
fn corpus() -> Corpus {
serde_json::from_str(include_str!("../../../contracts/golden/domain.json")).unwrap()
}
#[test]
fn protocol_phase_vocabulary_is_exact() {
let phases = corpus().job_phases;
assert_eq!(phases.len(), 7);
assert!(phases[..4].iter().all(|phase| !phase.is_terminal()));
assert!(phases[4..].iter().all(|phase| phase.is_terminal()));
}
#[test]
fn runtime_failure_dispositions_match_the_architecture() {
for case in corpus().runtime_failures {
assert_eq!(case.class.disposition(), case.disposition);
}
}
#[test]
fn domain_values_validate_and_normalize() {
let corpus = corpus();
for value in corpus.buckets.valid {
assert_eq!(BucketName::parse(&value).unwrap().as_str(), value);
}
for value in corpus.buckets.invalid {
assert!(BucketName::parse(value).is_err());
}
for case in corpus.target_prefixes.valid {
assert_eq!(
TargetPrefix::parse(&case.input, []).unwrap().canonical(),
case.canonical
);
}
for value in corpus.target_prefixes.invalid {
assert!(TargetPrefix::parse(&value, []).is_err());
}
for case in corpus.reserved_target_prefixes {
assert!(
TargetPrefix::parse(&case.input, case.reserved.iter().map(String::as_str)).is_err()
);
}
for case in corpus.member_paths.valid {
assert_eq!(
MemberPath::parse(&case.input).unwrap().canonical(),
case.canonical
);
}
for value in corpus.member_paths.invalid {
assert!(MemberPath::parse(&value).is_err());
}
}
#[test]
fn request_fingerprints_match_the_shared_corpus() {
for case in corpus().fingerprints {
assert_eq!(
serde_json_canonicalizer::to_string(&case.value).unwrap(),
case.canonical
);
assert_eq!(fingerprint(&case.value).unwrap().to_hex(), case.sha256);
}
}
#[test]
fn storage_scope_coverage_uses_exact_segment_tuples() {
for case in corpus().scope_coverage {
let scope = StorageScope {
store: TargetStoreId::parse(&case.scope[0]).unwrap(),
bucket: BucketName::parse(&case.scope[1]).unwrap(),
prefix: TargetPrefix::parse(&case.scope[2], []).unwrap(),
};
let target = Target {
store: TargetStoreId::parse(&case.target[0]).unwrap(),
bucket: BucketName::parse(&case.target[1]).unwrap(),
prefix: TargetPrefix::parse(&case.target[2], []).unwrap(),
};
assert_eq!(scope.covers(&target), case.covers);
}
}