1package cef
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 cef2gtk "github.com/bnema/purego-cef2gtk"
9)
10
11func TestRenderStallWatchdogStartStopIdempotent(t *testing.T) {
12 wv := &WebView{ctx: context.Background(), viewBridge: &Cef2gtkAdapter{}}
13
14 wv.startRenderStallWatchdog()
15 firstStop := wv.renderStallStop
16 firstDone := wv.renderStallDone
17 if firstStop == nil || firstDone == nil {
18 t.Fatal("startRenderStallWatchdog did not initialize stop/done channels")
19 }
20
21 wv.startRenderStallWatchdog()
22 if wv.renderStallStop != firstStop || wv.renderStallDone != firstDone {
23 t.Fatal("second start should not replace active watchdog channels")
24 }
25
26 wv.stopRenderStallWatchdog()
27 if wv.renderStallStop != nil || wv.renderStallDone != nil {
28 t.Fatal("stopRenderStallWatchdog should clear watchdog channels")
29 }
30
31 // A second stop should be a no-op, not a double close panic.
32 wv.stopRenderStallWatchdog()
33}
34
35func TestClassifyRenderStallDetectsCEFUIBlockedWithIOAlive(t *testing.T) {
36 classification := classifyRenderStall(
37 cefHeartbeatSnapshot{PostResult: 1, InFlight: true, LastAckAge: 5 * time.Second},
38 cefHeartbeatSnapshot{PostResult: 1, InFlight: false, LastAckAge: 100 * time.Millisecond},
39 )
40 if classification.Category != "cef-ui-task-runner-blocked-io-alive" {
41 t.Fatalf("category = %q", classification.Category)
42 }
43 if !classification.CEFUIBlocked {
44 t.Fatal("CEF UI should be classified as blocked")
45 }
46 if !classification.CEFIOAlive {
47 t.Fatal("CEF IO should be classified as alive")
48 }
49}
50
51func TestClassifyRenderStallKeepsOSRCategoryWhenUIHeartbeatHealthy(t *testing.T) {
52 classification := classifyRenderStall(
53 cefHeartbeatSnapshot{PostResult: 1, InFlight: false, LastAckAge: 100 * time.Millisecond},
54 cefHeartbeatSnapshot{PostResult: 1, InFlight: false, LastAckAge: 100 * time.Millisecond},
55 )
56 if classification.Category != "osr-paint-stalled" {
57 t.Fatalf("category = %q", classification.Category)
58 }
59 if classification.CEFUIBlocked {
60 t.Fatal("CEF UI should not be classified as blocked")
61 }
62}
63
64func TestLatestDiagnosticEventHelpers(t *testing.T) {
65 now := time.Now()
66 diag := cef2gtk.Diagnostics{Events: []cef2gtk.DiagnosticEvent{
67 {Time: now.Add(-3 * time.Second), Kind: "accelerated-paint"},
68 {Time: now.Add(-2 * time.Second), Kind: "render-failure", Message: "old"},
69 {Time: now.Add(-1 * time.Second), Kind: "render-failure", Message: "new"},
70 }}
71
72 if got := latestDiagnosticEventOfKind(diag, "render-failure"); got.Message != "new" {
73 t.Fatalf("latest render-failure message = %q, want new", got.Message)
74 }
75 if got := latestDiagnosticEvent(diag); got.Kind != "render-failure" || got.Message != "new" {
76 t.Fatalf("latest event = (%q, %q), want (render-failure, new)", got.Kind, got.Message)
77 }
78 if got := latestDiagnosticEventTime(diag, "accelerated-paint"); !got.Equal(now.Add(-3 * time.Second)) {
79 t.Fatalf("latest accelerated paint time = %v, want %v", got, now.Add(-3*time.Second))
80 }
81}