1package headless
2
3import (
4 "context"
5 "testing"
6 "time"
7
8 "github.com/bnema/neferwl/internal/ports"
9 "github.com/stretchr/testify/require"
10)
11
12// runWithFrames runs an output with a frames channel of the given size and
13// returns what it needs to feed scenes and stop it.
14func runWithFrames(t *testing.T, size int) (scenes chan ports.Scene, frames chan ports.OutputFrame, f *frames, stop func()) {
15 t.Helper()
16 scenes = make(chan ports.Scene, 8)
17 frames = make(chan ports.OutputFrame, size)
18 r, rec := recordingRenderer(t, nil)
19 sink, _ := presentedSink(t, 16)
20 ctx, cancel := context.WithCancel(context.Background())
21 done := make(chan error, 1)
22 go func() {
23 done <- Run(ctx, Options{Width: 2, Height: 2, Name: "HEADLESS-1", Presented: sink, Frames: frames,
24 NewRenderer: func(int, int) (ports.Renderer, error) { return r, nil }}, scenes, nil, nil, nil, nil)
25 }()
26 return scenes, frames, rec, func() {
27 cancel()
28 require.NoError(t, <-done)
29 }
30}
31
32// The presentation of an animating scene tells core the next frame is due;
33// the one of a settled scene does not.
34func TestAnimatingSceneSendsFrame(t *testing.T) {
35 scenes, frames, rec, stop := runWithFrames(t, 4)
36 defer stop()
37
38 scenes <- ports.Scene{Seq: 1, OutputWidth: 2, OutputHeight: 2, Animating: true}
39 select {
40 case got := <-frames:
41 require.Equal(t, ports.OutputFrame{Output: "HEADLESS-1"}, got)
42 case <-time.After(3 * time.Second):
43 t.Fatal("no frame for an animating scene")
44 }
45
46 // The scene an animation settles on: drawn, nobody woken.
47 scenes <- ports.Scene{Seq: 2, OutputWidth: 2, OutputHeight: 2}
48 waitFrames(t, rec, 2)
49 // A third scene is drawn after the settled one (the owner handles scenes
50 // in order): had the settled frame woken core, its frame precedes the
51 // third's in the channel.
52 scenes <- ports.Scene{Seq: 3, OutputWidth: 2, OutputHeight: 2}
53 waitFrames(t, rec, 3)
54 require.Empty(t, frames)
55}
56
57// A frames channel core has not read stays full: the owner never waits.
58func TestAnimatingFramesNeverBlock(t *testing.T) {
59 scenes, frames, rec, stop := runWithFrames(t, 1)
60 defer stop()
61 for seq := uint64(1); seq <= 3; seq++ {
62 scenes <- ports.Scene{Seq: seq, OutputWidth: 2, OutputHeight: 2, Animating: true}
63 waitFrames(t, rec, int(seq))
64 }
65 require.Len(t, frames, 1)
66}