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

Testing Guide

How to run and write tests for odoo-rust-mcp.


Rust Tests

Unit Tests

cd rust-mcp

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_search_operation

# Run tests with warnings as errors (same as CI)
RUSTFLAGS='-Dwarnings' cargo test

Config Manager Tests

The config manager has dedicated unit and integration tests that run with sequential threading to avoid port conflicts:

cd rust-mcp

# Unit tests (in-process)
cargo test --lib config_manager -- --nocapture --test-threads=1

# Integration tests (spawns actual HTTP server)
cargo test --test config_manager -- --nocapture

Cross-Platform Tests

Tests run on Linux, macOS, and Windows in CI:

# Run all tests with all features enabled (same as CI matrix)
cargo test --all-features

Config UI Tests

The React Config UI uses Vitest with Istanbul coverage:

cd config-ui

# Run tests
npm test

# Run tests with coverage report
npm run test:coverage

# Type checking (not tests, but catches errors)
npm run typecheck

# Linting
npm run lint

Coverage output is written to config-ui/coverage/ in Cobertura XML format.


Smoke Testing

WebSocket Smoke Client

End-to-end validation of MCP operations against a running server:

cd rust-mcp
cargo run --release --bin ws_smoke_client -- \
  --url ws://127.0.0.1:8787 \
  --instance default \
  --model res.partner

Expected output:

tools/list: 24 tools
- odoo_search
- odoo_search_read
- odoo_read
- ...
odoo_count result: {"count":18}
odoo_search_read count: 2
prompts/list: odoo_common_models, odoo_domain_filters, odoo_field_types, odoo_workflow_states, odoo_read_group, odoo_context, odoo_api_tips, odoo_owl_components, odoo_assets_and_bundles, odoo_frontend_contexts, odoo_qweb_and_templates

HTTP Health Check

curl http://127.0.0.1:8787/health

Expected:

{
  "service": "odoo-rust-mcp",
  "status": "ok"
}

Config UI Health Check

curl http://127.0.0.1:3008/health

Expected:

{
  "service": "odoo-rust-mcp-config",
  "status": "ok"
}

Manual Testing Checklist

Transport Modes

  • stdio: Test with Cursor or Claude Desktop
  • HTTP: Test with curl or Postman
  • WebSocket: Test with ws_smoke_client
  • SSE: Test streaming responses

Authentication

  • Odoo 19+: Test API key authentication (JSON-2 client)
  • Odoo <19: Test username/password authentication (JSON-RPC client)
  • Multi-instance: Test switching between instances
  • MCP HTTP auth: Test Bearer token authentication

Tools

  • Read tools: search, search_read, read, count, name_search, name_get
  • Write tools: create, create_batch, update, delete, copy
  • Workflow tools: execute, workflow_action
  • Metadata tools: list_models, get_model_metadata, default_get, check_access
  • Advanced tools: read_group, onchange, generate_report
  • Cleanup tools: database_cleanup, deep_cleanup (requires ODOO_ENABLE_CLEANUP_TOOLS=true)

Config UI

  • Login with default credentials
  • Change password
  • Edit instances (add, modify, remove)
  • Edit tools (enable/disable)
  • Edit prompts
  • Edit server metadata
  • Enable/disable MCP HTTP auth
  • Generate MCP auth token

Writing Tests

Unit Test Example

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_domain() {
        let domain = r#"[["name", "=", "Test"]]"#;
        let result = parse_domain(domain);
        assert!(result.is_ok());
    }

    #[test]
    fn test_invalid_domain() {
        let domain = "invalid";
        let result = parse_domain(domain);
        assert!(result.is_err());
    }
}
}

Async Test Example

#![allow(unused)]
fn main() {
#[tokio::test]
async fn test_odoo_client() {
    let client = OdooClient::new(config).await.unwrap();
    let result = client.search("res.partner", &[]).await;
    assert!(result.is_ok());
}
}

Test Coverage

Rust Coverage (cargo-tarpaulin)

cd rust-mcp

# Install tarpaulin
cargo install cargo-tarpaulin

# Generate HTML report
cargo tarpaulin --all-targets --all-features --out Html

# Generate Cobertura XML (for CI upload)
cargo tarpaulin --all-targets --all-features --out xml --output-dir coverage

TypeScript Coverage (Istanbul via Vitest)

cd config-ui
npm run test:coverage

Coverage reports are uploaded to Codecov in CI.


CI/CD Pipeline

GitHub Actions runs on every push to main and on pull requests. The pipeline has 4 stages:

Stage 1: Build UI

Builds the React Config UI first (required dependency for all other jobs):

build-ui
  -> npm ci
  -> npm run build
  -> Upload artifact: config-ui-dist

Stage 2: Parallel Quality Checks

All run in parallel after build-ui completes:

JobDescription
checkcargo check --all-features
fmtcargo fmt --all --check
clippycargo clippy -- -D warnings
testcargo test on Linux, macOS, Windows
ui-testsnpm test (Vitest)
coverageRust (tarpaulin) + TypeScript (Istanbul), uploaded to Codecov
securitycargo audit
config-testsConfig manager unit + integration tests
config-integrationBuilds release binary, starts HTTP server, tests endpoints
helm-validationhelm lint + helm template validation
docker-testDocker image build test

Stage 3: Build Release Binary

Runs after quality checks pass:

build-release (needs: build-ui, check, fmt, clippy, ui-tests)
  -> Download config-ui-dist artifact
  -> cargo build --release

Stage 4: Service Integration Tests

Tests real deployment scenarios:

JobDescription
test-systemd-serviceInstalls binary + systemd unit, tests lifecycle (start/restart/stop), tests HTTP + MCP endpoints
test-macos-serviceBuilds and runs binary on macOS, tests HTTP + MCP endpoints

Pipeline Diagram

build-ui
    |
    +---> check --------+
    +---> fmt ----------+
    +---> clippy -------+---> build-release ---> test-systemd-service
    +---> ui-tests -----+
    +---> test (matrix)
    +---> coverage
    +---> security
    +---> config-tests
    +---> config-integration
    +---> helm-validation
    +---> docker-test
    +---> test-macos-service

Test Configuration

For tests requiring an Odoo connection, set environment variables:

export TEST_ODOO_URL=http://localhost:8069
export TEST_ODOO_DB=test_db
export TEST_ODOO_API_KEY=test_key

Or use .env.test:

TEST_ODOO_URL=http://localhost:8069
TEST_ODOO_DB=test_db
TEST_ODOO_VERSION=18
TEST_ODOO_USERNAME=admin
TEST_ODOO_PASSWORD=admin

Debugging Tests

# Run with debug output
RUST_LOG=debug cargo test -- --nocapture

# Run single test with backtrace
RUST_BACKTRACE=1 cargo test test_name -- --nocapture