test(daemon): cover lifecycle and coalescing metrics
- commit
- 357675218cf27f6c3c007e330ce3285ff405c839
- author
- brice · · 2026-07-12 04:37 UTC
- parent
- 7d036d7
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +42 -5
M internal/usecase/daemon/performance_benchmark_test.go +9 -5
| @@ -177,6 +177,14 @@ func benchmarkDaemonLargeHistory(b *testing.B, workload string, run func(*perfor | |||
| 177 | 177 | } | |
| 178 | 178 | } | |
| 179 | 179 | ||
| 180 | + | func TestCoordinatorCoalescingRatioReportsInvalidationsPerWake(t *testing.T) { | |
| 181 | + | require.Equal(t, float64(3), coordinatorCoalescingRatio(performanceMetrics{ | |
| 182 | + | coordinatorWakes: 1, | |
| 183 | + | coordinatorCoalesced: 3, | |
| 184 | + | })) | |
| 185 | + | require.Zero(t, coordinatorCoalescingRatio(performanceMetrics{})) | |
| 186 | + | } | |
| 187 | + | ||
| 180 | 188 | func benchmarkReportMetrics(b *testing.B, metrics performanceMetrics, operations, historyRows int) { | |
| 181 | 189 | b.Helper() | |
| 182 | 190 | if operations == 0 { | |
| @@ -191,11 +199,7 @@ func benchmarkReportMetrics(b *testing.B, metrics performanceMetrics, operations | |||
| 191 | 199 | b.ReportMetric(float64(metrics.coordinatorInvalidations)/perOperation, "coordinatorinvalidations/op") | |
| 192 | 200 | b.ReportMetric(float64(metrics.coordinatorWakes)/perOperation, "coordinatorwakes/op") | |
| 193 | 201 | b.ReportMetric(float64(metrics.coordinatorCoalesced)/perOperation, "coordinatorcoalesced/op") | |
| 194 | - | if metrics.coordinatorInvalidations > 0 { | |
| 195 | - | b.ReportMetric(float64(metrics.coordinatorCoalesced)/float64(metrics.coordinatorInvalidations), "coordinatorcoalescingratio") | |
| 196 | - | } else { | |
| 197 | - | b.ReportMetric(0, "coordinatorcoalescingratio") | |
| 198 | - | } | |
| 202 | + | b.ReportMetric(coordinatorCoalescingRatio(metrics), "coordinatorcoalescingratio") | |
| 199 | 203 | b.ReportMetric(float64(historyRows), "historyrows/pane") | |
| 200 | 204 | } | |
| 201 | 205 | ||
| @@ -177,6 +177,14 @@ func benchmarkDaemonLargeHistory(b *testing.B, workload string, run func(*perfor | |||||
| 177 | } | 177 | } | ||
| 178 | } | 178 | } | ||
| 179 | 179 | ||||
| 180 | + | func TestCoordinatorCoalescingRatioReportsInvalidationsPerWake(t *testing.T) { | |||
| 181 | + | require.Equal(t, float64(3), coordinatorCoalescingRatio(performanceMetrics{ | |||
| 182 | + | coordinatorWakes: 1, | |||
| 183 | + | coordinatorCoalesced: 3, | |||
| 184 | + | })) | |||
| 185 | + | require.Zero(t, coordinatorCoalescingRatio(performanceMetrics{})) | |||
| 186 | + | } | |||
| 187 | + | ||||
| 180 | func benchmarkReportMetrics(b *testing.B, metrics performanceMetrics, operations, historyRows int) { | 188 | func benchmarkReportMetrics(b *testing.B, metrics performanceMetrics, operations, historyRows int) { | ||
| 181 | b.Helper() | 189 | b.Helper() | ||
| 182 | if operations == 0 { | 190 | if operations == 0 { | ||
| @@ -191,11 +199,7 @@ func benchmarkReportMetrics(b *testing.B, metrics performanceMetrics, operations | |||||
| 191 | b.ReportMetric(float64(metrics.coordinatorInvalidations)/perOperation, "coordinatorinvalidations/op") | 199 | b.ReportMetric(float64(metrics.coordinatorInvalidations)/perOperation, "coordinatorinvalidations/op") | ||
| 192 | b.ReportMetric(float64(metrics.coordinatorWakes)/perOperation, "coordinatorwakes/op") | 200 | b.ReportMetric(float64(metrics.coordinatorWakes)/perOperation, "coordinatorwakes/op") | ||
| 193 | b.ReportMetric(float64(metrics.coordinatorCoalesced)/perOperation, "coordinatorcoalesced/op") | 201 | b.ReportMetric(float64(metrics.coordinatorCoalesced)/perOperation, "coordinatorcoalesced/op") | ||
| 194 | - | if metrics.coordinatorInvalidations > 0 { | 202 | + | b.ReportMetric(coordinatorCoalescingRatio(metrics), "coordinatorcoalescingratio") |
| 195 | - | b.ReportMetric(float64(metrics.coordinatorCoalesced)/float64(metrics.coordinatorInvalidations), "coordinatorcoalescingratio") | |||
| 196 | - | } else { | |||
| 197 | - | b.ReportMetric(0, "coordinatorcoalescingratio") | |||
| 198 | - | } | |||
| 199 | b.ReportMetric(float64(historyRows), "historyrows/pane") | 203 | b.ReportMetric(float64(historyRows), "historyrows/pane") | ||
| 200 | } | 204 | } | ||
| 201 | 205 | ||||
M internal/usecase/daemon/render_coordinator_test.go +33 -0
| @@ -900,6 +900,39 @@ func TestRenderCoordinatorPreviewSubscriptionsAreIndependent(t *testing.T) { | |||
| 900 | 900 | awaitWake(t, second) | |
| 901 | 901 | } | |
| 902 | 902 | ||
| 903 | + | func TestRenderCoordinatorAttachmentLifecycleDropsStaleInvalidationState(t *testing.T) { | |
| 904 | + | cases := []struct { | |
| 905 | + | name string | |
| 906 | + | transition func(*renderCoordinator, *attachedClient, *attachedClient) | |
| 907 | + | }{ | |
| 908 | + | {"detach and attach", func(rc *renderCoordinator, old, replacement *attachedClient) { | |
| 909 | + | rc.noteDetach(old) | |
| 910 | + | rc.attach(replacement) | |
| 911 | + | }}, | |
| 912 | + | {"replace", func(rc *renderCoordinator, old, replacement *attachedClient) { | |
| 913 | + | rc.noteReplace(old, replacement) | |
| 914 | + | }}, | |
| 915 | + | } | |
| 916 | + | for _, tc := range cases { | |
| 917 | + | t.Run(tc.name, func(t *testing.T) { | |
| 918 | + | h := newCoordinatorHarness(t) | |
| 919 | + | old, replacement := &attachedClient{}, &attachedClient{} | |
| 920 | + | h.rc.attach(old) | |
| 921 | + | h.rc.invalidate(renderInvalidation{class: invalidateUrgent, reset: true, producer: "stale"}) | |
| 922 | + | tc.transition(h.rc, old, replacement) | |
| 923 | + | ||
| 924 | + | h.rc.invalidateForAttachment(replacement, renderInvalidation{class: invalidateOutput, producer: "fresh"}) | |
| 925 | + | timers := h.armedTimers(t) | |
| 926 | + | require.NotEmpty(t, timers) | |
| 927 | + | timers[len(timers)-1].ch <- time.Time{} | |
| 928 | + | wake := awaitWake(t, h.wakes) | |
| 929 | + | require.False(t, wake.reset) | |
| 930 | + | require.False(t, wake.urgent) | |
| 931 | + | require.Equal(t, 1, wake.coalesced) | |
| 932 | + | }) | |
| 933 | + | } | |
| 934 | + | } | |
| 935 | + | ||
| 903 | 936 | func TestRenderCoordinatorLifecycleDropsStaleWakes(t *testing.T) { | |
| 904 | 937 | cases := []struct { | |
| 905 | 938 | name string | |
| @@ -900,6 +900,39 @@ func TestRenderCoordinatorPreviewSubscriptionsAreIndependent(t *testing.T) { | |||||
| 900 | awaitWake(t, second) | 900 | awaitWake(t, second) | ||
| 901 | } | 901 | } | ||
| 902 | 902 | ||||
| 903 | + | func TestRenderCoordinatorAttachmentLifecycleDropsStaleInvalidationState(t *testing.T) { | |||
| 904 | + | cases := []struct { | |||
| 905 | + | name string | |||
| 906 | + | transition func(*renderCoordinator, *attachedClient, *attachedClient) | |||
| 907 | + | }{ | |||
| 908 | + | {"detach and attach", func(rc *renderCoordinator, old, replacement *attachedClient) { | |||
| 909 | + | rc.noteDetach(old) | |||
| 910 | + | rc.attach(replacement) | |||
| 911 | + | }}, | |||
| 912 | + | {"replace", func(rc *renderCoordinator, old, replacement *attachedClient) { | |||
| 913 | + | rc.noteReplace(old, replacement) | |||
| 914 | + | }}, | |||
| 915 | + | } | |||
| 916 | + | for _, tc := range cases { | |||
| 917 | + | t.Run(tc.name, func(t *testing.T) { | |||
| 918 | + | h := newCoordinatorHarness(t) | |||
| 919 | + | old, replacement := &attachedClient{}, &attachedClient{} | |||
| 920 | + | h.rc.attach(old) | |||
| 921 | + | h.rc.invalidate(renderInvalidation{class: invalidateUrgent, reset: true, producer: "stale"}) | |||
| 922 | + | tc.transition(h.rc, old, replacement) | |||
| 923 | + | ||||
| 924 | + | h.rc.invalidateForAttachment(replacement, renderInvalidation{class: invalidateOutput, producer: "fresh"}) | |||
| 925 | + | timers := h.armedTimers(t) | |||
| 926 | + | require.NotEmpty(t, timers) | |||
| 927 | + | timers[len(timers)-1].ch <- time.Time{} | |||
| 928 | + | wake := awaitWake(t, h.wakes) | |||
| 929 | + | require.False(t, wake.reset) | |||
| 930 | + | require.False(t, wake.urgent) | |||
| 931 | + | require.Equal(t, 1, wake.coalesced) | |||
| 932 | + | }) | |||
| 933 | + | } | |||
| 934 | + | } | |||
| 935 | + | ||||
| 903 | func TestRenderCoordinatorLifecycleDropsStaleWakes(t *testing.T) { | 936 | func TestRenderCoordinatorLifecycleDropsStaleWakes(t *testing.T) { | ||
| 904 | cases := []struct { | 937 | cases := []struct { | ||
| 905 | name string | 938 | name string | ||