1package daemon
2
3import (
4 "testing"
5
6 "github.com/bnema/vev/internal/adapters/sessionwire"
7 "github.com/bnema/vev/internal/protocol"
8 "github.com/stretchr/testify/require"
9)
10
11func TestUIActionNavigationUsesAdmittedCause(t *testing.T) {
12 for _, actionID := range []uint64{0, 17} {
13 for _, message := range []protocol.ServerMessage{
14 protocol.AttachTarget{CauseActionID: 999, Session: "destination", Intent: protocol.IntentAttach},
15 protocol.RouteNavigationAction{CauseActionID: 999, SnapshotGeneration: 1, Key: 2, Generation: 3},
16 protocol.RouteCreateSessionAction{CauseActionID: 999, RequestID: 1, SnapshotGeneration: 2, Key: 3, Generation: 4, SessionName: "new"},
17 } {
18 t.Run(testNavigationName(message, actionID), func(t *testing.T) {
19 _, sess, ac, sends := newManualSessionWithPTYs(t, nil)
20 effect, ok := ac.beginAttachmentEffect(captureAttachmentCapability(sess, ac, ac.transport()))
21 require.True(t, ok)
22 t.Cleanup(effect.End)
23 effect.uiActionID = actionID
24 require.NoError(t, effect.sendControl(message))
25 frame := awaitTestValue(t, sends, "navigation was not sent")
26 require.Equal(t, actionID, testNavigationCause(t, frame.Payload))
27 original, err := testServerEnvelope(message)
28 require.NoError(t, err)
29 require.Equal(t, uint64(999), testNavigationCause(t, original.Payload), "sending must not mutate reusable navigation templates")
30 })
31 }
32 }
33}
34
35func testNavigationName(message protocol.ServerMessage, actionID uint64) string {
36 name := "human/"
37 if actionID != 0 {
38 name = "automation/"
39 }
40 switch message.(type) {
41 case protocol.AttachTarget:
42 return name + "attach"
43 case protocol.RouteNavigationAction:
44 return name + "recent"
45 default:
46 return name + "create"
47 }
48}
49
50func testNavigationCause(t *testing.T, payload []byte) uint64 {
51 t.Helper()
52 message, err := sessionwire.DecodeServerEnvelope(payload)
53 require.NoError(t, err)
54 switch message := message.(type) {
55 case protocol.AttachTarget:
56 return message.CauseActionID
57 case protocol.RouteNavigationAction:
58 return message.CauseActionID
59 case protocol.RouteCreateSessionAction:
60 return message.CauseActionID
61 default:
62 t.Fatalf("unexpected navigation message %T", message)
63 return 0
64 }
65}
66
67func TestUIActionInputPaletteSubmissionCarriesItsOwnCause(t *testing.T) {
68 d, sess, ac, sends := newManualSessionWithPTYs(t, nil)
69 rc := d.attachCoordinator(sess, nil, ac, true)
70 t.Cleanup(func() { rc.beginSessionTeardown().finish(); rc.waitForTimerWorkers() })
71 ac.setRouteSnapshot(protocol.RecentRouteSnapshot{
72 Generation: 9, Active: protocol.RouteRef{Key: 1, Generation: 1},
73 ActiveEntry: testRouteEntry(1, 1, sess.name, 1, protocol.RouteKindLocal),
74 Entries: []protocol.RecentRouteEntry{{Key: 8, Generation: 4, Target: testRouteTarget("logs", 8), Name: "logs", HostLabel: "edge", Kind: protocol.RouteKindRemote}},
75 })
76 for _, input := range []protocol.Input{
77 {ActionID: 40, Data: []byte("\x1b ")},
78 {ActionID: 41, Data: []byte("logs@edge\r")},
79 } {
80 require.False(t, d.handleAttachmentClientMessage(captureAttachmentCapability(sess, ac, ac.transport()), input))
81 }
82 frame := awaitFrame(t, sends, "RouteNavigationAction")
83 require.Equal(t, uint64(41), testNavigationCause(t, frame.Payload), "submission owns navigation, not the earlier palette-opening action")
84}