1package daemonmux
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/require"
7
8 "github.com/bnema/vev/internal/ports"
9 "github.com/bnema/vev/internal/protocol"
10)
11
12// TestServerBindingValidatesAndExposesAuthority proves the immutable binding
13// rejects every invalid field once, at construction, and exposes exactly the
14// validated authority through its accessors.
15func TestServerBindingValidatesAndExposesAuthority(t *testing.T) {
16 binding, err := NewServerBinding(testIdentity(), testIncarnation(), testPolicy())
17 require.NoError(t, err)
18 require.NoError(t, binding.Validate())
19 require.Equal(t, testIdentity(), binding.Identity())
20 require.Equal(t, testIncarnation(), binding.Incarnation())
21 require.Equal(t, testPolicy(), binding.Policy())
22}
23
24// TestServerBindingRefusesInvalidAuthority proves an empty identity, a zero
25// incarnation, and every invalid policy shape are refused with the binding's
26// single sentinel.
27func TestServerBindingRefusesInvalidAuthority(t *testing.T) {
28 invalidPolicy := testPolicy()
29 invalidPolicy.ProtocolVersion = 0
30
31 tests := []struct {
32 name string
33 identity ports.BrokerDaemonIdentity
34 incarnation ports.BrokerDaemonIncarnation
35 policy ports.BrokerPolicy
36 }{
37 {name: "empty identity", identity: "", incarnation: testIncarnation(), policy: testPolicy()},
38 {name: "zero incarnation", identity: testIdentity(), incarnation: ports.BrokerDaemonIncarnation{}, policy: testPolicy()},
39 {name: "zero policy", identity: testIdentity(), incarnation: testIncarnation(), policy: ports.BrokerPolicy{}},
40 {name: "policy without protocol version", identity: testIdentity(), incarnation: testIncarnation(), policy: invalidPolicy},
41 }
42 for _, test := range tests {
43 t.Run(test.name, func(t *testing.T) {
44 _, err := NewServerBinding(test.identity, test.incarnation, test.policy)
45 require.ErrorIs(t, err, ErrInvalidBinding)
46 })
47 }
48}
49
50// TestServerBindingAcceptsOnlyExactPolicy proves the binding accepts the exact
51// policy and refuses a request differing in a single field.
52func TestServerBindingAcceptsOnlyExactPolicy(t *testing.T) {
53 binding, err := NewServerBinding(testIdentity(), testIncarnation(), testPolicy())
54 require.NoError(t, err)
55 require.True(t, binding.Accepts(testPolicy()))
56
57 tests := []struct {
58 name string
59 mutate func(*ports.BrokerPolicy)
60 }{
61 {name: "protocol version", mutate: func(p *ports.BrokerPolicy) { p.ProtocolVersion++ }},
62 {name: "catalogue schema version", mutate: func(p *ports.BrokerPolicy) { p.CatalogSchemaVersion++ }},
63 {name: "environment policy", mutate: func(p *ports.BrokerPolicy) {
64 p.EnvironmentPolicy = protocol.EnvironmentPolicyClientOwned
65 }},
66 {name: "transport", mutate: func(p *ports.BrokerPolicy) { p.Transport = "stdio" }},
67 {name: "trust", mutate: func(p *ports.BrokerPolicy) { p.Trust = "tofu" }},
68 {name: "launch", mutate: func(p *ports.BrokerPolicy) { p.Launch = "manual" }},
69 {name: "isolation", mutate: func(p *ports.BrokerPolicy) { p.Isolation = "system" }},
70 }
71 for _, test := range tests {
72 t.Run(test.name, func(t *testing.T) {
73 requested := testPolicy()
74 test.mutate(&requested)
75 require.False(t, binding.Accepts(requested))
76 })
77 }
78}
79
80// TestServerBindingIsImmutable proves the binding copied its inputs at
81// construction: mutating the caller's local policy afterwards never changes
82// what the binding enforces.
83func TestServerBindingIsImmutable(t *testing.T) {
84 local := testPolicy()
85 binding, err := NewServerBinding(testIdentity(), testIncarnation(), local)
86 require.NoError(t, err)
87
88 local.Transport = "mutated"
89 local.Trust = "mutated"
90 require.Equal(t, testPolicy(), binding.Policy())
91 require.True(t, binding.Accepts(testPolicy()))
92}