mirror of
https://github.com/blackboxprogramming/BlackRoad-Operating-System.git
synced 2026-03-17 03:57:13 -05:00
This commit implements a unified test orchestration system that coordinates
all test suites across the BlackRoad Operating System monorepo, providing
consistent testing behavior between local development and CI/CD environments.
## Core Components
### 1. Test Orchestrator Script (test_all.sh)
- Unified interface to run all test suites
- Smart suite detection with existence checks
- Two operational modes:
* Best-effort: Run all suites, report summary (default)
* Strict mode: Fail-fast on first error (--strict)
- Color-coded, structured output with summary table
- Modular suite functions for easy extension
- Result tracking with pass/fail/skip status and duration
- Verbose mode for detailed test output
Supported test suites:
- Backend (FastAPI + pytest)
- Agents (200+ AI agent ecosystem)
- Operator Engine (GitHub automation)
- Python SDK (pytest)
- TypeScript SDK (Jest)
- Frontend (structure validation)
### 2. GitHub Actions Workflow (.github/workflows/test-orchestrator.yml)
- Runs orchestrator in CI using same script as local dev
- Service containers (Postgres, Redis) for integration tests
- Multi-language runtime setup (Python 3.11, Node 20)
- Dependency caching for faster builds
- Test artifact uploads (coverage, reports)
- Manual workflow dispatch with suite selection
- Coverage reporting for PRs (Codecov integration)
- Automatic PR status comments
### 3. Comprehensive Documentation (TESTING.md)
- Complete testing guide for developers and AI assistants
- Quick start examples
- Suite-by-suite documentation
- Local development setup instructions
- CI/CD integration guide
- Test writing best practices
- Troubleshooting FAQ with common issues and solutions
- Framework-specific examples
## Reusable Templates (.templates/test-orchestrator/)
Created generic templates for use in other repositories:
### Template Files
- test_all.sh.template - Generic orchestrator script
- test-orchestrator.yml.template - Generic CI workflow
- TESTING.md.template - Generic testing documentation
- PROMPTS.md - AI assistant prompts for implementation
- README.md - Template usage guide and customization instructions
### Key Features
- Clear placeholders ({{REPO_NAME}}, {{PROJECT_DESCRIPTION}}, etc.)
- Comprehensive inline comments
- Framework-agnostic design (Python/Node/Go/Rust examples)
- Adaptation guides for different project structures
- AI assistant prompts for Claude, Copilot, ChatGPT
### Use Cases
- Multi-language monorepos
- Microservices architectures
- Data science projects
- Infrastructure projects
- Any project needing unified test orchestration
## Benefits
1. **Consistency**: Same test experience locally and in CI
2. **Discoverability**: New contributors know exactly how to run tests
3. **Maintainability**: Single pattern to learn and maintain
4. **Extensibility**: Easy to add new test suites
5. **CI-Friendly**: Optimized for GitHub Actions
6. **Reusability**: Templates can be copied to any repo
## Usage
Local development:
./test_all.sh # Run all suites
./test_all.sh --strict # Fail-fast mode
./test_all.sh --suite backend # Run specific suite
./test_all.sh --verbose # Detailed output
CI triggers automatically on:
- Push to main, claude/**, copilot/**, codex/** branches
- Pull requests to main
- Manual workflow dispatch
## Migration Notes
This implementation:
- Preserves existing test scripts (scripts/run_backend_tests.sh)
- Works alongside existing CI workflows
- Can be adopted gradually or all at once
- Requires no changes to existing test code
## Future Enhancements
Potential additions:
- Matrix testing across Python/Node versions
- Performance benchmarking suite
- Flaky test detection
- Test result caching
- Slack/Discord notifications
---
Pattern adapted for: BlackRoad Operating System monorepo
Designed for: Maximum reusability across projects
Target audience: Developers, DevOps engineers, AI assistants
330 lines
8.4 KiB
Bash
330 lines
8.4 KiB
Bash
#!/usr/bin/env bash
|
||
#
|
||
# test_all.sh - {{REPO_NAME}} Test Orchestrator
|
||
#
|
||
# {{PROJECT_DESCRIPTION}}
|
||
#
|
||
# This script runs all test suites across the repository in a coordinated fashion.
|
||
# Adapted from: BlackRoad Operating System Test Orchestrator Pattern
|
||
#
|
||
# Usage:
|
||
# ./test_all.sh # Best-effort mode (run all suites, report summary)
|
||
# ./test_all.sh --strict # Strict mode (fail on first error)
|
||
# ./test_all.sh --suite <name> # Run specific suite only
|
||
# ./test_all.sh --help # Show usage
|
||
#
|
||
# Available suites: {{LIST_YOUR_SUITES_HERE}}
|
||
# Example: backend, frontend, api, sdk, docs
|
||
#
|
||
|
||
set -uo pipefail
|
||
|
||
###############################################################################
|
||
# CONFIGURATION
|
||
###############################################################################
|
||
|
||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
cd "$ROOT"
|
||
|
||
STRICT_MODE=false
|
||
SPECIFIC_SUITE=""
|
||
VERBOSE=false
|
||
|
||
# Color codes for pretty output
|
||
if [[ -t 1 ]]; then
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
BOLD='\033[1m'
|
||
RESET='\033[0m'
|
||
else
|
||
RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' RESET=''
|
||
fi
|
||
|
||
# Results tracking
|
||
declare -A SUITE_RESULTS
|
||
declare -A SUITE_TIMES
|
||
SUITES_RAN=0
|
||
SUITES_PASSED=0
|
||
SUITES_FAILED=0
|
||
SUITES_SKIPPED=0
|
||
|
||
###############################################################################
|
||
# HELPERS
|
||
###############################################################################
|
||
|
||
have() {
|
||
command -v "$1" >/dev/null 2>&1
|
||
}
|
||
|
||
log_header() {
|
||
echo ""
|
||
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
|
||
echo -e "${BOLD}$1${RESET}"
|
||
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
|
||
}
|
||
|
||
log_suite() {
|
||
echo ""
|
||
echo -e "${BLUE}▶ $1${RESET}"
|
||
}
|
||
|
||
log_info() {
|
||
echo -e " ${CYAN}ℹ${RESET} $1"
|
||
}
|
||
|
||
log_success() {
|
||
echo -e " ${GREEN}✓${RESET} $1"
|
||
}
|
||
|
||
log_warning() {
|
||
echo -e " ${YELLOW}⚠${RESET} $1"
|
||
}
|
||
|
||
log_error() {
|
||
echo -e " ${RED}✗${RESET} $1"
|
||
}
|
||
|
||
log_skip() {
|
||
echo -e " ${YELLOW}⊘${RESET} $1"
|
||
}
|
||
|
||
record_result() {
|
||
local suite=$1
|
||
local result=$2 # PASS, FAIL, SKIP
|
||
local duration=$3
|
||
|
||
SUITE_RESULTS[$suite]=$result
|
||
SUITE_TIMES[$suite]=$duration
|
||
((SUITES_RAN++))
|
||
|
||
case $result in
|
||
PASS) ((SUITES_PASSED++)) ;;
|
||
FAIL) ((SUITES_FAILED++)) ;;
|
||
SKIP) ((SUITES_SKIPPED++)) ;;
|
||
esac
|
||
|
||
if [[ "$result" == "FAIL" && "$STRICT_MODE" == "true" ]]; then
|
||
log_error "Strict mode enabled - aborting on first failure"
|
||
print_summary
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
print_summary() {
|
||
echo ""
|
||
log_header "TEST SUMMARY"
|
||
echo ""
|
||
|
||
# Summary table
|
||
printf "${BOLD}%-25s %-10s %-15s${RESET}\n" "Suite" "Result" "Duration"
|
||
echo "─────────────────────────────────────────────────────────"
|
||
|
||
# TODO: Update this list with your actual suites
|
||
for suite in example-suite-1 example-suite-2 example-suite-3; do
|
||
if [[ -n "${SUITE_RESULTS[$suite]:-}" ]]; then
|
||
result="${SUITE_RESULTS[$suite]}"
|
||
duration="${SUITE_TIMES[$suite]}"
|
||
|
||
case $result in
|
||
PASS)
|
||
printf "${GREEN}%-25s %-10s %-15s${RESET}\n" "$suite" "✓ PASS" "$duration"
|
||
;;
|
||
FAIL)
|
||
printf "${RED}%-25s %-10s %-15s${RESET}\n" "$suite" "✗ FAIL" "$duration"
|
||
;;
|
||
SKIP)
|
||
printf "${YELLOW}%-25s %-10s %-15s${RESET}\n" "$suite" "⊘ SKIP" "$duration"
|
||
;;
|
||
esac
|
||
fi
|
||
done
|
||
|
||
echo "─────────────────────────────────────────────────────────"
|
||
echo ""
|
||
echo -e "${BOLD}Total:${RESET} $SUITES_RAN suites | ${GREEN}$SUITES_PASSED passed${RESET} | ${RED}$SUITES_FAILED failed${RESET} | ${YELLOW}$SUITES_SKIPPED skipped${RESET}"
|
||
echo ""
|
||
|
||
if [[ $SUITES_FAILED -gt 0 ]]; then
|
||
echo -e "${RED}${BOLD}❌ TESTS FAILED${RESET}"
|
||
return 1
|
||
else
|
||
echo -e "${GREEN}${BOLD}✅ ALL TESTS PASSED${RESET}"
|
||
return 0
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# TEST SUITE FUNCTIONS
|
||
# TODO: Customize these for your project!
|
||
###############################################################################
|
||
|
||
# EXAMPLE SUITE 1: Replace with your actual test suite
|
||
run_example_suite_1() {
|
||
log_suite "Example Suite 1 (Description)"
|
||
|
||
local start_time=$(date +%s)
|
||
|
||
# Check if suite exists
|
||
if [[ ! -d "$ROOT/path/to/suite1" ]]; then
|
||
log_skip "path/to/suite1 directory not found"
|
||
record_result "example-suite-1" "SKIP" "0s"
|
||
return 0
|
||
fi
|
||
|
||
cd "$ROOT/path/to/suite1"
|
||
|
||
# TODO: Add your test commands here
|
||
# Examples:
|
||
# - pytest -v
|
||
# - npm test
|
||
# - go test ./...
|
||
# - cargo test
|
||
|
||
log_info "Running tests..."
|
||
# YOUR_TEST_COMMAND_HERE
|
||
|
||
local exit_code=$?
|
||
local end_time=$(date +%s)
|
||
local duration=$((end_time - start_time))
|
||
|
||
if [[ $exit_code -eq 0 ]]; then
|
||
log_success "Example Suite 1 tests passed"
|
||
record_result "example-suite-1" "PASS" "${duration}s"
|
||
else
|
||
log_error "Example Suite 1 tests failed"
|
||
record_result "example-suite-1" "FAIL" "${duration}s"
|
||
return 1
|
||
fi
|
||
|
||
cd "$ROOT"
|
||
}
|
||
|
||
# EXAMPLE SUITE 2: Add more suites as needed
|
||
run_example_suite_2() {
|
||
log_suite "Example Suite 2 (Description)"
|
||
|
||
local start_time=$(date +%s)
|
||
|
||
if [[ ! -d "$ROOT/path/to/suite2" ]]; then
|
||
log_skip "path/to/suite2 directory not found"
|
||
record_result "example-suite-2" "SKIP" "0s"
|
||
return 0
|
||
fi
|
||
|
||
# TODO: Implement your test logic
|
||
|
||
cd "$ROOT"
|
||
}
|
||
|
||
# Add more suite functions as needed...
|
||
|
||
###############################################################################
|
||
# COMMAND-LINE PARSING
|
||
###############################################################################
|
||
|
||
show_help() {
|
||
cat << EOF
|
||
${BOLD}{{REPO_NAME}} - Test Orchestrator${RESET}
|
||
|
||
${BOLD}USAGE:${RESET}
|
||
./test_all.sh [OPTIONS]
|
||
|
||
${BOLD}OPTIONS:${RESET}
|
||
--strict Fail on first test suite failure (default: best-effort)
|
||
--suite <name> Run specific test suite only
|
||
--verbose, -v Show verbose test output
|
||
--help, -h Show this help message
|
||
|
||
${BOLD}AVAILABLE SUITES:${RESET}
|
||
example-suite-1 Description of suite 1
|
||
example-suite-2 Description of suite 2
|
||
# TODO: Update this list with your actual suites
|
||
|
||
${BOLD}EXAMPLES:${RESET}
|
||
./test_all.sh # Run all suites, best-effort mode
|
||
./test_all.sh --strict # Run all suites, fail-fast mode
|
||
./test_all.sh --suite example-suite-1 # Run only suite 1
|
||
./test_all.sh --suite example-suite-1 --verbose # Verbose output
|
||
|
||
${BOLD}EXIT CODES:${RESET}
|
||
0 All tests passed
|
||
1 One or more test suites failed
|
||
|
||
EOF
|
||
}
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case $1 in
|
||
--strict)
|
||
STRICT_MODE=true
|
||
shift
|
||
;;
|
||
--suite)
|
||
SPECIFIC_SUITE="$2"
|
||
shift 2
|
||
;;
|
||
--verbose|-v)
|
||
VERBOSE=true
|
||
shift
|
||
;;
|
||
--help|-h)
|
||
show_help
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo -e "${RED}Unknown option: $1${RESET}"
|
||
echo "Use --help for usage information"
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
###############################################################################
|
||
# MAIN EXECUTION
|
||
###############################################################################
|
||
|
||
log_header "{{REPO_NAME}} - Test Orchestrator"
|
||
|
||
if [[ "$STRICT_MODE" == "true" ]]; then
|
||
log_info "Mode: ${RED}${BOLD}STRICT${RESET} (fail-fast)"
|
||
else
|
||
log_info "Mode: ${GREEN}${BOLD}BEST-EFFORT${RESET} (run all suites)"
|
||
fi
|
||
|
||
if [[ -n "$SPECIFIC_SUITE" ]]; then
|
||
log_info "Running suite: ${BOLD}$SPECIFIC_SUITE${RESET}"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# TODO: Update this section with your actual suite functions
|
||
if [[ -z "$SPECIFIC_SUITE" ]]; then
|
||
# Run all suites
|
||
run_example_suite_1 || true
|
||
run_example_suite_2 || true
|
||
# Add more suite calls here...
|
||
else
|
||
# Run specific suite
|
||
case $SPECIFIC_SUITE in
|
||
example-suite-1)
|
||
run_example_suite_1
|
||
;;
|
||
example-suite-2)
|
||
run_example_suite_2
|
||
;;
|
||
# Add more cases here...
|
||
*)
|
||
log_error "Unknown suite: $SPECIFIC_SUITE"
|
||
echo "Use --help to see available suites"
|
||
exit 1
|
||
;;
|
||
esac
|
||
fi
|
||
|
||
# Print summary and exit with appropriate code
|
||
print_summary
|
||
exit $?
|