// file: crates/ksp-job-api/tests/release_completeness.rs // version: 1 //! Completeness canaries for the initial Job API foundation. #[test] fn pre_002_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::cancellation::JobCancellationToken;", "pub use self::error::ERROR_CODE_JOB_ID_INVALID;", "pub use self::error::ERROR_CODE_JOB_KIND_INVALID;", "pub use self::error::ERROR_CODE_JOB_TRANSITION_INVALID;", "pub use self::identity::JobId;", "pub use self::identity::JobKindCode;", "pub use self::identity::MAX_JOB_ID_BYTES;", "pub use self::identity::MAX_JOB_KIND_CODE_BYTES;", "pub use self::lifecycle::JobCompletion;", "pub use self::lifecycle::JobLifecycle;", "pub use self::lifecycle::JobState;", "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_002_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!["cancellation.rs", "error.rs", "identity.rs", "lib.rs", "lifecycle.rs"]); return std::result::Result::Ok(()); } #[test] fn pre_002_surface_does_not_open_notifications_backfill_or_worker_contracts() { let sources = [ include_str!("../src/cancellation.rs"), include_str!("../src/identity.rs"), include_str!("../src/lib.rs"), include_str!("../src/lifecycle.rs"), ]; for source in sources { for forbidden in [ "JobNotification", "JobNotificationSequence", "JobSnapshot", "JobSnapshotSource", "BackfillRequest", "WorkerControl", "WorkerState", "spawn(", "RawTransaction", "provider", "endpoint", ] { assert!(!source.contains(forbidden), "future or domain-specific Job contract leaked early: {forbidden}"); } } let lifecycle_source = include_str!("../src/lifecycle.rs"); assert!(lifecycle_source.contains("#[derive(Eq, PartialEq)]\npub struct JobLifecycle")); assert!(!lifecycle_source.contains("#[derive(Clone, Eq, PartialEq)]\npub struct JobLifecycle")); return; }