test: D — live Base sepolia integration tests (gated, opt-in) #37
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: Python SDK Tests | |
| on: | |
| push: | |
| branches: [main, develop] | |
| paths: | |
| - 'src/**' | |
| - 'tests/**' | |
| - 'pyproject.toml' | |
| - '.github/workflows/test.yml' | |
| pull_request: | |
| branches: [main, develop] | |
| paths: | |
| - 'src/**' | |
| - 'tests/**' | |
| - 'pyproject.toml' | |
| - '.github/workflows/test.yml' | |
| workflow_dispatch: # Allow manual trigger | |
| env: | |
| PYTHON_VERSION: '3.11' | |
| COVERAGE_THRESHOLD: 85 | |
| jobs: | |
| # ============================================================================= | |
| # Fast Unit Tests (< 5 minutes) | |
| # ============================================================================= | |
| test-fast: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| strategy: | |
| matrix: | |
| python-version: ['3.9', '3.10', '3.11', '3.12'] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Run unit tests | |
| run: | | |
| pytest tests/ \ | |
| --ignore=tests/integration/ \ | |
| --ignore=tests/benchmarks/ \ | |
| -v \ | |
| --tb=short \ | |
| -x # Stop on first failure | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: test-results-${{ matrix.python-version }} | |
| path: | | |
| pytest.log | |
| .pytest_cache/ | |
| # ============================================================================= | |
| # Coverage Report | |
| # ============================================================================= | |
| test-coverage: | |
| name: Coverage Report | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| needs: test-fast | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| pip install pytest-cov | |
| - name: Run tests with coverage | |
| run: | | |
| pytest tests/ \ | |
| --ignore=tests/integration/ \ | |
| --ignore=tests/benchmarks/ \ | |
| --cov=src/agirails \ | |
| --cov-report=xml \ | |
| --cov-report=html \ | |
| --cov-report=term-missing \ | |
| --cov-fail-under=${{ env.COVERAGE_THRESHOLD }} | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: ./coverage.xml | |
| flags: unittests | |
| name: python-sdk-coverage | |
| fail_ci_if_error: false | |
| - name: Upload coverage HTML report | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: htmlcov/ | |
| # ============================================================================= | |
| # Security Tests | |
| # ============================================================================= | |
| test-security: | |
| name: Security Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: test-fast | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| pip install bandit pip-audit safety | |
| - name: Run security tests | |
| run: | | |
| pytest tests/test_security/ -v --tb=short | |
| - name: Run bandit security linter | |
| run: | | |
| bandit -r src/agirails -ll -ii --format json -o bandit-report.json || true | |
| bandit -r src/agirails -ll -ii | |
| - name: Run pip-audit for dependency vulnerabilities | |
| run: | | |
| pip-audit --format json --output pip-audit-report.json || true | |
| pip-audit | |
| - name: Upload security reports | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: security-reports | |
| path: | | |
| bandit-report.json | |
| pip-audit-report.json | |
| # ============================================================================= | |
| # Property-Based Tests (Hypothesis) | |
| # ============================================================================= | |
| test-properties: | |
| name: Property-Based Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| needs: test-fast | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Run property-based tests | |
| run: | | |
| pytest tests/test_properties/ \ | |
| -v \ | |
| --tb=short \ | |
| --hypothesis-show-statistics \ | |
| --hypothesis-seed=0 # Reproducible | |
| # ============================================================================= | |
| # Parity Tests (Python <-> TypeScript SDK) | |
| # ============================================================================= | |
| test-parity: | |
| name: SDK Parity Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| needs: test-fast | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Run parity tests | |
| run: | | |
| pytest tests/test_parity.py -v --tb=short | |
| - name: Run fixture-based parity tests | |
| run: | | |
| pytest tests/fixtures/ -v --tb=short || true | |
| # ============================================================================= | |
| # Integration Tests (Requires Anvil - Push only) | |
| # ============================================================================= | |
| test-integration: | |
| name: Integration Tests | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| if: github.event_name == 'push' | |
| needs: [test-fast, test-security] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install Foundry (Anvil) | |
| uses: foundry-rs/foundry-toolchain@v1 | |
| with: | |
| version: nightly | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| - name: Start Anvil in background | |
| run: | | |
| anvil --fork-url ${{ secrets.BASE_SEPOLIA_RPC_URL || 'https://sepolia.base.org' }} & | |
| sleep 5 # Wait for Anvil to start | |
| - name: Run integration tests | |
| env: | |
| ANVIL_RPC_URL: http://localhost:8545 | |
| run: | | |
| pytest tests/integration/ -v --tb=short || echo "Integration tests completed (some may be skipped)" | |
| - name: Stop Anvil | |
| if: always() | |
| run: pkill anvil || true | |
| # ============================================================================= | |
| # Benchmarks (Main only) | |
| # ============================================================================= | |
| test-benchmarks: | |
| name: Performance Benchmarks | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| needs: test-fast | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -e ".[dev]" | |
| pip install pytest-benchmark | |
| - name: Run benchmarks | |
| run: | | |
| pytest tests/benchmarks/ \ | |
| -v \ | |
| --benchmark-only \ | |
| --benchmark-json=benchmark-results.json \ | |
| --benchmark-min-rounds=10 \ | |
| --benchmark-warmup=on | |
| - name: Upload benchmark results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: benchmark-results | |
| path: benchmark-results.json | |
| - name: Store benchmark result | |
| uses: benchmark-action/github-action-benchmark@v1 | |
| if: github.event_name == 'push' | |
| with: | |
| tool: 'pytest' | |
| output-file-path: benchmark-results.json | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| auto-push: true | |
| alert-threshold: '150%' | |
| comment-on-alert: true | |
| fail-on-alert: false | |
| # ============================================================================= | |
| # Linting & Type Checking | |
| # ============================================================================= | |
| lint: | |
| name: Lint & Type Check | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| cache: 'pip' | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install ruff mypy | |
| pip install -e ".[dev]" | |
| - name: Run Ruff linter | |
| run: | | |
| ruff check src/agirails --output-format github | |
| - name: Run Ruff formatter check | |
| run: | | |
| ruff format --check src/agirails | |
| - name: Run mypy type checker | |
| run: | | |
| mypy src/agirails --ignore-missing-imports --no-error-summary || true | |
| # ============================================================================= | |
| # Summary Job | |
| # ============================================================================= | |
| test-summary: | |
| name: Test Summary | |
| runs-on: ubuntu-latest | |
| needs: [test-fast, test-coverage, test-security, test-properties, test-parity, lint] | |
| if: always() | |
| steps: | |
| - name: Check test results | |
| run: | | |
| echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Unit Tests | ${{ needs.test-fast.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Coverage | ${{ needs.test-coverage.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Security | ${{ needs.test-security.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Properties | ${{ needs.test-properties.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Parity | ${{ needs.test-parity.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Lint | ${{ needs.lint.result }} |" >> $GITHUB_STEP_SUMMARY | |
| - name: Fail if any required job failed | |
| if: | | |
| needs.test-fast.result == 'failure' || | |
| needs.test-coverage.result == 'failure' || | |
| needs.test-security.result == 'failure' || | |
| needs.lint.result == 'failure' | |
| run: exit 1 |