// file: crates/ksp-job-api/tests/public_api.rs // version: 1 //! External-consumer canaries for the public Job API foundation. #[test] fn pre_002_identity_lifecycle_and_cancellation_are_consumable_from_crate_root() { let id = ksp_job_api::JobId::new("campaign-2026.09.01:001"); let kind = ksp_job_api::JobKindCode::new("backfill_raw"); assert!(id.is_ok()); assert!(kind.is_ok()); let id = match id { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let kind = match kind { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let mut lifecycle = ksp_job_api::JobLifecycle::new(id.clone(), kind.clone()); assert_eq!(lifecycle.id(), &id); assert_eq!(lifecycle.kind(), &kind); assert_eq!(lifecycle.state(), ksp_job_api::JobState::Created); assert!(lifecycle.start().is_ok()); assert!(lifecycle.complete(ksp_job_api::JobCompletion::Partial).is_ok()); assert_eq!(lifecycle.state().completion(), std::option::Option::Some(ksp_job_api::JobCompletion::Partial)); let token = ksp_job_api::JobCancellationToken::new(); let clone = token.clone(); assert!(token.cancel()); assert!(clone.is_cancellation_requested()); assert!(!clone.cancel()); return; } #[test] fn pre_002_error_codes_are_stable_and_core_owned() { let codes: [ksp_core_lib::ErrorCode; 3] = [ksp_job_api::ERROR_CODE_JOB_ID_INVALID, ksp_job_api::ERROR_CODE_JOB_KIND_INVALID, ksp_job_api::ERROR_CODE_JOB_TRANSITION_INVALID]; assert_eq!(codes[0].domain(), "job_api"); assert_eq!(codes[0].code(), "job_id_invalid"); assert_eq!(codes[1].domain(), "job_api"); assert_eq!(codes[1].code(), "job_kind_invalid"); assert_eq!(codes[2].domain(), "job_api"); assert_eq!(codes[2].code(), "job_transition_invalid"); return; } #[test] fn pre_002_public_bounds_are_exact() { assert_eq!(ksp_job_api::MAX_JOB_ID_BYTES, 128); assert_eq!(ksp_job_api::MAX_JOB_KIND_CODE_BYTES, 128); return; }