]> git.r.bdr.sh - rbdr/mobius/blame - hotline/tracker_test.go
Fix tracker registration logging
[rbdr/mobius] / hotline / tracker_test.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
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 "testing"
10)
11
12func TestTrackerRegistration_Payload(t *testing.T) {
13 type fields struct {
40414f92 14 Port [2]byte
6988a057 15 UserCount int
9a75b7cb 16 PassID [4]byte
6988a057
JH
17 Name string
18 Description string
19 }
20 tests := []struct {
21 name string
22 fields fields
23 want []byte
24 }{
25 {
26 name: "returns expected payload bytes",
27 fields: fields{
40414f92 28 Port: [2]byte{0x00, 0x10},
6988a057 29 UserCount: 2,
9a75b7cb 30 PassID: [4]byte{0x00, 0x00, 0x00, 0x01},
6988a057
JH
31 Name: "Test Serv",
32 Description: "Fooz",
33 },
34 want: []byte{
35 0x00, 0x01,
36 0x00, 0x10,
37 0x00, 0x02,
38 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x01,
40 0x09,
41 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76,
42 0x04,
43 0x46, 0x6f, 0x6f, 0x7a,
50c837fe 44 0x00,
6988a057
JH
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 57
50c837fe 58 if got, _ := io.ReadAll(tr); !assert.Equal(t, tt.want, got) {
8ff2b66d 59 t.Errorf("Read() = %v, want %v", got, tt.want)
6988a057
JH
60 }
61 })
62 }
63}
8ff2b66d
JH
64
65func 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
197type mockConn struct {
198 readBuffer *bytes.Buffer
199 writeBuffer *bytes.Buffer
200 closed bool
201}
202
203func (m *mockConn) Read(b []byte) (n int, err error) {
204 return m.readBuffer.Read(b)
205}
206
207func (m *mockConn) Write(b []byte) (n int, err error) {
208 return m.writeBuffer.Write(b)
209}
210
211func (m *mockConn) Close() error {
212 m.closed = true
213 return nil
214}
215
216func 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}