feat: parameterized cluster — make cluster NODES=N #66
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: HyperCache CI | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main ] | |
| env: | |
| GO_VERSION: '1.23.2' | |
| jobs: | |
| unit-tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Cache Go modules | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/go/pkg/mod | |
| ~/.cache/go-build | |
| key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | |
| restore-keys: | | |
| ${{ runner.os }}-go- | |
| - name: Download dependencies | |
| run: go mod download | |
| - name: Verify dependencies | |
| run: go mod verify | |
| - name: Run golangci-lint | |
| uses: golangci/golangci-lint-action@v6 | |
| with: | |
| version: latest | |
| args: --timeout=5m | |
| - name: Install additional tools | |
| run: sudo apt-get update && sudo apt-get install -y bc | |
| - name: Run unit tests with coverage | |
| run: | | |
| mkdir -p test-results | |
| # Run each test path separately to avoid coverprofile "File exists" conflicts | |
| go test -v -race -coverprofile=test-results/unit.out -covermode=atomic -coverpkg=./internal/...,./pkg/...,./cmd/... -timeout=5m ./tests/unit/... | |
| go test -v -race -coverprofile=test-results/internal.out -covermode=atomic -coverpkg=./internal/...,./pkg/...,./cmd/... -timeout=5m ./internal/... | |
| go test -v -race -coverprofile=test-results/pkg.out -covermode=atomic -coverpkg=./internal/...,./pkg/...,./cmd/... -timeout=5m ./pkg/... | |
| # Merge coverage profiles | |
| head -1 test-results/unit.out > test-results/coverage.out | |
| tail -n +2 -q test-results/unit.out test-results/internal.out test-results/pkg.out >> test-results/coverage.out | |
| echo "✅ Unit tests completed" | |
| - name: Check test coverage | |
| run: | | |
| if [ -f "test-results/coverage.out" ]; then | |
| echo "📊 Coverage Report:" | |
| go tool cover -func=test-results/coverage.out | tail -10 | |
| # Extract coverage percentage | |
| COVERAGE=$(go tool cover -func=test-results/coverage.out | tail -1 | grep -o '[0-9]\+\.[0-9]\+%' | sed 's/%//') | |
| echo "Overall coverage: ${COVERAGE}%" | |
| # Enforce minimum coverage threshold | |
| THRESHOLD=30 | |
| if (( $(echo "$COVERAGE >= $THRESHOLD" | bc -l) )); then | |
| echo "✅ Coverage meets threshold: ${COVERAGE}% >= ${THRESHOLD}%" | |
| else | |
| echo "❌ Coverage below threshold: ${COVERAGE}% < ${THRESHOLD}%" | |
| exit 1 | |
| fi | |
| # Generate HTML coverage report | |
| go tool cover -html=test-results/coverage.out -o test-results/coverage.html | |
| else | |
| echo "⚠️ No coverage file found" | |
| fi | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: unit-test-results | |
| path: | | |
| test-results/ | |
| coverage.html | |
| scenario-tests: | |
| name: Scenario Tests | |
| runs-on: ubuntu-latest | |
| needs: unit-tests | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Download dependencies | |
| run: go mod download | |
| - name: Run scenario tests | |
| run: | | |
| go test -v -race -timeout=5m ./tests/scenarios/... | |
| echo "✅ Scenario tests completed" | |
| integration-tests: | |
| name: Integration Tests (Newman) | |
| runs-on: ubuntu-latest | |
| needs: unit-tests | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Set up Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Set up Node.js (for Newman) | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Install Newman | |
| run: npm install -g newman | |
| - name: Build HyperCache | |
| run: | | |
| mkdir -p bin logs | |
| go build -v -o bin/hypercache ./cmd/hypercache | |
| - name: Start 3-node cluster | |
| run: | | |
| rm -rf /tmp/hypercache | |
| mkdir -p /tmp/hypercache/node-{1,2,3} | |
| ./bin/hypercache -protocol resp -config configs/node1-config.yaml > logs/node-1.log 2>&1 & | |
| sleep 3 | |
| ./bin/hypercache -protocol resp -config configs/node2-config.yaml > logs/node-2.log 2>&1 & | |
| sleep 3 | |
| ./bin/hypercache -protocol resp -config configs/node3-config.yaml > logs/node-3.log 2>&1 & | |
| sleep 5 | |
| # Verify cluster is healthy | |
| for port in 9080 9081 9082; do | |
| STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$port/health) | |
| if [ "$STATUS" != "200" ]; then | |
| echo "Node on port $port not healthy (status: $STATUS)" | |
| cat logs/node-*.log | |
| exit 1 | |
| fi | |
| done | |
| echo "Cluster is healthy (3 nodes)" | |
| - name: Run Postman collection via Newman | |
| run: | | |
| newman run HyperCache.postman_collection.json \ | |
| --delay-request 2000 \ | |
| --timeout-request 10000 \ | |
| --reporters cli,json \ | |
| --reporter-json-export test-results/newman-results.json | |
| - name: Cleanup | |
| if: always() | |
| run: pkill -f bin/hypercache 2>/dev/null || true | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: integration-test-results | |
| path: | | |
| test-results/ | |
| logs/ |