Add indices #804
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
| # TESTING STRATEGY: | |
| # 1. Run comprehensive tests following the same approach as local Docker setup | |
| # 2. Run tests by category with appropriate timeouts and NO fail-fast (show all failures) | |
| # 3. Use the same test configuration as local development environment | |
| # 4. Enable parallel test execution where possible | |
| # 5. Generate comprehensive coverage reports | |
| # 6. Continue running all tests even if some fail to show complete failure picture | |
| name: Run Tests | |
| on: | |
| pull_request: | |
| branches: [ master, develop, staging ] | |
| push: | |
| branches: [ master, develop, staging ] | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| services: | |
| postgres: | |
| image: postgis/postgis:13-3.4 | |
| env: | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_USER: postgres | |
| POSTGRES_DB: gefapi_test | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| redis: | |
| image: redis:6 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 6379:6379 | |
| strategy: | |
| matrix: | |
| python-version: ["3.11", "3.12", "3.13"] | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Cache Poetry dependencies | |
| uses: actions/cache@v3 | |
| with: | |
| path: | | |
| ~/.cache/pypoetry | |
| ~/.cache/pip | |
| key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-poetry- | |
| - name: Install Poetry | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install poetry | |
| - name: Install dependencies with Poetry | |
| run: | | |
| poetry config virtualenvs.create false | |
| poetry install --no-interaction --no-ansi --with dev | |
| - name: Set environment variables for testing | |
| run: | | |
| echo "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/gefapi_test" >> $GITHUB_ENV | |
| echo "REDIS_URL=redis://localhost:6379/1" >> $GITHUB_ENV | |
| echo "JWT_SECRET_KEY=test-secret-key-for-ci" >> $GITHUB_ENV | |
| echo "FLASK_ENV=testing" >> $GITHUB_ENV | |
| echo "TESTING=true" >> $GITHUB_ENV | |
| echo "PYTHONPATH=${GITHUB_WORKSPACE}" >> $GITHUB_ENV | |
| - name: Initialize test database | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| # Enable PostGIS extension first | |
| PGPASSWORD=postgres psql -h localhost -U postgres -d gefapi_test -c "CREATE EXTENSION IF NOT EXISTS postgis;" | |
| PGPASSWORD=postgres psql -h localhost -U postgres -d gefapi_test -c "CREATE EXTENSION IF NOT EXISTS postgis_topology;" | |
| # Initialize database schema | |
| poetry run python -c " | |
| import os | |
| os.environ['DATABASE_URL'] = 'postgresql://postgres:postgres@localhost:5432/gefapi_test' | |
| os.environ['TESTING'] = 'true' | |
| from gefapi import app, db | |
| with app.app_context(): | |
| db.create_all() | |
| print('Test database initialized successfully')" | |
| - name: Check database status (like local setup) | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| poetry run python -c " | |
| import os | |
| from sqlalchemy import text | |
| os.environ['DATABASE_URL'] = 'postgresql://postgres:postgres@localhost:5432/gefapi_test' | |
| os.environ['TESTING'] = 'true' | |
| try: | |
| from gefapi import app, db | |
| with app.app_context(): | |
| # Test database connection | |
| result = db.session.execute(text('SELECT 1')).scalar() | |
| print(f'Database connection test: {result}') | |
| # Check for tables | |
| tables_result = db.session.execute( | |
| text( | |
| 'SELECT table_name FROM information_schema.tables WHERE table_schema = \'public\' ORDER BY table_name' | |
| ) | |
| ).fetchall() | |
| print('Tables found in database:') | |
| for table in tables_result: | |
| print(f'- {table[0]}') | |
| except Exception as e: | |
| print(f'β Database status check failed: {e}') | |
| exit(1) | |
| " | |
| - name: Discover available tests | |
| run: | | |
| echo "=== Discovering all available tests ===" | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| poetry run pytest --collect-only -q tests/ | head -50 | |
| echo "" | |
| echo "=== Test file summary ===" | |
| find tests/ -name "test_*.py" -exec basename {} \; | sort | |
| echo "" | |
| echo "=== Test count by file ===" | |
| for file in tests/test_*.py; do | |
| if [ -f "$file" ]; then | |
| count=$(grep -c "def test_" "$file" 2>/dev/null || echo "0") | |
| echo "$(basename "$file"): $count tests" | |
| fi | |
| done | |
| - name: Run comprehensive test suite (Docker-style) | |
| timeout-minutes: 25 | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| # Run all tests like Docker setup: no coverage, continue on failures, comprehensive | |
| poetry run pytest tests/ \ | |
| --no-cov \ | |
| --continue-on-collection-errors \ | |
| --tb=short \ | |
| --timeout=300 \ | |
| --junitxml=comprehensive-test-results.xml \ | |
| -v | |
| - name: Generate coverage report (separate run for coverage) | |
| if: matrix.python-version == '3.11' | |
| timeout-minutes: 20 | |
| continue-on-error: true | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| # Run tests again with coverage for reporting (only on Python 3.11) | |
| poetry run pytest tests/ \ | |
| --cov=gefapi \ | |
| --cov-report=xml \ | |
| --cov-report=html \ | |
| --cov-report=term-missing \ | |
| --cov-fail-under=30 \ | |
| --timeout=300 \ | |
| -q || echo "Coverage run completed with issues" | |
| - name: Upload coverage reports | |
| uses: codecov/codecov-action@v3 | |
| if: matrix.python-version == '3.11' | |
| with: | |
| file: ./coverage.xml | |
| flags: unittests | |
| name: codecov-umbrella | |
| fail_ci_if_error: false | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: test-results-${{ matrix.python-version }} | |
| path: | | |
| comprehensive-test-results.xml | |
| htmlcov/ | |
| coverage.xml | |
| retention-days: 30 | |
| - name: Run security checks | |
| run: | | |
| pip install safety bandit | |
| # Check for known security vulnerabilities in dependencies using legacy mode | |
| # The new 'scan' command requires authentication which isn't suitable for CI | |
| safety check --json --output safety-report.json || true | |
| # Show safety results in a readable format | |
| safety check || echo "Safety scan completed with warnings/issues" | |
| # Run bandit security linter | |
| bandit -r gefapi/ -f json -o bandit-report.json || true | |
| # Show bandit results | |
| bandit -r gefapi/ || true | |
| - name: Upload security scan results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: security-scan-results-${{ matrix.python-version }} | |
| path: | | |
| safety-report.json | |
| bandit-report.json | |
| retention-days: 30 | |
| comprehensive-integration-test: | |
| runs-on: ubuntu-latest | |
| needs: test | |
| if: github.event_name == 'pull_request' | |
| services: | |
| postgres: | |
| image: postgis/postgis:13-3.4 | |
| env: | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_USER: postgres | |
| POSTGRES_DB: gefapi_integration | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| redis: | |
| image: redis:6 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 6379:6379 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: 3.11 | |
| - name: Cache Poetry dependencies | |
| uses: actions/cache@v3 | |
| with: | |
| path: | | |
| ~/.cache/pypoetry | |
| ~/.cache/pip | |
| key: ${{ runner.os }}-poetry-${{ hashFiles('**/poetry.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-poetry- | |
| - name: Install Poetry | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install poetry | |
| - name: Install dependencies with Poetry | |
| run: | | |
| poetry config virtualenvs.create false | |
| poetry install --no-interaction --no-ansi --with dev | |
| - name: Set environment variables | |
| run: | | |
| echo "DATABASE_URL=postgresql://postgres:postgres@localhost:5432/gefapi_integration" >> $GITHUB_ENV | |
| echo "REDIS_URL=redis://localhost:6379/2" >> $GITHUB_ENV | |
| echo "JWT_SECRET_KEY=integration-test-key" >> $GITHUB_ENV | |
| echo "FLASK_ENV=testing" >> $GITHUB_ENV | |
| echo "TESTING=true" >> $GITHUB_ENV | |
| echo "PYTHONPATH=${GITHUB_WORKSPACE}" >> $GITHUB_ENV | |
| - name: Initialize integration test database | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| # Enable PostGIS extension first | |
| PGPASSWORD=postgres psql -h localhost -U postgres -d gefapi_integration -c "CREATE EXTENSION IF NOT EXISTS postgis;" | |
| PGPASSWORD=postgres psql -h localhost -U postgres -d gefapi_integration -c "CREATE EXTENSION IF NOT EXISTS postgis_topology;" | |
| # Initialize database schema | |
| poetry run python -c " | |
| import os | |
| os.environ['DATABASE_URL'] = 'postgresql://postgres:postgres@localhost:5432/gefapi_integration' | |
| os.environ['TESTING'] = 'true' | |
| from gefapi import app, db | |
| with app.app_context(): | |
| db.create_all() | |
| print('Integration test database initialized successfully')" | |
| - name: Run comprehensive integration tests | |
| timeout-minutes: 25 | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| poetry run pytest tests/test_integration.py \ | |
| --tb=long \ | |
| --continue-on-collection-errors \ | |
| --timeout=300 \ | |
| --junitxml=comprehensive-integration-results.xml \ | |
| -v | |
| - name: Run slow performance tests (comprehensive) | |
| timeout-minutes: 15 | |
| continue-on-error: true | |
| run: | | |
| export PYTHONPATH="${PYTHONPATH}:$(pwd)" | |
| poetry run pytest tests/test_performance.py \ | |
| -m "slow" \ | |
| --tb=long \ | |
| --continue-on-collection-errors \ | |
| --timeout=300 \ | |
| --junitxml=slow-performance-results.xml \ | |
| -v || echo "Slow performance tests completed with issues" | |
| - name: Upload comprehensive integration test results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: comprehensive-integration-results | |
| path: | | |
| comprehensive-integration-results.xml | |
| slow-performance-results.xml | |
| retention-days: 30 | |
| test-summary: | |
| runs-on: ubuntu-latest | |
| needs: [test, comprehensive-integration-test] | |
| if: always() | |
| steps: | |
| - name: Test Summary | |
| run: | | |
| echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Test Type | Status |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----------|--------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| Unit Tests | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| Integration Tests | ${{ needs.comprehensive-integration-test.result }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # Calculate overall status | |
| unit_status="${{ needs.test.result }}" | |
| integration_status="${{ needs.comprehensive-integration-test.result }}" | |
| # Count successful tests | |
| success_count=0 | |
| if [ "$unit_status" = "success" ]; then success_count=$((success_count + 1)); fi | |
| if [ "$integration_status" = "success" ] || [ "$integration_status" = "skipped" ]; then success_count=$((success_count + 1)); fi | |
| echo "### Results Details:" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ $success_count -eq 2 ]; then | |
| echo "π **ALL TESTS PASSED!** The test suite is comprehensive and working well." >> $GITHUB_STEP_SUMMARY | |
| elif [ $success_count -eq 1 ]; then | |
| echo "β οΈ **PARTIAL SUCCESS** Some tests passed, but check any failed tests." >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "β **TESTS FAILED** Multiple test suites failed. Please review the logs." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Test coverage includes**:" >> $GITHUB_STEP_SUMMARY | |
| echo "- β **All tests run comprehensively** (Docker-style approach, show all failures)" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Unit tests (auth, executions, pagination, scripts, users, utils, status)" >> $GITHUB_STEP_SUMMARY | |
| echo "- β API validation tests (security, consistency, error handling)" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Integration tests (full workflows)" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Performance tests (including slow tests on PR)" >> $GITHUB_STEP_SUMMARY | |
| echo "- β Smoke tests (import validation)" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "This workflow now runs **all available tests** following the exact Docker test approach." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### β¨ Test Suite Improvements" >> $GITHUB_STEP_SUMMARY | |
| echo "**Previous setup**: Only 3-4 specific test methods were running" >> $GITHUB_STEP_SUMMARY | |
| echo "**Current setup**: Comprehensive Docker-style test execution including:" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Main job**: Complete test suite with \`pytest tests/\` (Docker approach, show all failures)" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Integration job**: Additional comprehensive integration + slow performance tests (show all failures)" >> $GITHUB_STEP_SUMMARY | |
| echo "- **No test duplication**: Streamlined to avoid redundancy" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Multi-Python testing**: (3.11, 3.12, 3.13)" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Coverage reporting**: Separate coverage run on Python 3.11" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Enhanced reliability**: Database status checks, proper timeouts" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Result**: ~50+ tests running instead of ~3 tests β " >> $GITHUB_STEP_SUMMARY | |
| - name: Generate final coverage report | |
| if: always() | |
| run: | | |
| echo "=== Final Coverage Summary ===" | |
| if [ -f coverage.xml ]; then | |
| echo "Coverage report generated successfully" | |
| # Display a summary of coverage | |
| if command -v coverage &> /dev/null; then | |
| coverage report --show-missing || echo "Coverage report generation completed" | |
| fi | |
| else | |
| echo "No coverage.xml found" | |
| fi | |
| echo "=== Test Results Summary ===" | |
| echo "Comprehensive tests: $([ -f comprehensive-test-results.xml ] && echo 'completed' || echo 'not found')" | |
| echo "Comprehensive integration tests: $([ -f comprehensive-integration-results.xml ] && echo 'completed' || echo 'not found')" | |
| echo "Slow performance tests: $([ -f slow-performance-results.xml ] && echo 'completed' || echo 'not found')" |