Files
blackroad-operating-system/.templates/test-orchestrator/test_all.sh.template
Claude c50abba250 Add comprehensive Test Orchestrator pattern for monorepo testing
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
2025-11-18 07:42:01 +00:00

330 lines
8.4 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 $?