1package protoconv
2
3import (
4 "strings"
5 "testing"
6
7 "github.com/bnema/vev/internal/domain"
8 "github.com/bnema/vev/internal/ports"
9 "github.com/bnema/vev/internal/protocol"
10 "github.com/bnema/vev/internal/protocol/catalogue"
11 "github.com/bnema/vev/internal/protocol/wire"
12 "github.com/stretchr/testify/require"
13)
14
15func TestBrokerConversionRoundTrips(t *testing.T) {
16 registration := domain.RemoteRegistration{Endpoint: "dev@host:22", Incarnation: [16]byte{1, 2, 3}, Generation: 9}
17 target := protocol.ExactSessionTarget{LifecycleID: domain.SessionLifecycleID{1, 2, 3}, SessionName: "work"}
18 policy := ports.BrokerPolicy{ProtocolVersion: protocol.Version, CatalogSchemaVersion: catalogue.RemoteCatalogSchemaVersion, EnvironmentPolicy: protocol.EnvironmentPolicyDaemonOwned, Transport: "quic", Trust: "pinned", Launch: "agent", Isolation: "user"}
19 for _, tc := range []struct {
20 name string
21 run func(*testing.T)
22 }{
23 {"registration", func(t *testing.T) {
24 encoded := BrokerRegistrationToWire(registration)
25 got, err := BrokerRegistrationFromWire(encoded)
26 require.NoError(t, err)
27 require.Equal(t, registration, got)
28 encoded.Incarnation[0] = 0
29 require.Equal(t, byte(1), registration.Incarnation[0])
30 }},
31 {"target", func(t *testing.T) {
32 encoded := BrokerExactTargetToWire(target)
33 got, err := BrokerExactTargetFromWire(encoded)
34 require.NoError(t, err)
35 require.Equal(t, target, got)
36 encoded.LifecycleId.Value[0] = 0
37 require.Equal(t, byte(1), target.LifecycleID[0])
38 }},
39 {"policy", func(t *testing.T) {
40 got, err := BrokerPolicyFromWire(BrokerPolicyToWire(policy))
41 require.NoError(t, err)
42 require.Equal(t, policy, got)
43 }},
44 } {
45 t.Run(tc.name, tc.run)
46 }
47}
48
49func TestBrokerStartModeCodes(t *testing.T) {
50 for _, tc := range []struct {
51 name string
52 mode ports.BrokerDaemonStartMode
53 code uint32
54 valid bool
55 }{
56 {"existing", ports.BrokerDaemonExistingOnly, 1, true},
57 {"spawn", ports.BrokerDaemonStartIfNeeded, 2, true},
58 {"absent", 0, 0, false},
59 {"unknown", 3, 3, false},
60 {"aliased", 0, 257, false},
61 } {
62 t.Run(tc.name, func(t *testing.T) {
63 code, encodeErr := BrokerStartModeToWire(tc.mode)
64 mode, decodeErr := BrokerStartModeFromWire(tc.code)
65 if !tc.valid {
66 require.ErrorIs(t, encodeErr, ErrOutOfRange)
67 require.ErrorIs(t, decodeErr, ErrOutOfRange)
68 return
69 }
70 require.NoError(t, encodeErr)
71 require.NoError(t, decodeErr)
72 require.Equal(t, tc.code, code)
73 require.Equal(t, tc.mode, mode)
74 })
75 }
76}
77
78func TestBrokerConversionFailures(t *testing.T) {
79 for _, tc := range []struct {
80 name string
81 run func() error
82 want error
83 }{
84 {"nil registration", func() error { _, err := BrokerRegistrationFromWire(nil); return err }, ErrOutOfRange},
85 {"short incarnation", func() error {
86 _, err := BrokerRegistrationFromWire(&wire.RemoteRegistration{Endpoint: "dev@host:22", Incarnation: []byte{1}, Generation: 1})
87 return err
88 }, ErrOutOfRange},
89 {"nil target", func() error { _, err := BrokerExactTargetFromWire(nil); return err }, ErrOutOfRange},
90 {"nil policy", func() error { _, err := BrokerPolicyFromWire(nil); return err }, ErrOutOfRange},
91 {"policy narrowing", func() error {
92 _, err := BrokerPolicyFromWire(&wire.BrokerWirePolicy{ProtocolVersion: 1<<16 + uint32(protocol.Version)})
93 return err
94 }, ErrOutOfRange},
95 {"policy validation", func() error { _, err := BrokerPolicyFromWire(&wire.BrokerWirePolicy{}); return err }, ErrInvalid},
96 {"oversize text", func() error { return BrokerDisplayText("abc", 2) }, ErrTooLarge},
97 {"bidi text", func() error { return BrokerDisplayText("a\u202eb", 20) }, ErrInvalid},
98 {"invalid utf8", func() error { return BrokerDisplayText("\xff", 20) }, ErrInvalid},
99 {"oversize env", func() error { return BrokerEnvEntries([]string{strings.Repeat("a", ports.BrokerMaxEnvEntryBytes+1)}) }, ErrTooLarge},
100 {"missing equals", func() error { return BrokerEnvEntries([]string{"TERM"}) }, ErrInvalid},
101 {"nul env", func() error { return BrokerEnvEntries([]string{"A=x\x00y"}) }, ErrInvalid},
102 {"ansi prompt env", func() error { return BrokerEnvEntries([]string{"PS1=\x1b[32m$ \x1b[0m"}) }, nil},
103 {"valid env", func() error { return BrokerEnvEntries([]string{"TERM=x"}) }, nil},
104 } {
105 t.Run(tc.name, func(t *testing.T) {
106 err := tc.run()
107 if tc.want == nil {
108 require.NoError(t, err)
109 } else {
110 require.ErrorIs(t, err, tc.want)
111 }
112 })
113 }
114}