1package app
2
3import (
4 "context"
5 "os"
6 "testing"
7
8 "github.com/bnema/neferwl/internal/adapters/logging"
9 "github.com/bnema/neferwl/internal/ports"
10)
11
12func leaseRig(t *testing.T, active, protected *bool) (*leasePublisher, chan ports.LeaseMessage, *mockleaseInventoryCard) {
13 t.Helper()
14 events := make(chan ports.LeaseMessage, 8)
15 p := newLeasePublisher(context.Background(), events, func() bool { return *active }, func() bool { return *protected }, logging.For(context.Background(), "app"))
16 t.Cleanup(p.close)
17 card := newMockleaseInventoryCard(t)
18 card.EXPECT().Path().Return("/dev/dri/card0").Maybe()
19 return p, events, card
20}
21
22func clientFile(t *testing.T) *os.File {
23 t.Helper()
24 f, err := os.CreateTemp(t.TempDir(), "card")
25 if err != nil {
26 t.Fatal(err)
27 }
28 return f
29}
30
31// An inventory is sent once per change, each with its own fd, and finished
32// leases go first.
33func TestLeasePublisherSendsChangesOnly(t *testing.T) {
34 active, protected := true, false
35 p, events, card := leaseRig(t, &active, &protected)
36 connectors := []ports.LeaseConnector{{Name: "HDMI-A-1"}}
37 card.EXPECT().FinishedLeases().Return([]uint32{7}).Once()
38 card.EXPECT().FinishedLeases().Return(nil)
39 card.EXPECT().Leasable().Return(connectors)
40 card.EXPECT().ClientFD().Return(clientFile(t), nil).Once()
41
42 p.publish(card)
43 if fin, ok := (<-events).(ports.LeaseFinished); !ok || fin.LeaseID != 7 {
44 t.Fatalf("finished lease first: %+v", fin)
45 }
46 inv, ok := (<-events).(ports.LeaseConnectors)
47 if !ok || inv.Device == nil || len(inv.Connectors) != 1 {
48 t.Fatalf("inventory: %+v", inv)
49 }
50 defer inv.Device.Close()
51 if inv.Device.Fd() == p.clientFDs[card].Fd() {
52 t.Fatal("message shares the publisher's fd")
53 }
54 p.publish(card)
55 if len(events) != 0 {
56 t.Fatalf("unchanged inventory resent: %+v", <-events)
57 }
58}
59
60// Protection withdraws the inventory and closes the client fd, even when
61// nothing was offered before.
62func TestLeasePublisherProtectedWithdraws(t *testing.T) {
63 active, protected := true, true
64 p, events, card := leaseRig(t, &active, &protected)
65 card.EXPECT().FinishedLeases().Return(nil)
66 p.publish(card)
67 if inv, ok := (<-events).(ports.LeaseConnectors); !ok || inv.Device != nil || len(inv.Connectors) != 0 {
68 t.Fatalf("protected inventory: %+v", inv)
69 }
70
71 protected = false
72 card.EXPECT().Leasable().Return([]ports.LeaseConnector{{Name: "DP-2"}}).Once()
73 card.EXPECT().ClientFD().Return(clientFile(t), nil).Once()
74 p.publish(card)
75 inv := (<-events).(ports.LeaseConnectors)
76 inv.Device.Close()
77 held := p.clientFDs[card]
78
79 active = false // an inactive seat withdraws what was offered
80 p.publish(card)
81 if inv, ok := (<-events).(ports.LeaseConnectors); !ok || inv.Device != nil {
82 t.Fatalf("withdrawn inventory: %+v", inv)
83 }
84 if _, err := held.Stat(); err == nil {
85 t.Fatal("client fd kept after withdrawal")
86 }
87 if p.clientFDs[card] != nil {
88 t.Fatal("client fd still tracked")
89 }
90}