attachment_route_identity_test.go RawHistoryFolder
1package daemon
2
3import (
4 "errors"
5 "testing"
6
7 "github.com/bnema/vev/internal/domain"
8 "github.com/bnema/vev/internal/ports"
9 "github.com/stretchr/testify/require"
10)
11
12type committedIdentityErrorTransport struct {
13 closeTrackingTransport
14}
15
16func (t *committedIdentityErrorTransport) Send(frame ports.Frame) error {
17 if frame.Type == ports.MsgCommittedRouteIdentity {
18 return errors.New("committed identity send failed")
19 }
20 return t.closeTrackingTransport.Send(frame)
21}
22
23func TestAttachmentTransitionPublishesCommittedRouteIdentity(t *testing.T) {
24 d, source, ac, _ := newManualSessionWithPTYs(t, nil)
25 transport := &closeTrackingTransport{}
26 ac.replaceTransport(transport)
27 rc := d.attachCoordinator(source, nil, ac, true)
28 token := source.attachmentToken(ac, transport)
29 token.lease = rc.attachmentLease(ac)
30 ac.publishAttachmentCapability(token)
31 ac.setRouteSnapshot(ports.RecentRouteSnapshot{Generation: 1})
32
33 target := &session{
34 sessionCore: sessionCore{
35 id: "target",
36 name: "target",
37 incarnation: domain.IncarnationID{2},
38 },
39 ctx: source.ctx,
40 cancel: func() {},
41 tabs: []*tab{newTab(nil, domain.Size{Cols: 80, Rows: 23})},
42 }
43 d.mu.Lock()
44 d.sessions[target.id] = target
45 d.mu.Unlock()
46
47 transition, err := d.transitionAttachment(attachmentTransitionRequest{
48 source: source,
49 target: target,
50 next: ac,
51 expectedTransport: transportSnapshot{transport: transport, incarnation: ac.transportSnapshot().incarnation},
52 ready: true,
53 })
54 require.NoError(t, err)
55 d.deferAttachmentTransitionCleanups(transition)
56
57 var identity ports.CommittedRouteIdentity
58 found := false
59 for _, frame := range transport.Sends() {
60 if frame.Type != ports.MsgCommittedRouteIdentity {
61 continue
62 }
63 var decodeErr error
64 identity, decodeErr = ports.UnmarshalCommittedRouteIdentity(frame.Payload)
65 require.NoError(t, decodeErr)
66 found = true
67 }
68 require.True(t, found, "attachment transitions must publish their committed route identity")
69 require.Equal(t, "target", identity.Target.SessionName)
70 require.Equal(t, domain.IncarnationID{2}, identity.Target.LifecycleID)
71}
72
73func TestAttachmentTransitionTearsDownAfterCommittedIdentitySendFailure(t *testing.T) {
74 d, source, ac, _ := newManualSessionWithPTYs(t, nil)
75 transport := &committedIdentityErrorTransport{}
76 ac.replaceTransport(transport)
77 rc := d.attachCoordinator(source, nil, ac, true)
78 token := source.attachmentToken(ac, transport)
79 token.lease = rc.attachmentLease(ac)
80 ac.publishAttachmentCapability(token)
81 ac.setRouteSnapshot(ports.RecentRouteSnapshot{Generation: 1})
82
83 target := &session{
84 sessionCore: sessionCore{
85 id: "target",
86 name: "target",
87 incarnation: domain.IncarnationID{2},
88 },
89 ctx: source.ctx,
90 cancel: func() {},
91 tabs: []*tab{newTab(nil, domain.Size{Cols: 80, Rows: 23})},
92 }
93 d.mu.Lock()
94 d.sessions[target.id] = target
95 d.mu.Unlock()
96
97 _, err := d.transitionAttachment(attachmentTransitionRequest{
98 source: source,
99 target: target,
100 next: ac,
101 expectedTransport: transportSnapshot{transport: transport, incarnation: ac.transportSnapshot().incarnation},
102 ready: true,
103 })
104 require.ErrorContains(t, err, "committed identity send failed")
105 require.Empty(t, target.snapshotAttachments())
106 require.Empty(t, source.snapshotAttachments())
107 require.True(t, transport.Closed())
108}