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