Skip to content

Add function to fetch countries that are missing from geoBoundaries A… #769

Add function to fetch countries that are missing from geoBoundaries A…

Add function to fetch countries that are missing from geoBoundaries A… #769

Workflow file for this run

# 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.10, 3.11, 3.12)" >> $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')"