Test Tutorial Agents #45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test Tutorial Agents | |
| on: | |
| workflow_dispatch: | |
| jobs: | |
| test-tutorials: | |
| timeout-minutes: 15 | |
| name: test-tutorials | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout agentex-python repo | |
| uses: actions/checkout@v4 | |
| - name: Install UV | |
| run: | | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| echo "$HOME/.local/bin" >> $GITHUB_PATH | |
| - name: Checkout scale-agentex repo | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: scaleapi/scale-agentex | |
| path: scale-agentex | |
| - name: Configure Docker Compose for host networking | |
| run: | | |
| cd scale-agentex/agentex | |
| echo "🔧 Configuring AgentEx container for GitHub Actions networking..." | |
| # Install yq for YAML manipulation | |
| sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 | |
| sudo chmod +x /usr/local/bin/yq | |
| # Add extra_hosts to agentex service to make host.docker.internal work | |
| # This allows the AgentEx container to reach the GitHub runner host | |
| yq eval '.services.agentex.extra_hosts = ["host.docker.internal:host-gateway"]' -i docker-compose.yml | |
| echo "✅ Added extra_hosts configuration to agentex service" | |
| - name: Navigate to scale-agentex repo | |
| run: | | |
| cd scale-agentex/agentex | |
| echo "🚀 Starting dependencies (Postgres, Redis, Temporal, MongoDB)..." | |
| # Start all services | |
| docker compose up -d | |
| echo "⏳ Waiting for dependencies to be healthy..." | |
| # Wait for services to be healthy | |
| for i in {1..30}; do | |
| if docker compose ps | grep -q "healthy"; then | |
| echo "✅ Dependencies are healthy" | |
| break | |
| fi | |
| echo " Attempt $i/30: Waiting for services..." | |
| sleep 5 | |
| done | |
| # Wait specifically for AgentEx server to be ready | |
| echo "⏳ Waiting for AgentEx server to be ready..." | |
| for i in {1..30}; do | |
| if curl -s --max-time 5 http://localhost:5003/health >/dev/null 2>&1; then | |
| echo "✅ AgentEx server is ready" | |
| break | |
| fi | |
| echo " Attempt $i/30: Waiting for AgentEx server..." | |
| sleep 5 | |
| done | |
| - name: Build AgentEx SDK | |
| run: | | |
| echo "🔨 Building AgentEx SDK wheel..." | |
| uv build | |
| echo "✅ SDK built successfully" | |
| ls -la dist/ | |
| - name: Run Parallel Tutorial Tests | |
| working-directory: ./examples/tutorials | |
| env: | |
| OPENAI_API_KEY: ${{ secrets.TUTORIAL_OPENAI_API_KEY }} | |
| run: | | |
| # Verify uv is working | |
| echo "UV version: $(uv --version)" | |
| echo "UV path: $(which uv)" | |
| # Start background job to poll AgentEx container logs and write to file | |
| ( | |
| echo "AgentEx container log polling started at $(date)" > /tmp/agentex_container_logs.txt | |
| # Function to get container logs | |
| get_logs() { | |
| echo "=== AgentEx Container Logs $(date) ===" >> /tmp/agentex_container_logs.txt | |
| docker logs agentex --tail=20 2>/dev/null >> /tmp/agentex_container_logs.txt || { | |
| echo "⚠️ Failed to get logs from 'agentex' container" >> /tmp/agentex_container_logs.txt | |
| echo "Available containers:" >> /tmp/agentex_container_logs.txt | |
| docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" >> /tmp/agentex_container_logs.txt | |
| } 2>/dev/null | |
| echo "=== End Logs ===" >> /tmp/agentex_container_logs.txt | |
| echo "" >> /tmp/agentex_container_logs.txt | |
| } | |
| # Poll logs every 10 seconds during test execution | |
| while true; do | |
| get_logs | |
| sleep 10 | |
| done | |
| ) & | |
| LOG_POLLER_PID=$! | |
| echo "📋 AgentEx log polling started in background (PID: $LOG_POLLER_PID)" | |
| # Find all tutorial directories | |
| tutorial_paths=() | |
| for dir in $(find . -name "manifest.yaml" -exec dirname {} \; | sort); do | |
| tutorial_paths+=("${dir#./}") # Remove leading ./ | |
| done | |
| echo "Found ${#tutorial_paths[@]} tutorials:" | |
| printf ' %s\n' "${tutorial_paths[@]}" | |
| # Run tests in parallel with unique ports | |
| pids=() | |
| failed_tests=() | |
| passed_tests=() | |
| # Run all tutorial tests | |
| for i in "${!tutorial_paths[@]}"; do | |
| tutorial="${tutorial_paths[$i]}" | |
| port=$((8000 + i)) | |
| echo "" | |
| echo "=========================================" | |
| echo "Starting test $((i+1))/${#tutorial_paths[@]}: $tutorial (port $port)" | |
| echo "=========================================" | |
| # Modify manifest.yaml to use unique port | |
| manifest_path="$tutorial/manifest.yaml" | |
| if [ -f "$manifest_path" ]; then | |
| # Backup original manifest | |
| cp "$manifest_path" "$manifest_path.backup" | |
| # Update port in manifest (modify the line containing 'port: 8000' or 'port: XXXX') | |
| sed -i "s/port: [0-9]*/port: $port/" "$manifest_path" | |
| # Keep host_address as host.docker.internal for CI (allows Docker container to reach GitHub runner host) | |
| # Note: The AgentEx server runs in Docker and needs host.docker.internal to reach the tutorial agent on the host | |
| fi | |
| # Run test in background with unique port and show output in real-time | |
| ( | |
| test_output_file="/tmp/test_output_$i.log" | |
| echo "Running test: $tutorial" | tee "$test_output_file" | |
| echo "Port: $port" | tee -a "$test_output_file" | |
| echo "========================================" | tee -a "$test_output_file" | |
| AGENTEX_API_BASE_URL="http://localhost:5003" \ | |
| ./run_agent_test.sh --build-cli "$tutorial" 2>&1 | tee -a "$test_output_file" | |
| exit_code=${PIPESTATUS[0]} | |
| if [ $exit_code -eq 0 ]; then | |
| echo "✅ PASSED: $tutorial (port $port)" | |
| echo "$tutorial" > "/tmp/passed_$i.txt" | |
| echo "$test_output_file" > "/tmp/passed_output_$i.txt" | |
| else | |
| echo "❌ FAILED: $tutorial (port $port)" | |
| echo "$tutorial" > "/tmp/failed_$i.txt" | |
| echo "$test_output_file" > "/tmp/failed_output_$i.txt" | |
| fi | |
| exit $exit_code | |
| ) & | |
| pids+=($!) | |
| done | |
| # Wait for all tests to complete | |
| echo "" | |
| echo "Waiting for all tests to complete..." | |
| for pid in "${pids[@]}"; do | |
| wait "$pid" | |
| done | |
| # Restore all original manifests | |
| echo "" | |
| echo "Restoring original manifest files..." | |
| for tutorial in "${tutorial_paths[@]}"; do | |
| if [ -f "$tutorial/manifest.yaml.backup" ]; then | |
| mv "$tutorial/manifest.yaml.backup" "$tutorial/manifest.yaml" | |
| echo "Restored $tutorial/manifest.yaml" | |
| fi | |
| done | |
| # Collect results | |
| for i in "${!tutorial_paths[@]}"; do | |
| if [ -f "/tmp/passed_$i.txt" ]; then | |
| passed_tests+=($(cat "/tmp/passed_$i.txt")) | |
| elif [ -f "/tmp/failed_$i.txt" ]; then | |
| failed_tests+=($(cat "/tmp/failed_$i.txt")) | |
| fi | |
| done | |
| # Stop the background log poller | |
| echo "🛑 Stopping AgentEx log poller (PID: $LOG_POLLER_PID)" | |
| kill $LOG_POLLER_PID 2>/dev/null || echo "Log poller already stopped" | |
| # Print summary | |
| echo "" | |
| echo "=========================================" | |
| echo "TEST SUMMARY" | |
| echo "=========================================" | |
| echo "Total: ${#tutorial_paths[@]}" | |
| echo "Passed: ${#passed_tests[@]}" | |
| echo "Failed: ${#failed_tests[@]}" | |
| if [ ${#failed_tests[@]} -gt 0 ]; then | |
| echo "" | |
| echo "Failed tests:" | |
| for test in "${failed_tests[@]}"; do | |
| echo " ❌ $test" | |
| done | |
| else | |
| echo "" | |
| echo "🎉 All tests passed!" | |
| fi | |
| # Show pytest results for all tests | |
| echo "" | |
| echo "=========================================" | |
| echo "PYTEST RESULTS" | |
| echo "=========================================" | |
| # Show passed test results | |
| if [ ${#passed_tests[@]} -gt 0 ]; then | |
| echo "" | |
| echo "✅ PASSED TESTS:" | |
| for i in "${!tutorial_paths[@]}"; do | |
| if [ -f "/tmp/passed_$i.txt" ]; then | |
| test_name=$(cat "/tmp/passed_$i.txt") | |
| output_file=$(cat "/tmp/passed_output_$i.txt") | |
| echo "" | |
| echo "📋 $test_name:" | |
| echo "----------------------------------------" | |
| if [ -f "$output_file" ]; then | |
| # Show just the pytest summary line for passed tests | |
| grep -E "(PASSED|FAILED|ERROR|::.*ok)" "$output_file" | tail -10 || echo "No pytest output found" | |
| else | |
| echo "No output file found" | |
| fi | |
| echo "----------------------------------------" | |
| fi | |
| done | |
| fi | |
| # Show failed test results | |
| if [ ${#failed_tests[@]} -gt 0 ]; then | |
| echo "" | |
| echo "❌ FAILED TESTS:" | |
| for i in "${!tutorial_paths[@]}"; do | |
| if [ -f "/tmp/failed_$i.txt" ]; then | |
| test_name=$(cat "/tmp/failed_$i.txt") | |
| output_file=$(cat "/tmp/failed_output_$i.txt") | |
| echo "" | |
| echo "📋 $test_name:" | |
| echo "----------------------------------------" | |
| if [ -f "$output_file" ]; then | |
| # Show full pytest output for failed tests | |
| tail -50 "$output_file" | |
| else | |
| echo "No output file found" | |
| fi | |
| echo "----------------------------------------" | |
| fi | |
| done | |
| fi | |
| if [ ${#failed_tests[@]} -gt 0 ]; then | |
| exit 1 | |
| fi | |
| - name: Debug Logs for Failed Tests | |
| if: always() | |
| run: | | |
| cd scale-agentex/agentex | |
| echo "" | |
| echo "================================================================================" | |
| echo "🐛 DEBUG LOGS (for troubleshooting)" | |
| echo "================================================================================" | |
| # Show collected AgentEx server container logs | |
| echo "" | |
| echo "=========================================" | |
| echo "AGENTEX SERVER LOGS (COLLECTED DURING TESTS)" | |
| echo "=========================================" | |
| if [ -f "/tmp/agentex_container_logs.txt" ]; then | |
| echo "📋 AgentEx server logs collected during test execution:" | |
| echo "----------------------------------------" | |
| cat /tmp/agentex_container_logs.txt | |
| echo "----------------------------------------" | |
| else | |
| echo "⚠️ No AgentEx container logs file found" | |
| echo "📋 Attempting to get current container logs:" | |
| echo "----------------------------------------" | |
| docker logs agentex --tail=50 2>/dev/null || { | |
| echo "❌ Failed to get logs from 'agentex' container" | |
| echo "Available containers:" | |
| docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | |
| } | |
| echo "----------------------------------------" | |
| fi | |
| # Show tutorial agent logs for failed tests | |
| cd ../../examples/tutorials | |
| # Check if there were any failed tests | |
| failed_tests=() | |
| for i in {0..20}; do # Check up to 20 possible tests | |
| if [ -f "/tmp/failed_$i.txt" ]; then | |
| failed_tests+=($(cat "/tmp/failed_$i.txt")) | |
| fi | |
| done | |
| if [ ${#failed_tests[@]} -gt 0 ]; then | |
| echo "" | |
| echo "=========================================" | |
| echo "TUTORIAL AGENT LOGS FOR FAILED TESTS" | |
| echo "=========================================" | |
| for test in "${failed_tests[@]}"; do | |
| test_name=$(basename "$test") | |
| logfile="/tmp/agentex-${test_name}.log" | |
| echo "" | |
| echo "📋 Tutorial agent logs for $test:" | |
| echo "----------------------------------------" | |
| if [ -f "$logfile" ]; then | |
| echo "Tutorial agent logs (last 100 lines):" | |
| tail -100 "$logfile" | |
| else | |
| echo "⚠️ No agent log file found at: $logfile" | |
| echo "Available agent log files:" | |
| ls -la /tmp/agentex-*.log 2>/dev/null || echo " (none)" | |
| fi | |
| echo "----------------------------------------" | |
| done | |
| else | |
| echo "" | |
| echo "✅ No failed tests - no agent logs to show" | |
| fi |