Skip to content
integration-test-authoring logo

Integration Test Authoring for Breenix

integration-test-authoring

This skill should be used when creating new integration tests for Breenix kernel features. Use for writing shared QEMU tests with checkpoint signals, creating xtask test commands, adding test workflows, and following Breenix testing patterns.

SKILL.md

Full skill instructions

Integration Test Authoring for Breenix

Create integration tests for kernel features using Breenix testing patterns.

Purpose

Breenix uses integration tests that run the actual kernel in QEMU and verify behavior through serial output. This skill provides patterns for creating robust tests.

Breenix Testing Architecture

Shared QEMU Pattern

Most tests use tests/​shared_qemu.rs to share a single QEMU instance:

Benefits:

  • All tests run in ~45 seconds (vs 10+ minutes for separate QEMU instances)
  • Tests run in sequence in one kernel boot
  • Shared setup and teardown

Test Structure:

#[test]
fn test_memory_allocation() {
    shared_qemu::run_test("memory", "✅ MEMORY TEST COMPLETE");
}

Checkpoint Signals

Tests wait for specific strings in serial output:

Common signals:

  • 🎯 KERNEL_POST_TESTS_COMPLETE 🎯 - All POST tests done
  • ✅ [FEATURE] TEST COMPLETE - Specific test done
  • USERSPACE OUTPUT: - Userspace execution
  • Custom markers for specific tests

Creating a New Integration Test

Step 1: Add Kernel-Side Test Code

Location: kernel/​src/ (appropriate module)

#[cfg(feature = "testing")]
pub fn test_my_feature() {
    use crate::serial::serial_println;

    serial_println!("=== Testing My Feature ===");

    // Test setup
    let result = setup_feature();
    assert!(result.is_ok(), "Setup failed");

    // Test operations
    let outcome = perform_operation();
    assert_eq!(outcome, expected_value);

    // Signal completion
    serial_println!("✅ MY_FEATURE TEST COMPLETE");
}

Key points:

  • Guard with #[cfg(feature = "testing")]
  • Use serial_println! for output
  • Add clear start marker
  • Add unique completion signal

Step 2: Call from POST or main

Option A: Add to POST (Power-On Self Test)

kernel/​src/​test_post.rs:

#[cfg(feature = "testing")]
pub fn run_post_tests() {
    // ... existing tests ...

    crate::my_module::test_my_feature();

    serial_println!("🎯 KERNEL_POST_TESTS_COMPLETE 🎯");
}

Option B: Create specialized test entry point

For tests that need specific setup:

#[cfg(feature = "testing")]
pub fn run_specialized_tests() {
    crate::my_module::test_my_feature();
    serial_println!("🎯 SPECIALIZED_TESTS_COMPLETE 🎯");
}

Step 3: Add Rust Integration Test

Location: tests/​test_my_feature.rs

#![cfg(test)]

mod shared_qemu;

#[test]
fn test_my_feature() {
    shared_qemu::run_test(
        "my_feature",
        "✅ MY_FEATURE TEST COMPLETE"
    );
}

For tests that need isolation:

#[test]
#[ignore]  // Run separately: cargo test test_special -- --ignored
fn test_special_case() {
    // Custom QEMU setup for this test
}

Step 4: (Optional) Add xtask Command

For complex or frequently-run tests, add to xtask/​src/​main.rs:

#[derive(StructOpt)]
enum Cmd {
    Ring3Smoke,
    Ring3Enosys,
    MyFeatureTest,  // New
}

fn my_feature_test() -> Result<()> {
    println!("Starting My Feature Test...");

    let serial_output_file = "target/​xtask_my_feature_output.txt";
    let _ = fs::remove_file(serial_output_file);

    // Start QEMU
    let mut child = Command::new("cargo")
        .args(&[
            "run", "--release",
            "--features", "testing",
            "--bin", "qemu-uefi",
            "--",
            "-serial", &format!("file:{}", serial_output_file),
            "-display", "none",
        ])
        .spawn()?;

    // Monitor for signal
    let start = Instant::now();
    let timeout = Duration::from_secs(30);
    let mut found = false;

    while start.elapsed() < timeout {
        if let Ok(mut file) = fs::File::open(serial_output_file) {
            let mut contents = String::new();
            if file.read_to_string(&mut contents).is_ok() {
                if contents.contains("✅ MY_FEATURE TEST COMPLETE") {
                    found = true;
                    break;
                }
            }
        }
        thread::sleep(Duration::from_millis(100));
    }

    let _ = child.kill();
    let _ = child.wait();

    if found {
        println!("✅ My Feature test passed");
        Ok(())
    } else {
        bail!("❌ My Feature test failed");
    }
}

Step 5: (Optional) Add CI Workflow

For features needing dedicated CI:

.github/​workflows/​my-feature-test.yml:

name: My Feature Test

on:
  push:
    paths:
      - 'kernel/​src/​my_module/​**'
      - 'tests/​test_my_feature.rs'

jobs:
  my-feature:
    runs-on: ubuntu-latest
    timeout-minutes: 20

    steps:
      - uses: actions/​checkout@v4

      - name: Install Rust
        uses: actions-rs/​toolchain@v1
        with:
          toolchain: nightly-2025-06-24
          override: true
          target: x86_64-unknown-none
          components: rust-src, llvm-tools-preview

      - name: Cache cargo
        uses: actions/​cache@v4
        with:
          path: |
            ~/​.cargo/​registry
            ~/​.cargo/​git
            target
          key: cargo-${{ runner.os }}-${{ hashFiles('**/​Cargo.lock') }}

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y qemu-system-x86 ovmf nasm

      - name: Run test
        run: cargo test test_my_feature

      - name: Upload logs
        if: always()
        uses: actions/​upload-artifact@v4
        with:
          name: my-feature-logs
          path: logs/​*.log
          retention-days: 7

Test Patterns

Pattern 1: Simple Feature Test

Use when: Testing a single subsystem or function

// Kernel side
#[cfg(feature = "testing")]
pub fn test_allocator() {
    serial_println!("=== Allocator Test ===");

    let ptr = allocate(1024);
    assert!(!ptr.is_null());

    deallocate(ptr, 1024);

    serial_println!("✅ ALLOCATOR TEST COMPLETE");
}

// Test side
#[test]
fn test_allocator() {
    shared_qemu::run_test("allocator", "✅ ALLOCATOR TEST COMPLETE");
}

Pattern 2: Userspace Test

Use when: Testing userspace execution or syscalls

// Create userspace test program
// userspace/​tests/​my_test.rs

#![no_std]
#![no_main]

use libbreenix::{sys_write, sys_exit};

#[no_mangle]
pub extern "C" fn _start() -> ! {
    sys_write(1, b"My test output\n");
    sys_exit(0);
}

// Build with userspace/​tests/​build.sh

// Kernel side - load and execute
#[cfg(feature = "testing")]
pub fn test_userspace_my_feature() {
    let binary = include_bytes!("../​../​userspace/​tests/​my_test.elf");
    create_and_run_process("my_test", binary);
    // Process will print "My test output" via syscall
}

// Test side
#[test]
fn test_userspace_my_feature() {
    shared_qemu::run_test("userspace", "My test output");
}

Pattern 3: Sequential Tests

Use when: Testing a workflow with multiple steps

#[cfg(feature = "testing")]
pub fn test_process_lifecycle() {
    serial_println!("=== Process Lifecycle Test ===");

    serial_println!("STEP 1: Creating process");
    let pid = create_process();
    assert!(pid > 0);
    serial_println!("✅ STEP 1 COMPLETE");

    serial_println!("STEP 2: Running process");
    run_process(pid);
    serial_println!("✅ STEP 2 COMPLETE");

    serial_println!("STEP 3: Terminating process");
    terminate_process(pid);
    serial_println!("✅ STEP 3 COMPLETE");

    serial_println!("✅ PROCESS_LIFECYCLE TEST COMPLETE");
}

Pattern 4: Regression Test

Use when: Preventing a specific bug from returning

// Document the original issue
#[cfg(feature = "testing")]
pub fn test_page_fault_regression() {
    serial_println!("=== Page Fault Regression Test ===");
    serial_println!("Tests fix from DIRECT_EXECUTION_FIX.md");

    // Reproduce the scenario that used to fail
    let process = create_userspace_process();
    // This used to cause double fault at int 0x80
    process.trigger_syscall();

    serial_println!("✅ NO DOUBLE FAULT - Regression test passed");
}

Best Practices

  1. Clear signals: Use unique, greppable completion markers
  2. Descriptive names: Test name should describe what's being tested
  3. Guard with feature flag: All test code behind #[cfg(feature = "testing")]
  4. Serial output: Use serial_println! for test communication
  5. Document purpose: Comment explaining what the test verifies
  6. Handle failures: Use assertions that provide useful error messages
  7. Cleanup: Ensure resources are freed even if test fails
  8. Timeout appropriately: Set realistic timeouts in xtask or CI

Debugging Tests

Test fails locally

# Run with visual output
BREENIX_VISUAL_TEST=1 cargo test test_my_feature

# Use quick debug for iteration
kernel-debug-loop/​scripts/​quick_debug.py \
  --signal "✅ MY_FEATURE TEST COMPLETE" \
  --timeout 15

# Check logs
grep "MY_FEATURE" logs/​breenix_*.log

Test fails in CI only

# Download CI artifacts
# Analyze with ci-failure-analysis
ci-failure-analysis/​scripts/​analyze_ci_failure.py \
  target/​xtask_*_output.txt

# Check for environment differences
# - Timeout too short for CI
# - Missing dependencies
# - Timing-dependent behavior

Summary

Integration test authoring requires:

  • Kernel-side test code with checkpoint signals
  • Rust integration test using shared QEMU
  • Optional xtask command for complex tests
  • Optional CI workflow for automated testing
  • Clear completion signals
  • Appropriate timeouts
  • Comprehensive documentation

Follow existing test patterns in tests/ for consistency.

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View