Merge pull request #53 from EUCPilots/fix-r2 #21
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: API Tests | |
| on: | |
| # Run tests on pull requests to any branch | |
| pull_request: | |
| branches: ["*"] | |
| paths: | |
| - 'src/**' | |
| - 'tests/**' | |
| # Run tests on pushes to main and development branches | |
| push: | |
| branches: [main, dev, development, staging, cache] | |
| paths: | |
| - 'src/**' | |
| - 'tests/**' | |
| # Allow manual workflow runs | |
| workflow_dispatch: | |
| jobs: | |
| test: | |
| name: Run API Tests | |
| runs-on: ubuntu-latest | |
| strategy: | |
| matrix: | |
| node-version: [18.x, 20.x] | |
| fail-fast: false | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js ${{ matrix.node-version }} | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ matrix.node-version }} | |
| cache: 'npm' | |
| cache-dependency-path: tests/package.json | |
| - name: Install test dependencies | |
| run: | | |
| cd tests | |
| npm ci | |
| - name: Run API tests against production | |
| run: | | |
| cd tests | |
| npm test | |
| env: | |
| NODE_ENV: test | |
| - name: Generate test report | |
| if: always() | |
| run: | | |
| cd tests | |
| npx mocha test.js --timeout 30000 --reporter json > test-results.json || true | |
| npx mocha test.js --timeout 30000 --reporter tap > test-results.tap || true | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-node-${{ matrix.node-version }} | |
| path: | | |
| tests/test-results.json | |
| tests/test-results.tap | |
| lint: | |
| name: Lint Code | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20.x' | |
| - name: Check JavaScript syntax | |
| run: | | |
| # Basic syntax check for main source file | |
| node -c src/index.js | |
| - name: Check JSON files | |
| run: | | |
| # Validate JSON files | |
| if [ -f src/package.json ]; then | |
| echo "Validating src/package.json..." | |
| python3 -m json.tool src/package.json > /dev/null | |
| fi | |
| if [ -f tests/package.json ]; then | |
| echo "Validating tests/package.json..." | |
| python3 -m json.tool tests/package.json > /dev/null | |
| fi | |
| - name: Check TOML files | |
| run: | | |
| # Install a more reliable TOML validator | |
| npm install -g toml-test-runner || npm install -g @taplo/cli || true | |
| # Validate wrangler.toml with alternative methods | |
| if [ -f src/wrangler.toml ]; then | |
| echo "Validating src/wrangler.toml..." | |
| # Method 1: Try with Node.js TOML parser | |
| if command -v node >/dev/null 2>&1; then | |
| node -e " | |
| try { | |
| const fs = require('fs'); | |
| const content = fs.readFileSync('src/wrangler.toml', 'utf8'); | |
| // Basic TOML syntax check - look for common issues | |
| const lines = content.split('\n'); | |
| let inString = false; | |
| let stringChar = ''; | |
| for (let i = 0; i < lines.length; i++) { | |
| const line = lines[i].trim(); | |
| if (line.startsWith('#') || line === '') continue; | |
| // Check for unmatched quotes | |
| for (let j = 0; j < line.length; j++) { | |
| const char = line[j]; | |
| if ((char === '\"' || char === \"'\") && (j === 0 || line[j-1] !== '\\\\')) { | |
| if (!inString) { | |
| inString = true; | |
| stringChar = char; | |
| } else if (char === stringChar) { | |
| inString = false; | |
| stringChar = ''; | |
| } | |
| } | |
| } | |
| // Check for basic TOML structure | |
| if (line.includes('=') && !inString) { | |
| const parts = line.split('='); | |
| if (parts.length < 2) { | |
| throw new Error('Invalid assignment on line ' + (i + 1)); | |
| } | |
| } | |
| } | |
| // Check required fields | |
| if (!content.includes('name')) { | |
| console.warn('Warning: No name field found in src/wrangler.toml'); | |
| } | |
| if (!content.includes('main')) { | |
| console.warn('Warning: No main field found in src/wrangler.toml'); | |
| } | |
| console.log('✅ src/wrangler.toml: Basic validation passed'); | |
| } catch (error) { | |
| console.error('❌ src/wrangler.toml: Validation failed -', error.message); | |
| process.exit(1); | |
| } | |
| " | |
| else | |
| echo "⚠️ Node.js not available for TOML validation" | |
| fi | |
| # Method 2: Basic text validation | |
| echo "Running basic TOML structure checks..." | |
| # Check for required Cloudflare Workers fields | |
| if grep -q "^name\s*=" src/wrangler.toml; then | |
| echo " ✅ 'name' field found" | |
| else | |
| echo " ❌ 'name' field missing" | |
| exit 1 | |
| fi | |
| if grep -q "^main\s*=" src/wrangler.toml; then | |
| echo " ✅ 'main' field found" | |
| else | |
| echo " ❌ 'main' field missing" | |
| exit 1 | |
| fi | |
| # Check for KV namespace binding | |
| if grep -q "kv_namespaces" src/wrangler.toml; then | |
| echo " ✅ KV namespaces configured" | |
| else | |
| echo " ⚠️ No KV namespaces found" | |
| fi | |
| # Check for R2 bucket binding | |
| if grep -q "r2_buckets" src/wrangler.toml; then | |
| echo " ✅ R2 buckets configured" | |
| else | |
| echo " ⚠️ No R2 buckets found" | |
| fi | |
| echo "✅ src/wrangler.toml validation completed" | |
| else | |
| echo "ℹ️ No src/wrangler.toml file found" | |
| fi | |
| security: | |
| name: Security Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20.x' | |
| - name: Install test dependencies | |
| run: | | |
| cd tests | |
| npm ci | |
| - name: Run security audit | |
| run: | | |
| cd tests | |
| npm audit --audit-level=high | |
| - name: Check for secrets | |
| run: | | |
| # Basic check for potential secrets in code | |
| echo "Checking for potential secrets..." | |
| # Check for hardcoded API keys, tokens, etc. | |
| if grep -r -i -E "(api[_-]?key|secret|token|password)\s*[:=]\s*['\"][^'\"]{8,}" src/ tests/ --exclude-dir=node_modules || true; then | |
| echo "⚠️ Potential secrets found in code. Please review." | |
| else | |
| echo "✅ No obvious secrets detected." | |
| fi | |
| validate-api: | |
| name: Validate API Schema | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20.x' | |
| - name: Install schema validation tools | |
| run: | | |
| npm install -g @apidevtools/swagger-cli | |
| - name: Validate OpenAPI schema | |
| run: | | |
| if [ -f schema/openapi.yml ]; then | |
| echo "Validating OpenAPI schema..." | |
| swagger-cli validate schema/openapi.yml | |
| echo "✅ OpenAPI schema is valid" | |
| else | |
| echo "ℹ️ No OpenAPI schema found at schema/openapi.yml" | |
| fi | |
| performance: | |
| name: Performance Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20.x' | |
| - name: Install dependencies | |
| run: | | |
| cd tests | |
| npm ci | |
| - name: Run performance tests | |
| run: | | |
| cd tests | |
| echo "Running performance validation..." | |
| # Run tests with timing | |
| time npx mocha test.js --timeout 30000 --grep "Caching Performance" | |
| # Basic load test with curl | |
| echo "Testing API response times..." | |
| for i in {1..5}; do | |
| echo "Request $i:" | |
| curl -w "Time: %{time_total}s, Status: %{http_code}\n" -o /dev/null -s \ | |
| -H "User-Agent: GitHub-Actions-Performance-Test/1.0.0" \ | |
| "https://evergreen-api.stealthpuppy.com/health" | |
| done | |
| comment-pr: | |
| name: Comment Test Results | |
| runs-on: ubuntu-latest | |
| needs: [test, lint, security, validate-api] | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Download test artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| pattern: test-results-* | |
| merge-multiple: true | |
| - name: Comment PR with results | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| try { | |
| // Read test results | |
| let testSummary = "## 🧪 Test Results\n\n"; | |
| // Check if test results exist | |
| if (fs.existsSync('test-results.json')) { | |
| const results = JSON.parse(fs.readFileSync('test-results.json', 'utf8')); | |
| const passing = results.stats.passes || 0; | |
| const failing = results.stats.failures || 0; | |
| const total = results.stats.tests || 0; | |
| if (failing === 0) { | |
| testSummary += `✅ **All ${total} tests passed!**\n\n`; | |
| } else { | |
| testSummary += `❌ **${failing} out of ${total} tests failed**\n\n`; | |
| } | |
| testSummary += `- ✅ Passing: ${passing}\n`; | |
| testSummary += `- ❌ Failing: ${failing}\n`; | |
| testSummary += `- 📊 Total: ${total}\n\n`; | |
| } else { | |
| testSummary += "📋 Test results not available\n\n"; | |
| } | |
| testSummary += "### 🔍 Validation Status\n"; | |
| testSummary += "- ✅ Code linting\n"; | |
| testSummary += "- ✅ Security scan\n"; | |
| testSummary += "- ✅ API schema validation\n"; | |
| testSummary += "- ✅ Performance tests\n\n"; | |
| testSummary += "### 📝 Notes\n"; | |
| testSummary += "- Tests run against production API\n"; | |
| testSummary += "- Validates both current and new caching implementations\n"; | |
| testSummary += "- Ensures API compatibility and performance\n"; | |
| // Post comment | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: testSummary | |
| }); | |
| } catch (error) { | |
| console.log('Error posting comment:', error); | |
| } | |
| notify-slack: | |
| name: Notify Team | |
| runs-on: ubuntu-latest | |
| needs: [test, lint, security, validate-api] | |
| if: failure() && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/cache') | |
| steps: | |
| - name: Notify on failure | |
| run: | | |
| echo "🚨 Tests failed on ${{ github.ref_name }} branch" | |
| echo "Consider setting up Slack notifications for critical failures" | |
| # You can add Slack webhook integration here if needed |