validate-test-suites.sh 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #!/bin/bash
  2. # validate-test-suites.sh
  3. # Validates all test suite JSON files against schema and checks paths exist
  4. #
  5. # Usage:
  6. # ./scripts/validation/validate-test-suites.sh [agent]
  7. # ./scripts/validation/validate-test-suites.sh openagent
  8. # ./scripts/validation/validate-test-suites.sh --all
  9. #
  10. # Exit codes:
  11. # 0 - All suites valid
  12. # 1 - Validation errors found
  13. # 2 - Missing dependencies
  14. set -e
  15. # Colors
  16. RED='\033[0;31m'
  17. GREEN='\033[0;32m'
  18. YELLOW='\033[1;33m'
  19. BLUE='\033[0;34m'
  20. NC='\033[0m' # No Color
  21. # Get script directory
  22. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  23. PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
  24. # Check for ajv-cli (JSON schema validator)
  25. # Use npx to run from local node_modules
  26. if ! command -v npx &> /dev/null; then
  27. echo -e "${RED}❌ Error: npx not found (Node.js required)${NC}"
  28. exit 2
  29. fi
  30. # Check if ajv-cli is installed
  31. if ! (cd "$PROJECT_ROOT/evals/framework" && npx ajv validate -s /dev/null -d /dev/null 2>&1 | grep -q "valid"); then
  32. echo -e "${RED}❌ Error: ajv-cli not found${NC}"
  33. echo ""
  34. echo "Install with: cd evals/framework && npm install"
  35. echo "Or globally: npm install -g ajv-cli"
  36. exit 2
  37. fi
  38. AJV_CMD="cd $PROJECT_ROOT/evals/framework && npx ajv"
  39. # Parse arguments
  40. AGENT="${1:-openagent}"
  41. VALIDATE_ALL=false
  42. if [[ "$1" == "--all" ]]; then
  43. VALIDATE_ALL=true
  44. fi
  45. # Counters
  46. TOTAL_SUITES=0
  47. VALID_SUITES=0
  48. INVALID_SUITES=0
  49. TOTAL_ERRORS=0
  50. TOTAL_WARNINGS=0
  51. echo -e "${BLUE}🔍 Validating Test Suites${NC}"
  52. echo ""
  53. # Function to validate a single suite
  54. validate_suite() {
  55. local agent=$1
  56. local suite_file=$2
  57. local suite_name=$(basename "$suite_file" .json)
  58. TOTAL_SUITES=$((TOTAL_SUITES + 1))
  59. echo -e "${BLUE}Validating:${NC} $agent/$suite_name"
  60. local schema_file="$PROJECT_ROOT/evals/agents/$agent/config/suite-schema.json"
  61. local tests_dir="$PROJECT_ROOT/evals/agents/$agent/tests"
  62. local suite_valid=true
  63. local suite_errors=0
  64. local suite_warnings=0
  65. # 1. Validate JSON syntax
  66. if ! jq empty "$suite_file" 2>/dev/null; then
  67. echo -e " ${RED}❌ Invalid JSON syntax${NC}"
  68. suite_valid=false
  69. suite_errors=$((suite_errors + 1))
  70. INVALID_SUITES=$((INVALID_SUITES + 1))
  71. TOTAL_ERRORS=$((TOTAL_ERRORS + 1))
  72. return
  73. fi
  74. # 2. Validate against schema
  75. if [[ -f "$schema_file" ]]; then
  76. validation_output=$(eval "$AJV_CMD validate -s \"$schema_file\" -d \"$suite_file\" --strict=false 2>&1")
  77. if ! echo "$validation_output" | grep -q "valid"; then
  78. echo -e " ${RED}❌ Schema validation failed${NC}"
  79. echo "$validation_output" | grep -v "valid" | sed 's/^/ /'
  80. suite_valid=false
  81. suite_errors=$((suite_errors + 1))
  82. fi
  83. else
  84. echo -e " ${YELLOW}⚠️ Schema not found: $schema_file${NC}"
  85. suite_warnings=$((suite_warnings + 1))
  86. fi
  87. # 3. Validate test paths exist
  88. local missing_tests=()
  89. local test_count=0
  90. while IFS= read -r test_path; do
  91. test_count=$((test_count + 1))
  92. local full_path="$tests_dir/$test_path"
  93. if [[ ! -f "$full_path" ]]; then
  94. missing_tests+=("$test_path")
  95. fi
  96. done < <(jq -r '.tests[].path' "$suite_file")
  97. # 4. Check test count matches
  98. local declared_count=$(jq -r '.totalTests' "$suite_file")
  99. if [[ "$test_count" -ne "$declared_count" ]]; then
  100. echo -e " ${YELLOW}⚠️ Test count mismatch: found $test_count, declared $declared_count${NC}"
  101. suite_warnings=$((suite_warnings + 1))
  102. fi
  103. # 5. Report missing tests
  104. if [[ ${#missing_tests[@]} -gt 0 ]]; then
  105. echo -e " ${RED}❌ Missing test files (${#missing_tests[@]}):${NC}"
  106. for missing in "${missing_tests[@]}"; do
  107. echo -e " - $missing"
  108. # Suggest similar files
  109. local dir=$(dirname "$missing")
  110. local filename=$(basename "$missing")
  111. if [[ -d "$tests_dir/$dir" ]]; then
  112. local similar=$(find "$tests_dir/$dir" -name "*.yaml" -type f -exec basename {} \; | grep -i "$(echo $filename | cut -d'-' -f1)" | head -3)
  113. if [[ -n "$similar" ]]; then
  114. echo -e " ${YELLOW}Did you mean?${NC}"
  115. echo "$similar" | sed 's/^/ - /'
  116. fi
  117. fi
  118. done
  119. suite_valid=false
  120. suite_errors=$((suite_errors + ${#missing_tests[@]}))
  121. fi
  122. # 6. Summary for this suite
  123. if [[ "$suite_valid" == true ]]; then
  124. echo -e " ${GREEN}✅ Valid${NC} ($test_count tests)"
  125. VALID_SUITES=$((VALID_SUITES + 1))
  126. else
  127. echo -e " ${RED}❌ Invalid${NC} ($suite_errors errors, $suite_warnings warnings)"
  128. INVALID_SUITES=$((INVALID_SUITES + 1))
  129. fi
  130. TOTAL_ERRORS=$((TOTAL_ERRORS + suite_errors))
  131. TOTAL_WARNINGS=$((TOTAL_WARNINGS + suite_warnings))
  132. echo ""
  133. }
  134. # Validate suites
  135. if [[ "$VALIDATE_ALL" == true ]]; then
  136. # Validate all agents
  137. for agent_dir in "$PROJECT_ROOT/evals/agents"/*; do
  138. if [[ -d "$agent_dir" ]]; then
  139. agent=$(basename "$agent_dir")
  140. # Check for suites directory
  141. suites_dir="$agent_dir/config/suites"
  142. if [[ -d "$suites_dir" ]]; then
  143. for suite_file in "$suites_dir"/*.json; do
  144. if [[ -f "$suite_file" ]]; then
  145. validate_suite "$agent" "$suite_file"
  146. fi
  147. done
  148. fi
  149. # Check for legacy core-tests.json
  150. legacy_file="$agent_dir/config/core-tests.json"
  151. if [[ -f "$legacy_file" ]]; then
  152. validate_suite "$agent" "$legacy_file"
  153. fi
  154. fi
  155. done
  156. else
  157. # Validate specific agent
  158. agent_dir="$PROJECT_ROOT/evals/agents/$AGENT"
  159. if [[ ! -d "$agent_dir" ]]; then
  160. echo -e "${RED}❌ Agent not found: $AGENT${NC}"
  161. exit 1
  162. fi
  163. # Check for suites directory
  164. suites_dir="$agent_dir/config/suites"
  165. if [[ -d "$suites_dir" ]]; then
  166. for suite_file in "$suites_dir"/*.json; do
  167. if [[ -f "$suite_file" ]]; then
  168. validate_suite "$AGENT" "$suite_file"
  169. fi
  170. done
  171. fi
  172. # Check for legacy core-tests.json
  173. legacy_file="$agent_dir/config/core-tests.json"
  174. if [[ -f "$legacy_file" ]]; then
  175. validate_suite "$AGENT" "$legacy_file"
  176. fi
  177. if [[ $TOTAL_SUITES -eq 0 ]]; then
  178. echo -e "${YELLOW}⚠️ No test suites found for agent: $AGENT${NC}"
  179. echo ""
  180. echo "Expected locations:"
  181. echo " - $suites_dir/*.json"
  182. echo " - $legacy_file"
  183. exit 1
  184. fi
  185. fi
  186. # Final summary
  187. echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
  188. echo -e "${BLUE}Summary${NC}"
  189. echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"
  190. echo -e "Total suites: $TOTAL_SUITES"
  191. echo -e "${GREEN}Valid suites: $VALID_SUITES${NC}"
  192. if [[ $INVALID_SUITES -gt 0 ]]; then
  193. echo -e "${RED}Invalid suites: $INVALID_SUITES${NC}"
  194. fi
  195. if [[ $TOTAL_ERRORS -gt 0 ]]; then
  196. echo -e "${RED}Total errors: $TOTAL_ERRORS${NC}"
  197. fi
  198. if [[ $TOTAL_WARNINGS -gt 0 ]]; then
  199. echo -e "${YELLOW}Total warnings: $TOTAL_WARNINGS${NC}"
  200. fi
  201. echo ""
  202. # Exit with appropriate code
  203. if [[ $INVALID_SUITES -gt 0 ]] || [[ $TOTAL_ERRORS -gt 0 ]]; then
  204. echo -e "${RED}❌ Validation failed${NC}"
  205. exit 1
  206. else
  207. echo -e "${GREEN}✅ All suites valid${NC}"
  208. exit 0
  209. fi