cloacina-testing API Reference
The cloacina-testing crate provides a lightweight, in-process test runner that executes tasks in dependency order without any database, scheduler, or background threads. It is designed for unit testing task logic.
Overview
Section titled “Overview”use cloacina_testing::{TestRunner, TestResult, TaskOutcome};use cloacina_workflow::Context;Add to your Cargo.toml:
[dev-dependencies]cloacina-testing = "0.12"tokio = { version = "1", features = ["rt-multi-thread", "macros"] }(Inside the cloacina repo itself, workspace members use a path
dependency instead.)
TestRunner
Section titled “TestRunner”A no-DB, in-process task executor for unit tests. Runs tasks sequentially in topological (dependency) order.
pub struct TestRunner { /* private */ }
impl TestRunner { /// Create a new empty test runner. pub fn new() -> Self;
/// Register a task. Returns `self` for chaining. pub fn register(self, task: Arc<dyn Task>) -> Self;
/// Execute all registered tasks in dependency order. /// Context propagates from each task to the next. /// If a task fails, its transitive dependents are skipped. pub async fn run( &self, initial_context: Context<serde_json::Value>, ) -> Result<TestResult, TestRunnerError>;}Behavior
Section titled “Behavior”- Tasks are executed sequentially in topological order
- Context propagation: each task receives the context produced by the previous task
- Failure cascading: if a task fails, all transitive dependents are marked
Skipped - Unregistered dependencies are silently ignored, allowing you to test subsets of a workflow
- Cycle detection: returns
TestRunnerError::CyclicDependencyif the dependency graph has cycles
TestResult
Section titled “TestResult”The result of running tasks through a TestRunner.
pub struct TestResult { /// The final context after all tasks have executed. pub context: Context<serde_json::Value>, /// Per-task outcomes in execution order. pub task_outcomes: IndexMap<String, TaskOutcome>,}Index Access
Section titled “Index Access”You can index a TestResult by task ID:
assert!(result["my_task"].is_completed());Panics if the task ID is not found.
TaskOutcome
Section titled “TaskOutcome”The outcome of a single task execution.
pub enum TaskOutcome { Completed, Failed(TaskError), Skipped,}
impl TaskOutcome { pub fn is_completed(&self) -> bool; pub fn is_failed(&self) -> bool; pub fn is_skipped(&self) -> bool;
/// Returns the error if Failed, panics otherwise. pub fn unwrap_error(&self) -> &TaskError;}Assertion Helpers
Section titled “Assertion Helpers”Convenience methods on TestResult for cleaner test assertions. All panic with descriptive messages on failure.
impl TestResult { /// Assert all tasks completed successfully. pub fn assert_all_completed(&self);
/// Assert a specific task completed. pub fn assert_task_completed(&self, task_id: &str);
/// Assert a specific task failed. pub fn assert_task_failed(&self, task_id: &str);
/// Assert a specific task was skipped. pub fn assert_task_skipped(&self, task_id: &str);}TestRunnerError
Section titled “TestRunnerError”pub enum TestRunnerError { /// The dependency graph contains a cycle. CyclicDependency { cycle: Vec<String> },}Boundary and Mock Utilities
Section titled “Boundary and Mock Utilities”The following types ship unconditionally (the crate defines no cargo
features). BoundaryEmitter and MockDataConnection are re-exported
at the crate root; ComputationBoundary and ConnectionDescriptor
live at cloacina_testing::boundary::ComputationBoundary and
cloacina_testing::mock::ConnectionDescriptor.
BoundaryEmitter
Section titled “BoundaryEmitter”Simulates detector output for testing continuous/event-driven tasks. Produces a Context matching the format an accumulator’s drain() would produce.
pub struct BoundaryEmitter { /* private */ }
impl BoundaryEmitter { pub fn new() -> Self;
/// Emit a time-range boundary. pub fn emit_time_range(self, start: DateTime<Utc>, end: DateTime<Utc>) -> Self;
/// Emit an offset-range boundary. pub fn emit_offset_range(self, start: i64, end: i64) -> Self;
/// Emit a raw ComputationBoundary. pub fn emit(self, boundary: ComputationBoundary) -> Self;
/// Convert emitted boundaries into a Context. pub fn into_context(self) -> Context<serde_json::Value>;}ComputationBoundary
Section titled “ComputationBoundary”Placeholder type representing a slice of data to process.
pub enum ComputationBoundary { TimeRange { start: DateTime<Utc>, end: DateTime<Utc> }, OffsetRange { start: i64, end: i64 },}MockDataConnection
Section titled “MockDataConnection”A mock data connection for testing tasks that interact with external data sources.
pub struct MockDataConnection<T: Any + Send + Sync + Clone> { /* private */ }
impl<T: Any + Send + Sync + Clone> MockDataConnection<T> { pub fn new(handle: T, descriptor: ConnectionDescriptor) -> Self;
/// Get a clone of the underlying handle. pub fn connect(&self) -> T;
/// Get the connection descriptor. pub fn descriptor(&self) -> &ConnectionDescriptor;
/// Returns empty JSON object for mocks. pub fn system_metadata(&self) -> Value;}ConnectionDescriptor
Section titled “ConnectionDescriptor”pub struct ConnectionDescriptor { pub system_type: String, pub location: String,}