162 lines
6.3 KiB
Rust
162 lines
6.3 KiB
Rust
// file: crates/ksp-worker-api/tests/release_completeness.rs
|
|
// version: 1
|
|
|
|
//! Exact frozen-surface and domain-firewall canaries for `ksp-worker-api`.
|
|
|
|
#[test]
|
|
fn pre_003_crate_root_export_inventory_is_exact() {
|
|
let crate_root = include_str!("../src/lib.rs");
|
|
let mut actual = std::vec::Vec::new();
|
|
for line in crate_root.lines() {
|
|
let trimmed = line.trim();
|
|
if trimmed.starts_with("pub use ") {
|
|
actual.push(trimmed);
|
|
}
|
|
}
|
|
actual.sort_unstable();
|
|
let mut expected = std::vec![
|
|
"pub use self::error::ERROR_CODE_WORKER_ID_INVALID;",
|
|
"pub use self::error::ERROR_CODE_WORKER_KIND_INVALID;",
|
|
"pub use self::error::ERROR_CODE_WORKER_SNAPSHOT_SEQUENCE_EXHAUSTED;",
|
|
"pub use self::error::ERROR_CODE_WORKER_TRANSITION_INVALID;",
|
|
"pub use self::identity::MAX_WORKER_ID_BYTES;",
|
|
"pub use self::identity::MAX_WORKER_KIND_CODE_BYTES;",
|
|
"pub use self::identity::WorkerId;",
|
|
"pub use self::identity::WorkerKindCode;",
|
|
"pub use self::lifecycle::WorkerActivity;",
|
|
"pub use self::lifecycle::WorkerHealth;",
|
|
"pub use self::lifecycle::WorkerLifecycle;",
|
|
"pub use self::lifecycle::WorkerState;",
|
|
"pub use self::snapshot::WorkerSnapshot;",
|
|
"pub use self::snapshot::WorkerSnapshotFuture;",
|
|
"pub use self::snapshot::WorkerSnapshotSequence;",
|
|
"pub use self::snapshot::WorkerSnapshotSource;",
|
|
"pub use self::stop::WorkerStopToken;",
|
|
"pub use ksp_core_lib::Error;",
|
|
"pub use ksp_core_lib::ErrorCode;",
|
|
"pub use ksp_core_lib::ErrorContext;",
|
|
"pub use ksp_core_lib::Result;",
|
|
];
|
|
expected.sort_unstable();
|
|
assert_eq!(actual, expected);
|
|
assert!(!crate_root.contains("pub mod "));
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_003_production_module_inventory_is_exact() -> std::io::Result<()> {
|
|
let source_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
|
|
let entries = match std::fs::read_dir(source_root) {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let mut names = std::vec::Vec::new();
|
|
for entry in entries {
|
|
let entry = match entry {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let file_type = match entry.file_type() {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
if !file_type.is_file() {
|
|
continue;
|
|
}
|
|
let name = match entry.file_name().into_string() {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => continue,
|
|
};
|
|
if name.ends_with(".rs") {
|
|
names.push(name);
|
|
}
|
|
}
|
|
names.sort_unstable();
|
|
assert_eq!(names, std::vec!["error.rs", "identity.rs", "lib.rs", "lifecycle.rs", "snapshot.rs", "stop.rs"]);
|
|
return std::result::Result::Ok(());
|
|
}
|
|
|
|
#[test]
|
|
fn pre_003_fixed_snapshot_shape_contains_only_common_worker_dimensions() {
|
|
let snapshot = include_str!("../src/snapshot.rs");
|
|
let struct_start = match snapshot.find("pub struct WorkerSnapshot {") {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let after_start = &snapshot[struct_start..];
|
|
let struct_end = match after_start.find("\n}") {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => return,
|
|
};
|
|
let definition = &after_start[..struct_end];
|
|
for required in ["id:", "kind:", "sequence:", "state:", "health:", "activity:"] {
|
|
assert!(definition.contains(required), "missing frozen Worker snapshot field: {required}");
|
|
}
|
|
for forbidden in ["String", "Vec<", "payload", "slot", "signature", "provider", "endpoint", "checkpoint", "backfill", "transaction"] {
|
|
assert!(!definition.contains(forbidden), "domain or arbitrary payload leaked into frozen Worker snapshot: {forbidden}");
|
|
}
|
|
let fields = definition.lines().filter(|line| {
|
|
let line = line.trim_start();
|
|
return line.starts_with("id:")
|
|
|| line.starts_with("kind:")
|
|
|| line.starts_with("sequence:")
|
|
|| line.starts_with("state:")
|
|
|| line.starts_with("health:")
|
|
|| line.starts_with("activity:");
|
|
});
|
|
assert_eq!(fields.count(), 6);
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn pre_003_surface_remains_runtime_neutral_job_independent_and_domain_free() {
|
|
let sources = [
|
|
include_str!("../src/error.rs"),
|
|
include_str!("../src/identity.rs"),
|
|
include_str!("../src/lib.rs"),
|
|
include_str!("../src/lifecycle.rs"),
|
|
include_str!("../src/snapshot.rs"),
|
|
include_str!("../src/stop.rs"),
|
|
];
|
|
for source in sources {
|
|
for forbidden in [
|
|
"Backfill",
|
|
"RawTransaction",
|
|
"WorkerHandle",
|
|
"checkpoint",
|
|
"endpoint",
|
|
"futures::",
|
|
"futures_util::",
|
|
"ksp_config_lib::",
|
|
"ksp_interface_lib::",
|
|
"ksp_job_api::",
|
|
"ksp_logging_lib::",
|
|
"ksp_offchain_transport_lib::",
|
|
"ksp_onchain_transport_lib::",
|
|
"ksp_store_api::",
|
|
"ksp_store_lib::",
|
|
"provider",
|
|
"reqwest::",
|
|
"serde::",
|
|
"serde_json::",
|
|
"slot",
|
|
"solana_",
|
|
"tauri::",
|
|
"tokio::",
|
|
"tonic::",
|
|
concat!("tracing", "::"),
|
|
] {
|
|
assert!(!source.contains(forbidden), "forbidden frozen Worker API concern detected: {forbidden}");
|
|
}
|
|
}
|
|
let snapshot = include_str!("../src/snapshot.rs");
|
|
assert!(snapshot.contains("pub trait WorkerSnapshotSource: std::marker::Send + std::marker::Sync"));
|
|
assert!(snapshot.contains("std::future::Future"));
|
|
assert!(!snapshot.contains("std::sync::mpsc"));
|
|
assert!(!snapshot.contains("VecDeque"));
|
|
let lifecycle = include_str!("../src/lifecycle.rs");
|
|
assert!(lifecycle.contains("#[derive(Eq, PartialEq)]\npub struct WorkerLifecycle"));
|
|
assert!(!lifecycle.contains("#[derive(Clone, Eq, PartialEq)]\npub struct WorkerLifecycle"));
|
|
return;
|
|
}
|