Collect Go code coverage from running applications via HTTP - no volumes, no GOCOVERDIR, no deployment modifications needed.
Traditional coverage collection with GOCOVERDIR requires:
- ❌ Setting
GOCOVERDIRenvironment variable - ❌ Mounting volumes in Kubernetes for coverage data
- ❌ Modifying deployment manifests to add volume mounts
- ❌ Extracting files from volumes after tests
This solution eliminates all of that:
- ✅ No
GOCOVERDIRneeded - ✅ No volume mounts required
- ✅ No deployment manifest changes
- ✅ Just inject
coverage_server.goduring build - ✅ Collect coverage via HTTP with provided client library
- Build time: Include
server/coverage_server.gowhen building with-coverflag - Runtime: Coverage server automatically starts on port 9095
- Test time: Client library collects coverage via HTTP port-forwarding
- Result: Coverage reports generated automatically
📖 Want technical details? See TECHNICAL.md for in-depth architecture, algorithms, and implementation details.
- 🚀 HTTP Coverage Server - Automatically starts coverage endpoint in your app
- 🔌 Client Library - Collect coverage from Kubernetes pods with port-forwarding
- 📊 Report Generation - Generate text and HTML coverage reports
- 🎯 Minimal Setup - Just inject one file during Docker build
- 🐳 Kubernetes-friendly - No volumes, no manifest modifications
Download server/coverage_server.go and compile it with your app (test builds only):
# Download coverage server
RUN wget https://raw.githubusercontent.com/psturc/go-coverage-http/main/server/coverage_server.go
# Build with coverage
RUN go build -cover -covermode=atomic -o app example_app.go coverage_server.goThe coverage server will automatically start on port 9095 (configurable via COVERAGE_PORT env var).
import coverageclient "github.com/psturc/go-coverage-http/client"
// Create client
client, _ := coverageclient.NewClient("default", "./coverage-output")
// Discover pod dynamically using label selector
podName, _ := client.GetPodName("app=my-app")
// Or use the manual pod name
// podName := "my-pod-12345"
// Collect from Kubernetes pod
client.CollectCoverageFromPod(ctx, podName, "my-test", 9095)
// Option 1: Use convenience method (automatically filters coverage_server.go)
client.ProcessCoverageReports("my-test")
// Option 2: Manual control over each step
client.GenerateCoverageReport("my-test")
client.FilterCoverageReport("my-test") // Uses default filters
client.GenerateHTMLReport("my-test")
// Option 3: Custom filtering
client.FilterCoverageReport("my-test", "coverage_server.go", "test_helper.go")The client can automatically discover pods using Kubernetes label selectors, eliminating the need for manual pod name lookup:
// Simple pod discovery (uses default context)
podName, err := client.GetPodName("app=my-app")
// With custom context and timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
podName, err := client.GetPodNameWithContext(ctx, "app=my-app,version=v1.0")
// The method will:
// - List all pods matching the label selector
// - Find the first pod in "Running" state
// - Return an error if no running pods are foundBy default, the client automatically filters out coverage_server.go from reports to avoid including the coverage collection infrastructure itself. You can customize this behavior:
// Add additional files to filter
client.AddDefaultFilter("internal/test_helper.go")
// Replace default filters
client.SetDefaultFilters([]string{"coverage_server.go", "mock_*.go"})
// Disable filtering (pass empty slice)
client.FilterCoverageReport("my-test", []string{}...)The client automatically detects and remaps container paths (e.g., /app/example_app.go) to local filesystem paths. This uses intelligent matching based on relative path structure:
// Path remapping is enabled by default
client.ProcessCoverageReports("my-test")
// Configure source directory (defaults to current working directory)
client.SetSourceDirectory("/path/to/my/project")
// Disable path remapping if needed
client.SetPathRemapping(false)How it works:
- The client analyzes coverage paths that don't exist locally (e.g.,
/app/example_app.go) - Matches them to local files by comparing path structures
- Automatically determines the mapping (e.g.,
/app/→/Users/user/project/) - Rewrites coverage data to use local paths
This allows tools like go tool cover to find source files and generate HTML reports with proper source code display.
Coverage data can be easily uploaded to Codecov via GitHub Actions. See the workflow example in this repository.
This repository includes a working demo application. To try it:
# Build Docker image with coverage enabled
docker build -f Dockerfile --build-arg ENABLE_COVERAGE=true -t localhost/coverage-http-demo:test .
# Deploy to Kubernetes
kubectl apply -f k8s-deployment.yaml
# Run E2E tests (will collect coverage automatically)
cd test && go test -vThe E2E tests will:
- Execute requests against the running pod
- Collect coverage data via port-forwarding
- Generate text and HTML reports in
./coverage-output/
example_app.go- Sample HTTP server with test endpointsDockerfile- Production build (downloadscoverage_server.gofrom GitHub)Dockerfile.local- Local development build (uses localcoverage_server.go)k8s-deployment.yaml- Kubernetes deployment manifesttest/e2e_test.go- E2E tests with coverage collection
Application endpoints:
:8000/health- Health check:8000/greet?name=X- Greeting endpoint:8000/calculate- Calculation endpoint
Coverage endpoints (test builds only):
:9095/coverage- Collect coverage data:9095/health- Coverage server health check
- TECHNICAL.md - Deep dive into architecture, algorithms, binary formats, and implementation details
- Example Workflow - Complete CI/CD pipeline with coverage collection and Codecov upload
- Example Test - Full e2e test implementation with coverage collection
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.