]> git.giacomolli.uk - onehouse/blob - protocol/address_test.go
Queue device commands and replay first results
[onehouse] / protocol / address_test.go
1 package protocol
2
3 import (
4 "strings"
5 "testing"
6
7 "github.com/stretchr/testify/require"
8 )
9
10 const (
11 deviceID = "01ARZ3NDEKTSV4RRFFQ69G5FAV"
12 messageID = "01ARZ3NDEKTSV4RRFFQ69G5FAW"
13 commandID = "01ARZ3NDEKTSV4RRFFQ69G5FAX"
14 )
15
16 func TestAddressRoundTrip(t *testing.T) {
17 testCases := []struct {
18 name string
19 kind Kind
20 target string
21 suffix string
22 }{
23 {
24 name: "routes metadata",
25 kind: Descriptor,
26 suffix: "descriptor",
27 },
28 {
29 name: "routes reachability",
30 kind: Availability,
31 suffix: "availability",
32 },
33 {
34 name: "routes retained values",
35 kind: Reported,
36 target: "relay.1",
37 suffix: "reported/relay.1",
38 },
39 {
40 name: "routes samples",
41 kind: Telemetry,
42 target: "power",
43 suffix: "telemetry/power",
44 },
45 {
46 name: "routes occurrences",
47 kind: Event,
48 target: "press",
49 suffix: "events/press",
50 },
51 {
52 name: "routes requests",
53 kind: Command,
54 target: "relay",
55 suffix: "commands/relay",
56 },
57 {
58 name: "routes ordered requests",
59 kind: CommandBatch,
60 suffix: "commands/$batch",
61 },
62 {
63 name: "routes outcomes",
64 kind: Result,
65 target: commandID,
66 suffix: "results/" + commandID,
67 },
68 {
69 name: "routes hub diagnostics",
70 kind: HubStatus,
71 suffix: "status",
72 },
73 }
74
75 for _, tc := range testCases {
76 t.Run(tc.name, func(t *testing.T) {
77 address := Address{
78 Kind: tc.kind,
79 ID: deviceID,
80 Target: tc.target,
81 }
82 topic, err := address.topic()
83 require.NoError(t, err)
84
85 expected := Root + "/devices/" + deviceID + "/" + tc.suffix
86 if tc.kind == HubStatus {
87 expected = Root + "/zigbee/hubs/" + deviceID + "/status"
88 }
89
90 require.Equal(t, expected, topic)
91
92 parsed, err := parseTopic(topic)
93 require.NoError(t, err)
94 require.Equal(t, address, parsed)
95 })
96 }
97 }
98
99 func TestParseTopicRejectsMalformedAddresses(t *testing.T) {
100 testCases := []string{
101 "", "onehouse/v2/devices/" + deviceID + "/descriptor",
102 Root + "/devices/" + strings.ToLower(deviceID) + "/descriptor",
103 Root + "/devices/" + deviceID + "/descriptor/extra",
104 Root + "/devices/" + deviceID + "/reported",
105 Root + "/devices/" + deviceID + "/reported/",
106 Root + "/devices/" + deviceID + "/reported/+",
107 Root + "/devices/" + deviceID + "/events/door--open",
108 Root + "/devices/" + deviceID + "/commands/$other",
109 Root + "/devices/" + deviceID + "/results/not-an-id",
110 Root + "/devices/" + deviceID + "/status",
111 Root + "/zigbee/hubs/" + deviceID + "/status/extra",
112 Root + "/devices/" + deviceID + "/unknown",
113 }
114
115 for _, tc := range testCases {
116 _, err := parseTopic(tc)
117 require.Error(t, err, tc)
118 }
119 }
120
121 func TestSubscriptionsSelectOnlyTheirDirection(t *testing.T) {
122 filters := CoreSubscriptions()
123 require.Len(t, filters, 6)
124 require.Equal(t, Subscription{
125 Filter: Root + "/devices/+/telemetry/+",
126 QoS: 0,
127 }, filters[3])
128
129 for index, filter := range filters {
130 require.NotContains(t, filter.Filter, "commands")
131
132 if index != 3 {
133 require.Equal(t, byte(1), filter.QoS)
134 }
135 }
136
137 subscription, err := CommandSubscription(deviceID)
138 require.NoError(t, err)
139 require.Equal(t, Root+"/devices/"+deviceID+"/commands/+", subscription.Filter)
140 require.Equal(t, byte(1), subscription.QoS)
141
142 _, err = CommandSubscription("+")
143 require.Error(t, err)
144 require.Equal(t, Root+"/zigbee/hubs/+/status", HubStatusSubscription().Filter)
145 }