package receiver import ( "os" "path/filepath" "testing" "time" "edp.buildth.ing/DevFW-CICD/forgejo-runner-optimiser/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_GetMetricsByWorkflowJob(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() // Save metrics for different workflow/job combinations payloads := []struct { org string repo string workflow string job string }{ {"org-a", "repo-1", "ci.yml", "build"}, {"org-a", "repo-1", "ci.yml", "build"}, {"org-a", "repo-1", "ci.yml", "test"}, {"org-a", "repo-1", "deploy.yml", "build"}, } for i, p := range payloads { payload := &MetricsPayload{ Execution: ExecutionContext{ Organization: p.org, Repository: p.repo, Workflow: p.workflow, Job: p.job, 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.GetMetricsByWorkflowJob("org-a", "repo-1", "ci.yml", "build") if err != nil { t.Fatalf("GetMetricsByWorkflowJob() error = %v", err) } if len(metrics) != 2 { t.Errorf("GetMetricsByWorkflowJob() returned %d metrics, want 2", len(metrics)) } for _, m := range metrics { if m.Organization != "org-a" || m.Repository != "repo-1" || m.Workflow != "ci.yml" || m.Job != "build" { t.Errorf("GetMetricsByWorkflowJob() returned metric with org=%q repo=%q workflow=%q job=%q, want org-a/repo-1/ci.yml/build", m.Organization, m.Repository, m.Workflow, m.Job) } } } func TestStore_GetMetricsByWorkflowJob_NotFound(t *testing.T) { store := newTestStore(t) defer func() { _ = store.Close() }() metrics, err := store.GetMetricsByWorkflowJob("nonexistent", "repo", "workflow", "job") if err != nil { t.Fatalf("GetMetricsByWorkflowJob() error = %v", err) } if len(metrics) != 0 { t.Errorf("GetMetricsByWorkflowJob() returned %d metrics, want 0", len(metrics)) } } 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.GetMetricsByWorkflowJob("test-org", "test-repo", "build.yml", "test") if err != nil { t.Fatalf("GetMetricsByWorkflowJob() error = %v", err) } if len(metrics) != 1 { t.Fatalf("GetMetricsByWorkflowJob() 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 }