1package daemon
2
3import (
4 "testing"
5
6 "github.com/bnema/vev/internal/domain"
7 "github.com/bnema/vev/internal/domain/layout"
8 "github.com/stretchr/testify/require"
9)
10
11func TestPaneOwnerPublicationAdvancesGenerationAndInvalidatesLease(t *testing.T) {
12 p := newPaneWithStableID(layout.PaneID("pane-1"), "p_stable", nil, domain.Size{Cols: 80, Rows: 23})
13 firstSession := &session{sessionCore: sessionCore{id: "first"}}
14 firstTab := newTab(nil, domain.Size{Cols: 80, Rows: 23})
15 secondSession := &session{sessionCore: sessionCore{id: "second"}}
16 secondTab := newTab(nil, domain.Size{Cols: 80, Rows: 23})
17
18 p.mu.Lock()
19 oldLease, _ := p.publishOwnerLocked(firstSession, firstTab, 0)
20 firstLease := p.effectLeaseLocked()
21 p.mu.Unlock()
22 require.False(t, oldLease.Current())
23 require.True(t, firstLease.Current())
24 require.Equal(t, uint64(1), firstLease.owner.generation)
25 require.Same(t, firstSession, firstLease.owner.session)
26 require.Same(t, firstTab, firstLease.owner.tab)
27
28 p.mu.Lock()
29 retiredLease, _ := p.publishOwnerLocked(secondSession, secondTab, 0)
30 secondLease := p.effectLeaseLocked()
31 p.mu.Unlock()
32 require.Equal(t, firstLease, retiredLease)
33 require.False(t, firstLease.Current())
34 require.True(t, secondLease.Current())
35 require.Equal(t, uint64(2), secondLease.owner.generation)
36 require.Equal(t, "p_stable", p.stableID, "owner publication must preserve stable pane identity")
37
38 p.mu.Lock()
39 clearedLease := p.clearOwnerLocked()
40 p.mu.Unlock()
41 require.Equal(t, secondLease, clearedLease)
42 require.False(t, secondLease.Current())
43 require.Nil(t, p.ownerSnapshot())
44 require.Equal(t, "p_stable", p.stableID, "terminal owner clearing must preserve stable pane identity")
45 // Leases retain immutable owner records even after later publication and
46 // terminal clearing.
47 require.Same(t, firstSession, firstLease.owner.session)
48 require.Same(t, firstTab, firstLease.owner.tab)
49 require.Equal(t, uint64(1), firstLease.owner.generation)
50}
51
52func TestFloatingPaneOwnerLeaseRequiresCurrentSlotGeneration(t *testing.T) {
53 p := newPaneWithStableID(layout.PaneID("floating"), "p_float", nil, domain.Size{Cols: 20, Rows: 8})
54 sess := &session{sessionCore: sessionCore{id: "owner"}}
55 tb := newTab(nil, domain.Size{Cols: 80, Rows: 23})
56
57 tb.mu.Lock()
58 generation := tb.beginFloatingWarmLocked(true)
59 p.mu.Lock()
60 p.publishOwnerLocked(sess, tb, generation)
61 lease := p.effectLeaseLocked()
62 p.mu.Unlock()
63 require.True(t, tb.installFloatingLocked(p, generation))
64 tb.mu.Unlock()
65 require.True(t, lease.Current())
66
67 tb.mu.Lock()
68 tb.floating.generation++
69 tb.mu.Unlock()
70 require.False(t, lease.Current(), "a reused floating slot must reject the old pane effect lease")
71 require.Equal(t, "p_float", p.stableID)
72}
73
74func TestPublishTiledPaneOwnersInitializesAllPanesBeforePublication(t *testing.T) {
75 sess := &session{sessionCore: sessionCore{id: "owner"}}
76 tb := newTabWithStableID("t_stable", "p_one", nil, domain.Size{Cols: 80, Rows: 23})
77 second := newPaneWithStableID("pane-2", "p_two", nil, domain.Size{Cols: 40, Rows: 23})
78 tb.panes[second.id] = second
79
80 publishTiledPaneOwners(sess, tb)
81
82 for _, p := range []*pane{tb.panes["pane-1"], second} {
83 owner := p.ownerSnapshot()
84 require.NotNil(t, owner)
85 require.Same(t, sess, owner.session)
86 require.Same(t, tb, owner.tab)
87 require.Equal(t, uint64(1), owner.generation)
88 require.Zero(t, owner.floatingSlotGeneration)
89 }
90 require.Equal(t, "p_one", tb.panes["pane-1"].stableID)
91 require.Equal(t, "p_two", second.stableID)
92}