package receiver import ( "os" "path/filepath" "testing" "time" "edp.buildth.ing/DevFW-CICD/forgejo-runner-resource-collector/internal/summary" ) func TestNewStore(t *testing.T) { dbPath := filepath.Join(t.TempDir(), "test.db") store, err := NewStore(dbPath) if err != nil { t.Fatalf("NewStore() error = %v", err) } defer func() { _ = store.Close() }() if _, err := os.Stat(dbPath); os.IsNotExist(err) { t.Error("database file was not created") } } func TestStore_SaveMetric(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() payload := &MetricsPayload{ Execution: ExecutionContext{ Organization: "test-org", Repository: "test-repo", Workflow: "ci.yml", Job: "build", RunID: "run-123", }, Summary: summary.RunSummary{ StartTime: time.Now().Add(-time.Minute), EndTime: time.Now(), DurationSeconds: 60.0, SampleCount: 12, CPUTotal: summary.StatSummary{Peak: 80.5, Avg: 45.2, P95: 75.0}, MemUsedBytes: summary.StatSummary{Peak: 1024000, Avg: 512000, P95: 900000}, MemUsedPercent: summary.StatSummary{Peak: 50.0, Avg: 25.0, P95: 45.0}, }, } id, err := store.SaveMetric(payload) if err != nil { t.Fatalf("SaveMetric() error = %v", err) } if id == 0 { t.Error("SaveMetric() returned id = 0, want non-zero") } } func TestStore_GetMetricsByRunID(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() // Save two metrics with same run ID for i := 0; i < 2; i++ { payload := &MetricsPayload{ Execution: ExecutionContext{ Organization: "test-org", Repository: "test-repo", Workflow: "ci.yml", Job: "build", RunID: "run-456", }, Summary: summary.RunSummary{SampleCount: i + 1}, } if _, err := store.SaveMetric(payload); err != nil { t.Fatalf("SaveMetric() error = %v", err) } } // Save one with different run ID otherPayload := &MetricsPayload{ Execution: ExecutionContext{RunID: "run-789"}, Summary: summary.RunSummary{}, } if _, err := store.SaveMetric(otherPayload); err != nil { t.Fatalf("SaveMetric() error = %v", err) } metrics, err := store.GetMetricsByRunID("run-456") if err != nil { t.Fatalf("GetMetricsByRunID() error = %v", err) } if len(metrics) != 2 { t.Errorf("GetMetricsByRunID() returned %d metrics, want 2", len(metrics)) } for _, m := range metrics { if m.RunID != "run-456" { t.Errorf("GetMetricsByRunID() returned metric with RunID = %q, want %q", m.RunID, "run-456") } } } func TestStore_GetMetricsByRunID_NotFound(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() metrics, err := store.GetMetricsByRunID("nonexistent") if err != nil { t.Fatalf("GetMetricsByRunID() error = %v", err) } if len(metrics) != 0 { t.Errorf("GetMetricsByRunID() returned %d metrics, want 0", len(metrics)) } } func TestStore_GetMetricsByRepository(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() // Save metrics for different repos repos := []struct { org string repo string }{ {"org-a", "repo-1"}, {"org-a", "repo-1"}, {"org-a", "repo-2"}, {"org-b", "repo-1"}, } for i, r := range repos { payload := &MetricsPayload{ Execution: ExecutionContext{ Organization: r.org, Repository: r.repo, RunID: "run-" + string(rune('a'+i)), }, Summary: summary.RunSummary{}, } if _, err := store.SaveMetric(payload); err != nil { t.Fatalf("SaveMetric() error = %v", err) } } metrics, err := store.GetMetricsByRepository("org-a", "repo-1") if err != nil { t.Fatalf("GetMetricsByRepository() error = %v", err) } if len(metrics) != 2 { t.Errorf("GetMetricsByRepository() returned %d metrics, want 2", len(metrics)) } for _, m := range metrics { if m.Organization != "org-a" || m.Repository != "repo-1" { t.Errorf("GetMetricsByRepository() returned metric with org=%q repo=%q, want org-a/repo-1", m.Organization, m.Repository) } } } func TestStore_SaveMetric_PreservesPayload(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() original := &MetricsPayload{ Execution: ExecutionContext{ Organization: "test-org", Repository: "test-repo", Workflow: "build.yml", Job: "test", RunID: "run-preserve", }, Summary: summary.RunSummary{ DurationSeconds: 123.45, SampleCount: 50, CPUTotal: summary.StatSummary{Peak: 99.9, Avg: 55.5, P95: 88.8}, }, } _, err := store.SaveMetric(original) if err != nil { t.Fatalf("SaveMetric() error = %v", err) } metrics, err := store.GetMetricsByRunID("run-preserve") if err != nil { t.Fatalf("GetMetricsByRunID() error = %v", err) } if len(metrics) != 1 { t.Fatalf("GetMetricsByRunID() returned %d metrics, want 1", len(metrics)) } m := metrics[0] if m.Organization != original.Execution.Organization { t.Errorf("Organization = %q, want %q", m.Organization, original.Execution.Organization) } if m.Repository != original.Execution.Repository { t.Errorf("Repository = %q, want %q", m.Repository, original.Execution.Repository) } if m.Workflow != original.Execution.Workflow { t.Errorf("Workflow = %q, want %q", m.Workflow, original.Execution.Workflow) } if m.Job != original.Execution.Job { t.Errorf("Job = %q, want %q", m.Job, original.Execution.Job) } if m.Payload == "" { t.Error("Payload is empty") } } func newTestStore(t *testing.T) *Store { t.Helper() dbPath := filepath.Join(t.TempDir(), "test.db") store, err := NewStore(dbPath) if err != nil { t.Fatalf("NewStore() error = %v", err) } return store }