Developer guide
Testing
Testing strategy and practices for Ninja development.
Test Types
Unit Tests
Test individual components and functions:
# Run all unit tests
cargo test --workspace
# Run specific crate tests
cargo test -p core
cargo test -p CLI
# Run with output
cargo test -- --nocaptureIntegration Tests
Test ShurikenManager operations with temporary directories:
use tempfile::tempdir;
use ninja::manager::ShurikenManager;
#[tokio::test]
async fn test_install_start_stop() {
let temp = tempdir().unwrap();
let manager = ShurikenManager::new(temp.path());
// Install shuriken
manager.install("test.shuriken").await.unwrap();
// Start service
manager.start("test-service").await.unwrap();
// Verify running
let state = manager.get_state("test-service").await.unwrap();
assert_eq!(state, State::Running);
// Stop service
manager.stop("test-service").await.unwrap();
}Script Tests
Test Lua management scripts using the engine API:
use ninja::engine::NinjaEngine;
#[test]
fn test_management_script() {
let engine = NinjaEngine::new();
let script = r#"
function start()
log.info("Starting")
return true
end
"#;
engine.execute(script).unwrap();
let result = engine.call_function("start", vec![]).unwrap();
assert!(result);
}Testing Shurikens
Create Test Fixtures
tests/fixtures/
└── test-shuriken/
├── .ninja/
│ ├── manifest.toml
│ ├── options.toml
│ ├── config.tmpl
│ └── manage.ns
└── bin/
└── serviceTest Both Management Types
Test native and script-managed shurikens:
#[tokio::test]
async fn test_native_management() {
// Test with native binary
}
#[tokio::test]
async fn test_script_management() {
// Test with Lua scripts
}Manual Testing
Build and Test CLI
# Build release
cargo build -p CLI --release
# Test commands
./target/release/shurikenctl --version
./target/release/shurikenctl list
./target/release/shurikenctl install test.shurikenGUI Testing
# Build GUI
cd GUI
pnpm install
pnpm tauri dev
# Or build release
pnpm tauri buildAPI Server Testing
# Start server
cargo run -p HTTP -- --port 8080
# Test endpoints
curl http://localhost:8080/api/shurikens
curl -X POST http://localhost:8080/api/shurikens/test/startBest Practices
Use Temporary Directories
Avoid polluting ~/.ninja during tests:
use tempfile::tempdir;
#[test]
fn my_test() {
let temp = tempdir().unwrap();
let ninja_dir = temp.path();
// Use ninja_dir for test
}Mock External Dependencies
Stub system calls and network requests:
// Mock systemctl calls
#[cfg(test)]
mod tests {
fn mock_systemctl() -> bool {
true // Simulate success
}
}Test Error Cases
Verify error handling:
#[tokio::test]
async fn test_start_nonexistent() {
let result = manager.start("nonexistent").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_start_already_running() {
manager.start("test").await.unwrap();
let result = manager.start("test").await;
assert!(matches!(result, Err(NinjaError::AlreadyRunning)));
}Clean Up Resources
Ensure tests clean up processes and files:
#[tokio::test]
async fn test_with_cleanup() {
// Setup
manager.start("test").await.unwrap();
// Test
// ...
// Cleanup
manager.stop("test").await.ok();
}Continuous Integration
GitHub Actions
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- run: cargo test --workspace
- run: cargo build --releaseCoverage
Generate coverage reports:
# Install tarpaulin
cargo install cargo-tarpaulin
# Generate coverage
cargo tarpaulin --workspace --out Html
# View report
open tarpaulin-report.htmlPerformance Testing
Benchmark critical operations:
#[bench]
fn bench_start_stop(b: &mut Bencher) {
b.iter(|| {
manager.start("test").await.unwrap();
manager.stop("test").await.unwrap();
});
}See also: Contributing, Architecture