]>
Commit | Line | Data |
---|---|---|
6988a057 JH |
1 | package hotline |
2 | ||
3 | import ( | |
a2ef262a | 4 | "bytes" |
8ff2b66d JH |
5 | "fmt" |
6 | "github.com/stretchr/testify/assert" | |
a2ef262a | 7 | "github.com/stretchr/testify/require" |
9a75b7cb | 8 | "io" |
6988a057 JH |
9 | "reflect" |
10 | "testing" | |
11 | ) | |
12 | ||
13 | func TestTrackerRegistration_Payload(t *testing.T) { | |
14 | type fields struct { | |
40414f92 | 15 | Port [2]byte |
6988a057 | 16 | UserCount int |
9a75b7cb | 17 | PassID [4]byte |
6988a057 JH |
18 | Name string |
19 | Description string | |
20 | } | |
21 | tests := []struct { | |
22 | name string | |
23 | fields fields | |
24 | want []byte | |
25 | }{ | |
26 | { | |
27 | name: "returns expected payload bytes", | |
28 | fields: fields{ | |
40414f92 | 29 | Port: [2]byte{0x00, 0x10}, |
6988a057 | 30 | UserCount: 2, |
9a75b7cb | 31 | PassID: [4]byte{0x00, 0x00, 0x00, 0x01}, |
6988a057 JH |
32 | Name: "Test Serv", |
33 | Description: "Fooz", | |
34 | }, | |
35 | want: []byte{ | |
36 | 0x00, 0x01, | |
37 | 0x00, 0x10, | |
38 | 0x00, 0x02, | |
39 | 0x00, 0x00, | |
40 | 0x00, 0x00, 0x00, 0x01, | |
41 | 0x09, | |
42 | 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, | |
43 | 0x04, | |
44 | 0x46, 0x6f, 0x6f, 0x7a, | |
45 | }, | |
46 | }, | |
47 | } | |
48 | for _, tt := range tests { | |
49 | t.Run(tt.name, func(t *testing.T) { | |
50 | tr := &TrackerRegistration{ | |
51 | Port: tt.fields.Port, | |
52 | UserCount: tt.fields.UserCount, | |
53 | PassID: tt.fields.PassID, | |
54 | Name: tt.fields.Name, | |
55 | Description: tt.fields.Description, | |
56 | } | |
9a75b7cb JH |
57 | |
58 | if got, _ := io.ReadAll(tr); !reflect.DeepEqual(got, tt.want) { | |
8ff2b66d | 59 | t.Errorf("Read() = %v, want %v", got, tt.want) |
6988a057 JH |
60 | } |
61 | }) | |
62 | } | |
63 | } | |
8ff2b66d JH |
64 | |
65 | func Test_serverScanner(t *testing.T) { | |
66 | type args struct { | |
67 | data []byte | |
68 | atEOF bool | |
69 | } | |
70 | tests := []struct { | |
71 | name string | |
72 | args args | |
73 | wantAdvance int | |
74 | wantToken []byte | |
75 | wantErr assert.ErrorAssertionFunc | |
76 | }{ | |
77 | { | |
78 | name: "when a full server entry is provided", | |
79 | args: args{ | |
80 | data: []byte{ | |
81 | 0x18, 0x05, 0x30, 0x63, // IP Addr | |
82 | 0x15, 0x7c, // Port | |
83 | 0x00, 0x02, // UserCount | |
84 | 0x00, 0x00, // ?? | |
85 | 0x03, // Name Len | |
86 | 0x54, 0x68, 0x65, // Name | |
87 | 0x03, // Desc Len | |
88 | 0x54, 0x54, 0x54, // Description | |
89 | }, | |
90 | atEOF: false, | |
91 | }, | |
92 | wantAdvance: 18, | |
93 | wantToken: []byte{ | |
94 | 0x18, 0x05, 0x30, 0x63, // IP Addr | |
95 | 0x15, 0x7c, // Port | |
96 | 0x00, 0x02, // UserCount | |
97 | 0x00, 0x00, // ?? | |
98 | 0x03, // Name Len | |
99 | 0x54, 0x68, 0x65, // Name | |
100 | 0x03, // Desc Len | |
101 | 0x54, 0x54, 0x54, // Description | |
102 | }, | |
103 | wantErr: assert.NoError, | |
104 | }, | |
105 | { | |
106 | name: "when extra bytes are provided", | |
107 | args: args{ | |
108 | data: []byte{ | |
109 | 0x18, 0x05, 0x30, 0x63, // IP Addr | |
110 | 0x15, 0x7c, // Port | |
111 | 0x00, 0x02, // UserCount | |
112 | 0x00, 0x00, // ?? | |
113 | 0x03, // Name Len | |
114 | 0x54, 0x68, 0x65, // Name | |
115 | 0x03, // Desc Len | |
116 | 0x54, 0x54, 0x54, // Description | |
117 | 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, | |
118 | }, | |
119 | atEOF: false, | |
120 | }, | |
121 | wantAdvance: 18, | |
122 | wantToken: []byte{ | |
123 | 0x18, 0x05, 0x30, 0x63, // IP Addr | |
124 | 0x15, 0x7c, // Port | |
125 | 0x00, 0x02, // UserCount | |
126 | 0x00, 0x00, // ?? | |
127 | 0x03, // Name Len | |
128 | 0x54, 0x68, 0x65, // Name | |
129 | 0x03, // Desc Len | |
130 | 0x54, 0x54, 0x54, // Description | |
131 | }, | |
132 | wantErr: assert.NoError, | |
133 | }, | |
134 | { | |
135 | name: "when insufficient bytes are provided", | |
136 | args: args{ | |
137 | data: []byte{ | |
138 | 0, 0, | |
139 | }, | |
140 | atEOF: false, | |
141 | }, | |
142 | wantAdvance: 0, | |
143 | wantToken: []byte(nil), | |
144 | wantErr: assert.NoError, | |
145 | }, | |
04f40273 JH |
146 | { |
147 | name: "when nameLen exceeds provided data", | |
148 | args: args{ | |
149 | data: []byte{ | |
150 | 0x18, 0x05, 0x30, 0x63, // IP Addr | |
151 | 0x15, 0x7c, // Port | |
152 | 0x00, 0x02, // UserCount | |
153 | 0x00, 0x00, // ?? | |
154 | 0xff, // Name Len | |
155 | 0x54, 0x68, 0x65, // Name | |
156 | 0x03, // Desc Len | |
157 | 0x54, 0x54, 0x54, // Description | |
158 | }, | |
159 | atEOF: false, | |
160 | }, | |
161 | wantAdvance: 0, | |
162 | wantToken: []byte(nil), | |
163 | wantErr: assert.NoError, | |
164 | }, | |
165 | { | |
166 | name: "when description len exceeds provided data", | |
167 | args: args{ | |
168 | data: []byte{ | |
169 | 0x18, 0x05, 0x30, 0x63, // IP Addr | |
170 | 0x15, 0x7c, // Port | |
171 | 0x00, 0x02, // UserCount | |
172 | 0x00, 0x00, // ?? | |
173 | 0x03, // Name Len | |
174 | 0x54, 0x68, 0x65, // Name | |
175 | 0xff, // Desc Len | |
176 | 0x54, 0x54, 0x54, // Description | |
177 | }, | |
178 | atEOF: false, | |
179 | }, | |
180 | wantAdvance: 0, | |
181 | wantToken: []byte(nil), | |
182 | wantErr: assert.NoError, | |
183 | }, | |
8ff2b66d JH |
184 | } |
185 | for _, tt := range tests { | |
186 | t.Run(tt.name, func(t *testing.T) { | |
187 | gotAdvance, gotToken, err := serverScanner(tt.args.data, tt.args.atEOF) | |
188 | if !tt.wantErr(t, err, fmt.Sprintf("serverScanner(%v, %v)", tt.args.data, tt.args.atEOF)) { | |
189 | return | |
190 | } | |
191 | assert.Equalf(t, tt.wantAdvance, gotAdvance, "serverScanner(%v, %v)", tt.args.data, tt.args.atEOF) | |
192 | assert.Equalf(t, tt.wantToken, gotToken, "serverScanner(%v, %v)", tt.args.data, tt.args.atEOF) | |
193 | }) | |
194 | } | |
195 | } | |
a2ef262a JH |
196 | |
197 | type mockConn struct { | |
198 | readBuffer *bytes.Buffer | |
199 | writeBuffer *bytes.Buffer | |
200 | closed bool | |
201 | } | |
202 | ||
203 | func (m *mockConn) Read(b []byte) (n int, err error) { | |
204 | return m.readBuffer.Read(b) | |
205 | } | |
206 | ||
207 | func (m *mockConn) Write(b []byte) (n int, err error) { | |
208 | return m.writeBuffer.Write(b) | |
209 | } | |
210 | ||
211 | func (m *mockConn) Close() error { | |
212 | m.closed = true | |
213 | return nil | |
214 | } | |
215 | ||
216 | func TestGetListing(t *testing.T) { | |
217 | tests := []struct { | |
218 | name string | |
219 | mockConn *mockConn | |
220 | wantErr bool | |
221 | wantResult []ServerRecord | |
222 | }{ | |
223 | { | |
224 | name: "Successful retrieval", | |
225 | mockConn: &mockConn{ | |
226 | readBuffer: bytes.NewBuffer([]byte{ | |
227 | // TrackerHeader | |
228 | 0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK" | |
229 | 0x00, 0x01, // Version 1 | |
230 | // ServerInfoHeader | |
231 | 0x00, 0x01, // MsgType (1) | |
232 | 0x00, 0x14, // MsgDataSize (20) | |
233 | 0x00, 0x02, // SrvCount (2) | |
234 | 0x00, 0x02, // SrvCountDup (2) | |
235 | // ServerRecord 1 | |
236 | 192, 168, 1, 1, // IP address | |
237 | 0x1F, 0x90, // Port 8080 | |
238 | 0x00, 0x10, // NumUsers 16 | |
239 | 0x00, 0x00, // Unused | |
240 | 0x04, // NameSize | |
241 | 'S', 'e', 'r', 'v', // Name | |
242 | 0x0B, // DescriptionSize | |
243 | 'M', 'y', ' ', 'S', 'e', 'r', 'v', 'e', 'r', ' ', '1', // Description | |
244 | // ServerRecord 2 | |
245 | 10, 0, 0, 1, // IP address | |
246 | 0x1F, 0x91, // Port 8081 | |
247 | 0x00, 0x05, // NumUsers 5 | |
248 | 0x00, 0x00, // Unused | |
249 | 0x04, // NameSize | |
250 | 'S', 'e', 'r', 'v', // Name | |
251 | 0x0B, // DescriptionSize | |
252 | 'M', 'y', ' ', 'S', 'e', 'r', 'v', 'e', 'r', ' ', '2', // Description | |
253 | }), | |
254 | writeBuffer: &bytes.Buffer{}, | |
255 | }, | |
256 | wantErr: false, | |
257 | wantResult: []ServerRecord{ | |
258 | { | |
259 | IPAddr: [4]byte{192, 168, 1, 1}, | |
260 | Port: [2]byte{0x1F, 0x90}, | |
261 | NumUsers: [2]byte{0x00, 0x10}, | |
262 | Unused: [2]byte{0x00, 0x00}, | |
263 | NameSize: 4, | |
264 | Name: []byte("Serv"), | |
265 | DescriptionSize: 11, | |
266 | Description: []byte("My Server 1"), | |
267 | }, | |
268 | { | |
269 | IPAddr: [4]byte{10, 0, 0, 1}, | |
270 | Port: [2]byte{0x1F, 0x91}, | |
271 | NumUsers: [2]byte{0x00, 0x05}, | |
272 | Unused: [2]byte{0x00, 0x00}, | |
273 | NameSize: 4, | |
274 | Name: []byte("Serv"), | |
275 | DescriptionSize: 11, | |
276 | Description: []byte("My Server 2"), | |
277 | }, | |
278 | }, | |
279 | }, | |
280 | { | |
281 | name: "Write error", | |
282 | mockConn: &mockConn{ | |
283 | readBuffer: &bytes.Buffer{}, | |
284 | writeBuffer: &bytes.Buffer{}, | |
285 | }, | |
286 | wantErr: true, | |
287 | wantResult: nil, | |
288 | }, | |
289 | { | |
290 | name: "Read error on TrackerHeader", | |
291 | mockConn: &mockConn{ | |
292 | readBuffer: bytes.NewBuffer([]byte{ | |
293 | // incomplete data to cause read error | |
294 | 0x48, | |
295 | }), | |
296 | writeBuffer: &bytes.Buffer{}, | |
297 | }, | |
298 | wantErr: true, | |
299 | wantResult: nil, | |
300 | }, | |
301 | { | |
302 | name: "Read error on ServerInfoHeader", | |
303 | mockConn: &mockConn{ | |
304 | readBuffer: bytes.NewBuffer([]byte{ | |
305 | // TrackerHeader | |
306 | 0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK" | |
307 | 0x00, 0x01, // Version 1 | |
308 | // incomplete ServerInfoHeader | |
309 | 0x00, | |
310 | }), | |
311 | writeBuffer: &bytes.Buffer{}, | |
312 | }, | |
313 | wantErr: true, | |
314 | wantResult: nil, | |
315 | }, | |
316 | { | |
317 | name: "Scanner error", | |
318 | mockConn: &mockConn{ | |
319 | readBuffer: bytes.NewBuffer([]byte{ | |
320 | // TrackerHeader | |
321 | 0x48, 0x54, 0x52, 0x4B, // Protocol "HTRK" | |
322 | 0x00, 0x01, // Version 1 | |
323 | // ServerInfoHeader | |
324 | 0x00, 0x01, // MsgType (1) | |
325 | 0x00, 0x14, // MsgDataSize (20) | |
326 | 0x00, 0x01, // SrvCount (1) | |
327 | 0x00, 0x01, // SrvCountDup (1) | |
328 | // incomplete ServerRecord to cause scanner error | |
329 | 192, 168, 1, 1, | |
330 | }), | |
331 | writeBuffer: &bytes.Buffer{}, | |
332 | }, | |
333 | wantErr: true, | |
334 | wantResult: nil, | |
335 | }, | |
336 | } | |
337 | ||
338 | for _, tt := range tests { | |
339 | t.Run(tt.name, func(t *testing.T) { | |
340 | got, err := GetListing(tt.mockConn) | |
341 | if tt.wantErr { | |
342 | require.Error(t, err) | |
343 | } else { | |
344 | require.NoError(t, err) | |
345 | assert.Equal(t, tt.wantResult, got) | |
346 | } | |
347 | }) | |
348 | } | |
349 | } |