1//go:build linux
2
3package session
4
5import (
6 "image"
7 "path/filepath"
8 "testing"
9 "time"
10)
11
12func TestReadbackBudgetAndBoundedWorker(t *testing.T) {
13 s := &Session{readbacks: make(chan readbackJob, readbackQueueSize)}
14 for i := 0; i < maxDebugPNGs; i++ {
15 if !s.wantReadback() {
16 t.Fatalf("budget ended at %d", i)
17 }
18 s.debugFrames++
19 }
20 if s.wantReadback() {
21 t.Fatal("readback copy scheduled after limit")
22 }
23 queue := make(chan readbackJob, readbackQueueSize)
24 for i := 0; i < readbackQueueSize; i++ {
25 if !offerReadback(queue, readbackJob{uint64(i), image.NewNRGBA(image.Rect(0, 0, 1, 1))}) {
26 t.Fatal("queue rejected before full")
27 }
28 }
29 done := make(chan bool, 1)
30 go func() { done <- offerReadback(queue, readbackJob{}) }()
31 select {
32 case accepted := <-done:
33 if accepted {
34 t.Fatal("full queue accepted job")
35 }
36 case <-time.After(time.Second):
37 t.Fatal("full queue blocked owner")
38 }
39 if len(queue) != readbackQueueSize {
40 t.Fatalf("queue grew: %d", len(queue))
41 }
42}
43
44func TestReadbackWorkerCountsWriteErrors(t *testing.T) {
45 s := &Session{
46 debugDir: filepath.Join(t.TempDir(), "missing"),
47 readbacks: make(chan readbackJob, readbackQueueSize),
48 readbackDone: make(chan struct{}),
49 debugWritten: make(chan uint64, maxDebugPNGs),
50 }
51 go s.readbackWorker()
52 s.readbacks <- readbackJob{1, image.NewNRGBA(image.Rect(0, 0, 1, 1))}
53 close(s.readbacks)
54 <-s.readbackDone
55 if s.debugWriteErrors != 1 || s.debugLastWriteErr == "" || len(s.debugWritten) != 0 {
56 t.Fatalf("errors=%d last=%q written=%d", s.debugWriteErrors, s.debugLastWriteErr, len(s.debugWritten))
57 }
58}
59
60// saveReadback is called only after beginReady/retire see Ready(); it has no
61// Frame.Wait path, even if a PNG is pending. The budget prevents new copies.
62func TestNoReadbackAfterLimit(t *testing.T) {
63 s := &Session{readbacks: make(chan readbackJob, readbackQueueSize), debugFrames: maxDebugPNGs}
64 if s.wantReadback() {
65 t.Fatal("readback enabled at limit")
66 }
67 s.debugFrames = 0
68 s.Slots = map[uint64]*Slot{1: {ReadbackPending: true}, 2: {ReadbackPending: true}}
69 for i := uint64(0); i < maxDebugPNGs-2; i++ {
70 s.debugFrames++
71 }
72 if s.wantReadback() {
73 t.Fatal("pending readbacks ignored")
74 }
75}