1package app
2
3import (
4 "context"
5 "testing"
6
7 portsmocks "github.com/bnema/neferwl/internal/mocks/ports"
8 "github.com/bnema/neferwl/internal/ports"
9)
10
11// Wayland feeds a started output its contents: Attach comes after the
12// output registered and got its security state, the output runs on what
13// Attach returned, Detach follows its end, and a restarted connector attaches
14// again.
15func TestOutputSetAttachesAndDetachesContents(t *testing.T) {
16 ctx, cancel := context.WithCancel(context.Background())
17 defer cancel()
18 set := newOutputSet(ctx, nil)
19 events := make(chan ports.SecurityBackendEvent, 4)
20 set.wireSecurity(outputChannels{securityEvents: events})
21 attacher := newMockcontentAttacher(t)
22 set.attach = attacher
23 ret := portsmocks.NewMockContentReturn(t)
24 feed := make(chan *ports.ContentBatch, 1)
25 var order []string
26 type seen struct {
27 contents <-chan *ports.ContentBatch
28 returns ports.ContentReturn
29 security ports.SecurityState
30 }
31 started := make(chan seen, 2)
32 run := func(ctx context.Context, _ <-chan ports.Scene, contents <-chan *ports.ContentBatch, returns ports.ContentReturn, _ <-chan ports.CursorChange, _ <-chan ports.CaptureRequest, security <-chan ports.SecurityState, _ ports.OutputInstance) error {
33 started <- seen{contents, returns, <-security}
34 <-ctx.Done()
35 return nil
36 }
37 attacher.EXPECT().AttachOutput("DP-1").RunAndReturn(func(string) (<-chan *ports.ContentBatch, ports.ContentReturn) {
38 order = append(order, "attach")
39 // The output is registered with the security backend first.
40 if len(events) != 1 {
41 t.Errorf("attached with %d registrations queued, want 1", len(events))
42 }
43 return feed, ret
44 }).Times(2)
45 attacher.EXPECT().DetachOutput("DP-1").Run(func(string) { order = append(order, "detach") }).Times(2)
46 for round := range 2 {
47 if !set.start(ctx, "DP-1", run) {
48 t.Fatal("start failed")
49 }
50 got := <-started
51 if got.contents != (<-chan *ports.ContentBatch)(feed) || got.returns != ports.ContentReturn(ret) {
52 t.Fatalf("round %d: output got another feed", round)
53 }
54 <-events
55 set.outs["DP-1"].stop()
56 if err := set.finish("DP-1"); err != nil {
57 t.Fatal(err)
58 }
59 }
60 want := []string{"attach", "detach", "attach", "detach"}
61 if len(order) != len(want) {
62 t.Fatalf("order %v, want %v", order, want)
63 }
64 for i := range want {
65 if order[i] != want[i] {
66 t.Fatalf("order %v, want %v", order, want)
67 }
68 }
69}
70
71// wait detaches the outputs it stops.
72func TestOutputSetWaitDetachesContents(t *testing.T) {
73 ctx, cancel := context.WithCancel(context.Background())
74 defer cancel()
75 set := newOutputSet(ctx, nil)
76 attacher := newMockcontentAttacher(t)
77 set.attach = attacher
78 attacher.EXPECT().AttachOutput("A").Return(nil, nil).Once()
79 attacher.EXPECT().DetachOutput("A").Return().Once()
80 set.start(ctx, "A", func(ctx context.Context, _ <-chan ports.Scene, _ <-chan *ports.ContentBatch, _ ports.ContentReturn, _ <-chan ports.CursorChange, _ <-chan ports.CaptureRequest, _ <-chan ports.SecurityState, _ ports.OutputInstance) error {
81 <-ctx.Done()
82 return nil
83 })
84 if err := set.wait(); err != nil {
85 t.Fatal(err)
86 }
87}