package web import ( "fmt" "testing" "time" "bugabinga.net/luci/internal/history" "bugabinga.net/luci/internal/inbox" "bugabinga.net/luci/internal/runstate" "bugabinga.net/luci/internal/trigger" ) type benchmarkState struct { now time.Time runID string events []history.Event pending []inbox.Pending active []runstate.Active } func BenchmarkBuildDashboard(b *testing.B) { for _, size := range []struct { name string runs, children int }{ {"small", 120, 2}, {"medium", 1000, 4}, } { state := benchmarkHistory(size.runs, size.children) b.Run(size.name, func(b *testing.B) { view := BuildDashboard(state.now, state.events, state.pending, state.active, false) if len(view.Attention) == 0 || len(view.Progress) == 0 || len(view.Success) == 0 { b.Fatalf("invalid dashboard fixture: %#v", view) } b.ReportAllocs() b.ResetTimer() for b.Loop() { _ = BuildDashboard(state.now, state.events, state.pending, state.active, false) } }) } } func BenchmarkBuildRun(b *testing.B) { for _, size := range []struct { name string runs, children int }{ {"small", 120, 2}, {"medium", 1000, 4}, } { state := benchmarkHistory(size.runs, size.children) b.Run(size.name, func(b *testing.B) { view := BuildRun(state.runID, state.now, state.events, state.pending, state.active) if !view.Known || view.Parent.ChildID != "run" || len(view.Children) != size.children { b.Fatalf("invalid run fixture: %#v", view) } b.ReportAllocs() b.ResetTimer() for b.Loop() { _ = BuildRun(state.runID, state.now, state.events, state.pending, state.active) } }) } } func benchmarkHistory(runs, children int) benchmarkState { now := time.Date(2026, 9, 27, 12, 0, 0, 0, time.UTC) target := runs / 2 events := make([]history.Event, 0, runs*(children+1)) for run := range runs { runID := fmt.Sprintf("%d", 1_700_000_000_000_000_000+run) when := now.Add(-time.Duration(runs-run) * time.Minute) status := "success" if run%17 == 0 { status = "failed" } events = append(events, history.Event{ RunID: runID, ChildID: "run", Repo: fmt.Sprintf("repo-%02d", run%24), Job: "push", Rev: fmt.Sprintf("%040x", run), Ref: "refs/heads/trunk", Trigger: "push", Status: status, Subject: "build and test revision", StartedAt: when.Add(-45 * time.Second), Time: when, }) for child := range children { childStatus := status if child > 0 && childStatus == "failed" { childStatus = "success" } events = append(events, history.Event{ RunID: runID, ChildID: fmt.Sprintf("%03d", child+1), Repo: fmt.Sprintf("repo-%02d", run%24), Job: fmt.Sprintf("test[go=1.%d,os=linux]", 24+child), Rev: fmt.Sprintf("%040x", run), Ref: "refs/heads/trunk", Trigger: "push", Status: childStatus, Subject: "build and test revision", Matrix: map[string]string{"go": fmt.Sprintf("1.%d", 24+child), "os": "linux"}, StartedAt: when.Add(-30 * time.Second), Time: when, }) } } pendingID := fmt.Sprintf("%d", now.Add(-15*time.Second).UnixNano()) return benchmarkState{ now: now, runID: fmt.Sprintf("%d", 1_700_000_000_000_000_000+target), events: events, pending: []inbox.Pending{{ ID: pendingID, Phase: "queued", Event: trigger.PushEvent{Kind: "push", Repo: "repo-queued", New: "0123456789abcdef0123456789abcdef01234567", Ref: "refs/heads/trunk"}, }}, active: []runstate.Active{{ RunID: "1700000000000002000", ChildID: "001", Repo: "repo-running", Job: "test[go=1.26,os=linux]", Rev: "0123456789abcdef0123456789abcdef01234567", Ref: "refs/heads/trunk", Trigger: "push", StartedAt: now.Add(-2 * time.Minute), }}, } }