All checks were successful
ci / build (push) Successful in 46s
Add push client that sends run summary to a configurable HTTP endpoint on shutdown. Execution context is read from GitHub Actions style environment variables (with Gitea fallbacks). New flag: -push-endpoint <url> Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
162 lines
4.2 KiB
Go
162 lines
4.2 KiB
Go
package summary
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestPushClient_Push(t *testing.T) {
|
|
var received MetricsPayload
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodPost {
|
|
t.Errorf("expected POST, got %s", r.Method)
|
|
}
|
|
if ct := r.Header.Get("Content-Type"); ct != "application/json" {
|
|
t.Errorf("expected Content-Type application/json, got %s", ct)
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&received); err != nil {
|
|
t.Errorf("failed to decode body: %v", err)
|
|
}
|
|
w.WriteHeader(http.StatusCreated)
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := NewPushClient(server.URL)
|
|
client.ctx = ExecutionContext{
|
|
Organization: "test-org",
|
|
Repository: "test-repo",
|
|
Workflow: "ci.yml",
|
|
Job: "build",
|
|
RunID: "12345",
|
|
}
|
|
|
|
summary := &RunSummary{
|
|
StartTime: time.Now().Add(-time.Minute),
|
|
EndTime: time.Now(),
|
|
DurationSeconds: 60.0,
|
|
SampleCount: 10,
|
|
CPUTotal: StatSummary{Peak: 80.0, Avg: 50.0, P95: 75.0},
|
|
}
|
|
|
|
err := client.Push(context.Background(), summary)
|
|
if err != nil {
|
|
t.Fatalf("Push() error = %v", err)
|
|
}
|
|
|
|
if received.Execution.Organization != "test-org" {
|
|
t.Errorf("Organization = %q, want %q", received.Execution.Organization, "test-org")
|
|
}
|
|
if received.Execution.RunID != "12345" {
|
|
t.Errorf("RunID = %q, want %q", received.Execution.RunID, "12345")
|
|
}
|
|
if received.Summary.SampleCount != 10 {
|
|
t.Errorf("SampleCount = %d, want %d", received.Summary.SampleCount, 10)
|
|
}
|
|
}
|
|
|
|
func TestPushClient_Push_NilSummary(t *testing.T) {
|
|
client := NewPushClient("http://localhost:9999")
|
|
err := client.Push(context.Background(), nil)
|
|
if err != nil {
|
|
t.Errorf("Push(nil) error = %v, want nil", err)
|
|
}
|
|
}
|
|
|
|
func TestPushClient_Push_ServerError(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer server.Close()
|
|
|
|
client := NewPushClient(server.URL)
|
|
client.ctx = ExecutionContext{RunID: "test"}
|
|
|
|
err := client.Push(context.Background(), &RunSummary{})
|
|
if err == nil {
|
|
t.Error("Push() expected error for 500 response, got nil")
|
|
}
|
|
}
|
|
|
|
func TestPushClient_Push_ConnectionError(t *testing.T) {
|
|
client := NewPushClient("http://localhost:1") // Invalid port
|
|
client.ctx = ExecutionContext{RunID: "test"}
|
|
|
|
err := client.Push(context.Background(), &RunSummary{})
|
|
if err == nil {
|
|
t.Error("Push() expected error for connection failure, got nil")
|
|
}
|
|
}
|
|
|
|
func TestExecutionContextFromEnv(t *testing.T) {
|
|
// Save and restore env
|
|
origVars := map[string]string{
|
|
"GITHUB_REPOSITORY_OWNER": "",
|
|
"GITHUB_REPOSITORY": "",
|
|
"GITHUB_WORKFLOW": "",
|
|
"GITHUB_JOB": "",
|
|
"GITHUB_RUN_ID": "",
|
|
}
|
|
for k := range origVars {
|
|
origVars[k] = getEnvWithFallback(k)
|
|
}
|
|
defer func() {
|
|
for k, v := range origVars {
|
|
if v == "" {
|
|
t.Setenv(k, "")
|
|
}
|
|
}
|
|
}()
|
|
|
|
t.Setenv("GITHUB_REPOSITORY_OWNER", "my-org")
|
|
t.Setenv("GITHUB_REPOSITORY", "my-org/my-repo")
|
|
t.Setenv("GITHUB_WORKFLOW", "CI")
|
|
t.Setenv("GITHUB_JOB", "test")
|
|
t.Setenv("GITHUB_RUN_ID", "999")
|
|
|
|
ctx := ExecutionContextFromEnv()
|
|
|
|
if ctx.Organization != "my-org" {
|
|
t.Errorf("Organization = %q, want %q", ctx.Organization, "my-org")
|
|
}
|
|
if ctx.Repository != "my-org/my-repo" {
|
|
t.Errorf("Repository = %q, want %q", ctx.Repository, "my-org/my-repo")
|
|
}
|
|
if ctx.Workflow != "CI" {
|
|
t.Errorf("Workflow = %q, want %q", ctx.Workflow, "CI")
|
|
}
|
|
if ctx.Job != "test" {
|
|
t.Errorf("Job = %q, want %q", ctx.Job, "test")
|
|
}
|
|
if ctx.RunID != "999" {
|
|
t.Errorf("RunID = %q, want %q", ctx.RunID, "999")
|
|
}
|
|
}
|
|
|
|
func TestExecutionContextFromEnv_GiteaFallback(t *testing.T) {
|
|
t.Setenv("GITHUB_RUN_ID", "")
|
|
t.Setenv("GITEA_RUN_ID", "gitea-123")
|
|
|
|
ctx := ExecutionContextFromEnv()
|
|
|
|
if ctx.RunID != "gitea-123" {
|
|
t.Errorf("RunID = %q, want %q (Gitea fallback)", ctx.RunID, "gitea-123")
|
|
}
|
|
}
|
|
|
|
func TestPushClient_ExecutionContext(t *testing.T) {
|
|
client := NewPushClient("http://example.com")
|
|
client.ctx = ExecutionContext{
|
|
Organization: "org",
|
|
Repository: "repo",
|
|
RunID: "run",
|
|
}
|
|
|
|
ctx := client.ExecutionContext()
|
|
if ctx.Organization != "org" {
|
|
t.Errorf("Organization = %q, want %q", ctx.Organization, "org")
|
|
}
|
|
}
|