Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Internal Crate Reference

High-level roles of the crates that make up the framework:

  • Configs (testing-framework/configs/): Prepares reusable configuration primitives for nodes, networking, tracing, data availability, and wallets, shared by all scenarios and runners. Includes topology generation and circuit asset resolution.

  • Core scenario orchestration (testing-framework/core/): Houses the topology and scenario model, runtime coordination, node clients, and readiness/health probes. Defines Deployer and Runner traits, ScenarioBuilder, and RunContext.

  • Workflows (testing-framework/workflows/): Packages workloads (transaction, DA, chaos) and expectations (consensus liveness) into reusable building blocks. Offers fluent DSL extensions (ScenarioBuilderExt, ChaosBuilderExt).

  • Runners (testing-framework/runners/{local,compose,k8s}/): Implements deployment backends (local host, Docker Compose, Kubernetes) that all consume the same scenario plan. Each provides a Deployer implementation (LocalDeployer, ComposeDeployer, K8sDeployer).

  • Runner Examples (crate name: runner-examples, path: examples/): Runnable binaries demonstrating framework usage and serving as living documentation. These are the primary entry point for running scenarios (examples/src/bin/local_runner.rs, examples/src/bin/compose_runner.rs, examples/src/bin/k8s_runner.rs).

Where to Add New Capabilities

What You’re AddingWhere It GoesExamples
Node config parametertesting-framework/configs/src/topology/configs/Slot duration, log levels, DA params
Topology featuretesting-framework/core/src/topology/New network layouts, node roles
Scenario capabilitytesting-framework/core/src/scenario/New capabilities, context methods
Workloadtesting-framework/workflows/src/workloads/New traffic generators
Expectationtesting-framework/workflows/src/expectations/New success criteria
Builder APItesting-framework/workflows/src/builder/DSL extensions, fluent methods
Deployertesting-framework/runners/New deployment backends
Example scenarioexamples/src/bin/Demonstration binaries

Extension Workflow

Adding a New Workload

  1. Define the workload in testing-framework/workflows/src/workloads/your_workload.rs:
use async_trait::async_trait;
use testing_framework_core::scenario::{DynError, RunContext, Workload};

pub struct YourWorkload;

#[async_trait]
impl Workload for YourWorkload {
    fn name(&self) -> &'static str {
        "your_workload"
    }

    async fn start(&self, _ctx: &RunContext) -> Result<(), DynError> {
        // implementation
        Ok(())
    }
}
  1. Add builder extension in testing-framework/workflows/src/builder/mod.rs:
pub struct YourWorkloadBuilder;

impl YourWorkloadBuilder {
    pub fn some_config(self) -> Self {
        self
    }
}

pub trait ScenarioBuilderExt: Sized {
    fn your_workload(self) -> YourWorkloadBuilder;
}
  1. Use in examples in examples/src/bin/your_scenario.rs:
use testing_framework_core::scenario::ScenarioBuilder;

pub struct YourWorkloadBuilder;

impl YourWorkloadBuilder {
    pub fn some_config(self) -> Self {
        self
    }
}

pub trait YourWorkloadDslExt: Sized {
    fn your_workload_with<F>(self, configurator: F) -> Self
    where
        F: FnOnce(YourWorkloadBuilder) -> YourWorkloadBuilder;
}

impl<Caps> YourWorkloadDslExt for testing_framework_core::scenario::Builder<Caps> {
    fn your_workload_with<F>(self, configurator: F) -> Self
    where
        F: FnOnce(YourWorkloadBuilder) -> YourWorkloadBuilder,
    {
        let _ = configurator(YourWorkloadBuilder);
        self
    }
}

pub fn use_in_examples() {
    let _plan = ScenarioBuilder::topology_with(|t| t.network_star().validators(3).executors(0))
        .your_workload_with(|w| w.some_config())
        .build();
}

Adding a New Expectation

  1. Define the expectation in testing-framework/workflows/src/expectations/your_expectation.rs:
use async_trait::async_trait;
use testing_framework_core::scenario::{DynError, Expectation, RunContext};

pub struct YourExpectation;

#[async_trait]
impl Expectation for YourExpectation {
    fn name(&self) -> &'static str {
        "your_expectation"
    }

    async fn evaluate(&mut self, _ctx: &RunContext) -> Result<(), DynError> {
        // implementation
        Ok(())
    }
}
  1. Add builder extension in testing-framework/workflows/src/builder/mod.rs:
use testing_framework_core::scenario::ScenarioBuilder;

pub trait YourExpectationDslExt: Sized {
    fn expect_your_condition(self) -> Self;
}

impl<Caps> YourExpectationDslExt for testing_framework_core::scenario::Builder<Caps> {
    fn expect_your_condition(self) -> Self {
        self
    }
}

pub fn use_in_examples() {
    let _plan = ScenarioBuilder::topology_with(|t| t.network_star().validators(3).executors(0))
        .expect_your_condition()
        .build();
}

Adding a New Deployer

  1. Implement Deployer trait in testing-framework/runners/your_runner/src/deployer.rs:
use async_trait::async_trait;
use testing_framework_core::scenario::{Deployer, Runner, Scenario};

#[derive(Debug)]
pub struct YourError;

pub struct YourDeployer;

#[async_trait]
impl Deployer for YourDeployer {
    type Error = YourError;

    async fn deploy(&self, _scenario: &Scenario<()>) -> Result<Runner, Self::Error> {
        // Provision infrastructure
        // Wait for readiness
        // Return Runner
        todo!()
    }
}
  1. Provide cleanup and handle node control if supported.

  2. Add example in examples/src/bin/your_runner.rs.

For detailed examples, see Extending the Framework and Custom Workload Example.