name: Tests on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] workflow_dispatch: jobs: test: name: Run Tests runs-on: ubuntu-latest strategy: matrix: dotnet-version: ['9.0.x'] services: postgres: image: postgres:16-alpine env: POSTGRES_DB: colaflow_test POSTGRES_USER: colaflow_test POSTGRES_PASSWORD: colaflow_test_password options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 redis: image: redis:7-alpine options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 3s --health-retries 5 ports: - 6379:6379 steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for better coverage reports - name: Setup .NET ${{ matrix.dotnet-version }} uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet-version }} - name: Cache NuGet packages uses: actions/cache@v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} restore-keys: | ${{ runner.os }}-nuget- - name: Restore dependencies run: dotnet restore working-directory: ./src - name: Build solution run: dotnet build --no-restore --configuration Release working-directory: ./src - name: Run unit tests run: | dotnet test \ --no-build \ --configuration Release \ --filter "Category=Unit" \ --logger "trx;LogFileName=unit-tests.trx" \ --logger "console;verbosity=detailed" \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=./coverage/unit/ working-directory: ./tests continue-on-error: true - name: Run integration tests run: | dotnet test \ --no-build \ --configuration Release \ --filter "Category=Integration" \ --logger "trx;LogFileName=integration-tests.trx" \ --logger "console;verbosity=detailed" \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=./coverage/integration/ working-directory: ./tests env: ConnectionStrings__DefaultConnection: "Host=localhost;Port=5432;Database=colaflow_test;Username=colaflow_test;Password=colaflow_test_password" ConnectionStrings__Redis: "localhost:6379" continue-on-error: true - name: Run all tests with coverage run: | dotnet test \ --no-build \ --configuration Release \ --logger "trx;LogFileName=all-tests.trx" \ --logger "console;verbosity=normal" \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=./coverage/ \ /p:Threshold=80 \ /p:ThresholdType=line \ /p:ThresholdStat=total working-directory: ./tests - name: Generate coverage report if: always() run: | dotnet tool install -g dotnet-reportgenerator-globaltool reportgenerator \ -reports:./tests/coverage/coverage.opencover.xml \ -targetdir:./coverage-report \ -reporttypes:Html;Badges;TextSummary - name: Upload coverage report if: always() uses: actions/upload-artifact@v4 with: name: coverage-report path: ./coverage-report retention-days: 30 - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: test-results path: ./tests/**/*.trx retention-days: 30 - name: Publish test results if: always() uses: dorny/test-reporter@v1 with: name: Test Results path: ./tests/**/*.trx reporter: dotnet-trx fail-on-error: true - name: Comment coverage on PR if: github.event_name == 'pull_request' uses: 5monkeys/cobertura-action@master with: path: ./tests/coverage/coverage.opencover.xml minimum_coverage: 80 fail_below_threshold: true - name: Check coverage threshold run: | if [ -f ./coverage-report/Summary.txt ]; then cat ./coverage-report/Summary.txt # Extract line coverage percentage COVERAGE=$(grep "Line coverage:" ./coverage-report/Summary.txt | awk '{print $3}' | sed 's/%//') echo "Coverage: $COVERAGE%" # Check if coverage meets threshold if (( $(echo "$COVERAGE < 80" | bc -l) )); then echo "❌ Coverage $COVERAGE% is below threshold 80%" exit 1 else echo "✅ Coverage $COVERAGE% meets threshold 80%" fi fi docker-build: name: Docker Build Test runs-on: ubuntu-latest needs: test steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Test Docker Compose run: | docker-compose config echo "✅ Docker Compose configuration is valid" - name: Build Docker images (dry run) run: | docker-compose build --no-cache continue-on-error: true summary: name: Test Summary runs-on: ubuntu-latest needs: [test, docker-build] if: always() steps: - name: Generate summary run: | echo "## Test Results Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Job | Status |" >> $GITHUB_STEP_SUMMARY echo "|-----|--------|" >> $GITHUB_STEP_SUMMARY echo "| Tests | ${{ needs.test.result }} |" >> $GITHUB_STEP_SUMMARY echo "| Docker Build | ${{ needs.docker-build.result }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [[ "${{ needs.test.result }}" == "success" ]] && [[ "${{ needs.docker-build.result }}" == "success" ]]; then echo "✅ All checks passed!" >> $GITHUB_STEP_SUMMARY else echo "❌ Some checks failed. Please review the logs." >> $GITHUB_STEP_SUMMARY fi