]> git.r.bdr.sh - rbdr/mobius/blame - hotline/transaction_handlers_test.go
Fix test
[rbdr/mobius] / hotline / transaction_handlers_test.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
decc2fbf 4 "errors"
9ebf276d 5 "fmt"
6988a057 6 "github.com/stretchr/testify/assert"
8eb43f95 7 "github.com/stretchr/testify/mock"
00d1ef67 8 "io/fs"
6988a057 9 "math/rand"
00d1ef67 10 "os"
f22acf38 11 "path/filepath"
decc2fbf 12 "strings"
6988a057 13 "testing"
7cd900d6 14 "time"
6988a057
JH
15)
16
17func TestHandleSetChatSubject(t *testing.T) {
18 type args struct {
19 cc *ClientConn
20 t *Transaction
21 }
22 tests := []struct {
23 name string
24 args args
25 want []Transaction
26 wantErr bool
27 }{
28 {
29 name: "sends chat subject to private chat members",
30 args: args{
31 cc: &ClientConn{
72dd37f1 32 UserName: []byte{0x00, 0x01},
6988a057
JH
33 Server: &Server{
34 PrivateChats: map[uint32]*PrivateChat{
35 uint32(1): {
36 Subject: "unset",
37 ClientConn: map[uint16]*ClientConn{
38 uint16(1): {
39 Account: &Account{
187d6dc5 40 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
41 },
42 ID: &[]byte{0, 1},
43 },
44 uint16(2): {
45 Account: &Account{
187d6dc5 46 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
47 },
48 ID: &[]byte{0, 2},
49 },
50 },
51 },
52 },
53 Clients: map[uint16]*ClientConn{
54 uint16(1): {
55 Account: &Account{
187d6dc5 56 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
57 },
58 ID: &[]byte{0, 1},
59 },
60 uint16(2): {
61 Account: &Account{
187d6dc5 62 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
63 },
64 ID: &[]byte{0, 2},
65 },
66 },
67 },
68 },
69 t: &Transaction{
70 Flags: 0x00,
71 IsReply: 0x00,
72 Type: []byte{0, 0x6a},
73 ID: []byte{0, 0, 0, 1},
74 ErrorCode: []byte{0, 0, 0, 0},
75 Fields: []Field{
d005ef04
JH
76 NewField(FieldChatID, []byte{0, 0, 0, 1}),
77 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
78 },
79 },
80 },
81 want: []Transaction{
82 {
83 clientID: &[]byte{0, 1},
84 Flags: 0x00,
85 IsReply: 0x00,
86 Type: []byte{0, 0x77},
87 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
88 ErrorCode: []byte{0, 0, 0, 0},
89 Fields: []Field{
d005ef04
JH
90 NewField(FieldChatID, []byte{0, 0, 0, 1}),
91 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
92 },
93 },
94 {
95 clientID: &[]byte{0, 2},
96 Flags: 0x00,
97 IsReply: 0x00,
98 Type: []byte{0, 0x77},
99 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
100 ErrorCode: []byte{0, 0, 0, 0},
101 Fields: []Field{
d005ef04
JH
102 NewField(FieldChatID, []byte{0, 0, 0, 1}),
103 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
104 },
105 },
106 },
107 wantErr: false,
108 },
109 }
110 for _, tt := range tests {
111 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
112
113 t.Run(tt.name, func(t *testing.T) {
114 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
115 if (err != nil) != tt.wantErr {
116 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
117 return
118 }
119 if !assert.Equal(t, tt.want, got) {
120 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
121 }
122 })
123 }
124}
125
126func TestHandleLeaveChat(t *testing.T) {
127 type args struct {
128 cc *ClientConn
129 t *Transaction
130 }
131 tests := []struct {
132 name string
133 args args
134 want []Transaction
135 wantErr bool
136 }{
137 {
138 name: "returns expected transactions",
139 args: args{
140 cc: &ClientConn{
141 ID: &[]byte{0, 2},
142 Server: &Server{
143 PrivateChats: map[uint32]*PrivateChat{
144 uint32(1): {
145 ClientConn: map[uint16]*ClientConn{
146 uint16(1): {
147 Account: &Account{
187d6dc5 148 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
149 },
150 ID: &[]byte{0, 1},
151 },
152 uint16(2): {
153 Account: &Account{
187d6dc5 154 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
155 },
156 ID: &[]byte{0, 2},
157 },
158 },
159 },
160 },
161 Clients: map[uint16]*ClientConn{
162 uint16(1): {
163 Account: &Account{
187d6dc5 164 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
165 },
166 ID: &[]byte{0, 1},
167 },
168 uint16(2): {
169 Account: &Account{
187d6dc5 170 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
171 },
172 ID: &[]byte{0, 2},
173 },
174 },
175 },
176 },
d005ef04 177 t: NewTransaction(TranDeleteUser, nil, NewField(FieldChatID, []byte{0, 0, 0, 1})),
6988a057
JH
178 },
179 want: []Transaction{
180 {
181 clientID: &[]byte{0, 1},
182 Flags: 0x00,
183 IsReply: 0x00,
184 Type: []byte{0, 0x76},
185 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
186 ErrorCode: []byte{0, 0, 0, 0},
187 Fields: []Field{
d005ef04
JH
188 NewField(FieldChatID, []byte{0, 0, 0, 1}),
189 NewField(FieldUserID, []byte{0, 2}),
6988a057
JH
190 },
191 },
192 },
193 wantErr: false,
194 },
195 }
196 for _, tt := range tests {
197 rand.Seed(1)
198 t.Run(tt.name, func(t *testing.T) {
199 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
200 if (err != nil) != tt.wantErr {
201 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
202 return
203 }
204 if !assert.Equal(t, tt.want, got) {
205 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
206 }
207 })
208 }
209}
210
6988a057
JH
211func TestHandleGetUserNameList(t *testing.T) {
212 type args struct {
213 cc *ClientConn
214 t *Transaction
215 }
216 tests := []struct {
217 name string
218 args args
219 want []Transaction
220 wantErr bool
221 }{
222 {
223 name: "replies with userlist transaction",
224 args: args{
225 cc: &ClientConn{
226
227 ID: &[]byte{1, 1},
228 Server: &Server{
229 Clients: map[uint16]*ClientConn{
230 uint16(1): {
231 ID: &[]byte{0, 1},
a7216f67
JH
232 Icon: []byte{0, 2},
233 Flags: []byte{0, 3},
72dd37f1 234 UserName: []byte{0, 4},
6988a057 235 },
c7e932c0
JH
236 uint16(2): {
237 ID: &[]byte{0, 2},
a7216f67
JH
238 Icon: []byte{0, 2},
239 Flags: []byte{0, 3},
c7e932c0 240 UserName: []byte{0, 4},
bd1ce113 241 },
6988a057
JH
242 },
243 },
244 },
245 t: &Transaction{
246 ID: []byte{0, 0, 0, 1},
247 Type: []byte{0, 1},
248 },
249 },
250 want: []Transaction{
251 {
252 clientID: &[]byte{1, 1},
253 Flags: 0x00,
254 IsReply: 0x01,
945b9813 255 Type: []byte{0, 0},
6988a057
JH
256 ID: []byte{0, 0, 0, 1},
257 ErrorCode: []byte{0, 0, 0, 0},
258 Fields: []Field{
259 NewField(
d005ef04 260 FieldUsernameWithInfo,
6988a057
JH
261 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
262 ),
c7e932c0 263 NewField(
d005ef04 264 FieldUsernameWithInfo,
c7e932c0
JH
265 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
266 ),
6988a057
JH
267 },
268 },
269 },
270 wantErr: false,
271 },
272 }
273 for _, tt := range tests {
274 t.Run(tt.name, func(t *testing.T) {
275 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
276 if (err != nil) != tt.wantErr {
277 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
278 return
279 }
bd1ce113 280 assert.Equal(t, tt.want, got)
6988a057
JH
281 })
282 }
283}
284
285func TestHandleChatSend(t *testing.T) {
286 type args struct {
287 cc *ClientConn
288 t *Transaction
289 }
290 tests := []struct {
291 name string
292 args args
293 want []Transaction
294 wantErr bool
295 }{
296 {
297 name: "sends chat msg transaction to all clients",
298 args: args{
299 cc: &ClientConn{
9ebf276d 300 Account: &Account{
187d6dc5 301 Access: func() accessBitmap {
9ebf276d
JH
302 var bits accessBitmap
303 bits.Set(accessSendChat)
187d6dc5 304 return bits
9ebf276d
JH
305 }(),
306 },
72dd37f1 307 UserName: []byte{0x00, 0x01},
6988a057
JH
308 Server: &Server{
309 Clients: map[uint16]*ClientConn{
310 uint16(1): {
311 Account: &Account{
187d6dc5 312 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
313 },
314 ID: &[]byte{0, 1},
315 },
316 uint16(2): {
317 Account: &Account{
187d6dc5 318 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
319 },
320 ID: &[]byte{0, 2},
321 },
322 },
323 },
324 },
325 t: &Transaction{
326 Fields: []Field{
d005ef04 327 NewField(FieldData, []byte("hai")),
6988a057
JH
328 },
329 },
330 },
331 want: []Transaction{
332 {
333 clientID: &[]byte{0, 1},
334 Flags: 0x00,
335 IsReply: 0x00,
336 Type: []byte{0, 0x6a},
337 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
338 ErrorCode: []byte{0, 0, 0, 0},
339 Fields: []Field{
d005ef04 340 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
341 },
342 },
343 {
344 clientID: &[]byte{0, 2},
345 Flags: 0x00,
346 IsReply: 0x00,
347 Type: []byte{0, 0x6a},
348 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
349 ErrorCode: []byte{0, 0, 0, 0},
350 Fields: []Field{
d005ef04 351 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
352 },
353 },
354 },
355 wantErr: false,
356 },
361928c9
JH
357 {
358 name: "treats Chat ID 00 00 00 00 as a public chat message",
359 args: args{
360 cc: &ClientConn{
361 Account: &Account{
362 Access: func() accessBitmap {
363 var bits accessBitmap
364 bits.Set(accessSendChat)
365 return bits
366 }(),
367 },
368 UserName: []byte{0x00, 0x01},
369 Server: &Server{
370 Clients: map[uint16]*ClientConn{
371 uint16(1): {
372 Account: &Account{
373 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
374 },
375 ID: &[]byte{0, 1},
376 },
377 uint16(2): {
378 Account: &Account{
379 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
380 },
381 ID: &[]byte{0, 2},
382 },
383 },
384 },
385 },
386 t: &Transaction{
387 Fields: []Field{
d005ef04
JH
388 NewField(FieldData, []byte("hai")),
389 NewField(FieldChatID, []byte{0, 0, 0, 0}),
361928c9
JH
390 },
391 },
392 },
393 want: []Transaction{
394 {
395 clientID: &[]byte{0, 1},
396 Flags: 0x00,
397 IsReply: 0x00,
398 Type: []byte{0, 0x6a},
399 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
400 ErrorCode: []byte{0, 0, 0, 0},
401 Fields: []Field{
d005ef04 402 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
403 },
404 },
405 {
406 clientID: &[]byte{0, 2},
407 Flags: 0x00,
408 IsReply: 0x00,
409 Type: []byte{0, 0x6a},
410 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
411 ErrorCode: []byte{0, 0, 0, 0},
412 Fields: []Field{
d005ef04 413 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
414 },
415 },
416 },
417 wantErr: false,
418 },
9ebf276d
JH
419 {
420 name: "when user does not have required permission",
421 args: args{
422 cc: &ClientConn{
423 Account: &Account{
187d6dc5 424 Access: func() accessBitmap {
9ebf276d 425 var bits accessBitmap
187d6dc5 426 return bits
9ebf276d
JH
427 }(),
428 },
429 Server: &Server{
430 Accounts: map[string]*Account{},
431 },
432 },
433 t: NewTransaction(
d005ef04
JH
434 TranChatSend, &[]byte{0, 1},
435 NewField(FieldData, []byte("hai")),
9ebf276d
JH
436 ),
437 },
438 want: []Transaction{
439 {
440 Flags: 0x00,
441 IsReply: 0x01,
860861f2 442 Type: []byte{0, 0},
9ebf276d
JH
443 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
444 ErrorCode: []byte{0, 0, 0, 1},
445 Fields: []Field{
d005ef04 446 NewField(FieldError, []byte("You are not allowed to participate in chat.")),
9ebf276d
JH
447 },
448 },
449 },
450 wantErr: false,
451 },
72dd37f1 452 {
d005ef04 453 name: "sends chat msg as emote if FieldChatOptions is set to 1",
72dd37f1
JH
454 args: args{
455 cc: &ClientConn{
9ebf276d 456 Account: &Account{
187d6dc5 457 Access: func() accessBitmap {
9ebf276d
JH
458 var bits accessBitmap
459 bits.Set(accessSendChat)
187d6dc5 460 return bits
9ebf276d
JH
461 }(),
462 },
72dd37f1
JH
463 UserName: []byte("Testy McTest"),
464 Server: &Server{
465 Clients: map[uint16]*ClientConn{
466 uint16(1): {
467 Account: &Account{
187d6dc5 468 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72dd37f1
JH
469 },
470 ID: &[]byte{0, 1},
471 },
472 uint16(2): {
473 Account: &Account{
187d6dc5 474 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72dd37f1
JH
475 },
476 ID: &[]byte{0, 2},
477 },
478 },
479 },
480 },
481 t: &Transaction{
482 Fields: []Field{
d005ef04
JH
483 NewField(FieldData, []byte("performed action")),
484 NewField(FieldChatOptions, []byte{0x00, 0x01}),
72dd37f1
JH
485 },
486 },
487 },
488 want: []Transaction{
489 {
490 clientID: &[]byte{0, 1},
491 Flags: 0x00,
492 IsReply: 0x00,
493 Type: []byte{0, 0x6a},
481631f6 494 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
72dd37f1
JH
495 ErrorCode: []byte{0, 0, 0, 0},
496 Fields: []Field{
d005ef04 497 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
498 },
499 },
500 {
501 clientID: &[]byte{0, 2},
502 Flags: 0x00,
503 IsReply: 0x00,
504 Type: []byte{0, 0x6a},
481631f6 505 ID: []byte{0xf0, 0xc5, 0x34, 0x1e},
72dd37f1
JH
506 ErrorCode: []byte{0, 0, 0, 0},
507 Fields: []Field{
d005ef04 508 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
509 },
510 },
511 },
512 wantErr: false,
513 },
2e43fd4e 514 {
d005ef04 515 name: "does not send chat msg as emote if FieldChatOptions is set to 0",
2e43fd4e
JH
516 args: args{
517 cc: &ClientConn{
518 Account: &Account{
519 Access: func() accessBitmap {
520 var bits accessBitmap
521 bits.Set(accessSendChat)
522 return bits
523 }(),
524 },
525 UserName: []byte("Testy McTest"),
526 Server: &Server{
527 Clients: map[uint16]*ClientConn{
528 uint16(1): {
529 Account: &Account{
530 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
531 },
532 ID: &[]byte{0, 1},
533 },
534 uint16(2): {
535 Account: &Account{
536 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
537 },
538 ID: &[]byte{0, 2},
539 },
540 },
541 },
542 },
543 t: &Transaction{
544 Fields: []Field{
d005ef04
JH
545 NewField(FieldData, []byte("hello")),
546 NewField(FieldChatOptions, []byte{0x00, 0x00}),
2e43fd4e
JH
547 },
548 },
549 },
550 want: []Transaction{
551 {
552 clientID: &[]byte{0, 1},
553 Flags: 0x00,
554 IsReply: 0x00,
555 Type: []byte{0, 0x6a},
556 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
557 ErrorCode: []byte{0, 0, 0, 0},
558 Fields: []Field{
d005ef04 559 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
560 },
561 },
562 {
563 clientID: &[]byte{0, 2},
564 Flags: 0x00,
565 IsReply: 0x00,
566 Type: []byte{0, 0x6a},
567 ID: []byte{0xf0, 0xc5, 0x34, 0x1e},
568 ErrorCode: []byte{0, 0, 0, 0},
569 Fields: []Field{
d005ef04 570 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
571 },
572 },
573 },
574 wantErr: false,
575 },
6988a057
JH
576 {
577 name: "only sends chat msg to clients with accessReadChat permission",
578 args: args{
579 cc: &ClientConn{
9ebf276d 580 Account: &Account{
187d6dc5 581 Access: func() accessBitmap {
9ebf276d
JH
582 var bits accessBitmap
583 bits.Set(accessSendChat)
187d6dc5 584 return bits
9ebf276d
JH
585 }(),
586 },
72dd37f1 587 UserName: []byte{0x00, 0x01},
6988a057
JH
588 Server: &Server{
589 Clients: map[uint16]*ClientConn{
590 uint16(1): {
591 Account: &Account{
187d6dc5
JH
592 Access: func() accessBitmap {
593 var bits accessBitmap
594 bits.Set(accessReadChat)
595 return bits
596 }()},
6988a057
JH
597 ID: &[]byte{0, 1},
598 },
599 uint16(2): {
600 Account: &Account{
187d6dc5 601 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
6988a057
JH
602 },
603 ID: &[]byte{0, 2},
604 },
605 },
606 },
607 },
608 t: &Transaction{
609 Fields: []Field{
d005ef04 610 NewField(FieldData, []byte("hai")),
6988a057
JH
611 },
612 },
613 },
614 want: []Transaction{
615 {
616 clientID: &[]byte{0, 1},
617 Flags: 0x00,
618 IsReply: 0x00,
619 Type: []byte{0, 0x6a},
620 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
621 ErrorCode: []byte{0, 0, 0, 0},
622 Fields: []Field{
d005ef04 623 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
624 },
625 },
626 },
627 wantErr: false,
628 },
481631f6
JH
629 {
630 name: "only sends private chat msg to members of private chat",
631 args: args{
632 cc: &ClientConn{
633 Account: &Account{
187d6dc5 634 Access: func() accessBitmap {
481631f6
JH
635 var bits accessBitmap
636 bits.Set(accessSendChat)
187d6dc5 637 return bits
481631f6
JH
638 }(),
639 },
640 UserName: []byte{0x00, 0x01},
641 Server: &Server{
642 PrivateChats: map[uint32]*PrivateChat{
643 uint32(1): {
644 ClientConn: map[uint16]*ClientConn{
645 uint16(1): {
646 ID: &[]byte{0, 1},
647 },
648 uint16(2): {
649 ID: &[]byte{0, 2},
650 },
651 },
652 },
653 },
654 Clients: map[uint16]*ClientConn{
655 uint16(1): {
656 Account: &Account{
187d6dc5 657 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
481631f6
JH
658 },
659 ID: &[]byte{0, 1},
660 },
661 uint16(2): {
662 Account: &Account{
187d6dc5 663 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
481631f6
JH
664 },
665 ID: &[]byte{0, 2},
666 },
667 uint16(3): {
668 Account: &Account{
187d6dc5 669 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
481631f6
JH
670 },
671 ID: &[]byte{0, 3},
672 },
673 },
674 },
675 },
676 t: &Transaction{
677 Fields: []Field{
d005ef04
JH
678 NewField(FieldData, []byte("hai")),
679 NewField(FieldChatID, []byte{0, 0, 0, 1}),
481631f6
JH
680 },
681 },
682 },
683 want: []Transaction{
684 {
685 clientID: &[]byte{0, 1},
686 Flags: 0x00,
687 IsReply: 0x00,
688 Type: []byte{0, 0x6a},
689 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
690 ErrorCode: []byte{0, 0, 0, 0},
691 Fields: []Field{
d005ef04
JH
692 NewField(FieldChatID, []byte{0, 0, 0, 1}),
693 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
481631f6
JH
694 },
695 },
696 {
697 clientID: &[]byte{0, 2},
698 Flags: 0x00,
699 IsReply: 0x00,
700 Type: []byte{0, 0x6a},
701 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
702 ErrorCode: []byte{0, 0, 0, 0},
703 Fields: []Field{
d005ef04
JH
704 NewField(FieldChatID, []byte{0, 0, 0, 1}),
705 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
481631f6
JH
706 },
707 },
708 },
709 wantErr: false,
710 },
6988a057
JH
711 }
712 for _, tt := range tests {
6988a057
JH
713 t.Run(tt.name, func(t *testing.T) {
714 got, err := HandleChatSend(tt.args.cc, tt.args.t)
715
716 if (err != nil) != tt.wantErr {
717 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
718 return
719 }
9ebf276d 720 tranAssertEqual(t, tt.want, got)
6988a057
JH
721 })
722 }
723}
72dd37f1
JH
724
725func TestHandleGetFileInfo(t *testing.T) {
726 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
727
728 type args struct {
729 cc *ClientConn
730 t *Transaction
731 }
732 tests := []struct {
733 name string
734 args args
735 wantRes []Transaction
736 wantErr bool
737 }{
738 {
739 name: "returns expected fields when a valid file is requested",
740 args: args{
741 cc: &ClientConn{
742 ID: &[]byte{0x00, 0x01},
743 Server: &Server{
7cd900d6 744 FS: &OSFileStore{},
72dd37f1 745 Config: &Config{
29f329ae
JH
746 FileRoot: func() string {
747 path, _ := os.Getwd()
f22acf38 748 return filepath.Join(path, "/test/config/Files")
29f329ae 749 }(),
72dd37f1
JH
750 },
751 },
752 },
753 t: NewTransaction(
d005ef04
JH
754 TranGetFileInfo, nil,
755 NewField(FieldFileName, []byte("testfile.txt")),
756 NewField(FieldFilePath, []byte{0x00, 0x00}),
72dd37f1
JH
757 ),
758 },
759 wantRes: []Transaction{
760 {
761 clientID: &[]byte{0, 1},
762 Flags: 0x00,
763 IsReply: 0x01,
945b9813 764 Type: []byte{0, 0},
72dd37f1
JH
765 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
766 ErrorCode: []byte{0, 0, 0, 0},
767 Fields: []Field{
d005ef04
JH
768 NewField(FieldFileName, []byte("testfile.txt")),
769 NewField(FieldFileTypeString, []byte("Text File")),
770 NewField(FieldFileCreatorString, []byte("ttxt")),
d005ef04
JH
771 NewField(FieldFileType, []byte("TEXT")),
772 NewField(FieldFileCreateDate, make([]byte, 8)),
773 NewField(FieldFileModifyDate, make([]byte, 8)),
774 NewField(FieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
72dd37f1
JH
775 },
776 },
777 },
778 wantErr: false,
779 },
780 }
781 for _, tt := range tests {
782 t.Run(tt.name, func(t *testing.T) {
783 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
784
785 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
786 if (err != nil) != tt.wantErr {
787 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
788 return
789 }
29f329ae 790
7cd900d6 791 // Clear the fileWrapper timestamp fields to work around problems running the tests in multiple timezones
29f329ae 792 // TODO: revisit how to test this by mocking the stat calls
84f3e842 793 gotRes[0].Fields[4].Data = make([]byte, 8)
29f329ae 794 gotRes[0].Fields[5].Data = make([]byte, 8)
00d1ef67 795 if !assert.Equal(t, tt.wantRes, gotRes) {
72dd37f1
JH
796 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
797 }
798 })
799 }
800}
00d1ef67
JH
801
802func TestHandleNewFolder(t *testing.T) {
803 type args struct {
804 cc *ClientConn
805 t *Transaction
806 }
807 tests := []struct {
00d1ef67
JH
808 name string
809 args args
810 wantRes []Transaction
811 wantErr bool
812 }{
d4c152a4 813 {
b196a50a 814 name: "without required permission",
d4c152a4
JH
815 args: args{
816 cc: &ClientConn{
817 Account: &Account{
187d6dc5 818 Access: func() accessBitmap {
d4c152a4 819 var bits accessBitmap
187d6dc5 820 return bits
d4c152a4
JH
821 }(),
822 },
823 },
824 t: NewTransaction(
825 accessCreateFolder,
826 &[]byte{0, 0},
827 ),
828 },
829 wantRes: []Transaction{
830 {
831 Flags: 0x00,
832 IsReply: 0x01,
860861f2 833 Type: []byte{0, 0},
d4c152a4
JH
834 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
835 ErrorCode: []byte{0, 0, 0, 1},
836 Fields: []Field{
d005ef04 837 NewField(FieldError, []byte("You are not allowed to create folders.")),
d4c152a4
JH
838 },
839 },
840 },
841 wantErr: false,
842 },
00d1ef67
JH
843 {
844 name: "when path is nested",
845 args: args{
846 cc: &ClientConn{
d4c152a4 847 Account: &Account{
187d6dc5 848 Access: func() accessBitmap {
d4c152a4
JH
849 var bits accessBitmap
850 bits.Set(accessCreateFolder)
187d6dc5 851 return bits
d4c152a4
JH
852 }(),
853 },
00d1ef67
JH
854 ID: &[]byte{0, 1},
855 Server: &Server{
856 Config: &Config{
857 FileRoot: "/Files/",
858 },
b196a50a
JH
859 FS: func() *MockFileStore {
860 mfs := &MockFileStore{}
861 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
862 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
863 return mfs
864 }(),
00d1ef67
JH
865 },
866 },
867 t: NewTransaction(
d005ef04
JH
868 TranNewFolder, &[]byte{0, 1},
869 NewField(FieldFileName, []byte("testFolder")),
870 NewField(FieldFilePath, []byte{
00d1ef67
JH
871 0x00, 0x01,
872 0x00, 0x00,
873 0x03,
874 0x61, 0x61, 0x61,
875 }),
876 ),
877 },
00d1ef67
JH
878 wantRes: []Transaction{
879 {
880 clientID: &[]byte{0, 1},
881 Flags: 0x00,
882 IsReply: 0x01,
945b9813 883 Type: []byte{0, 0},
00d1ef67
JH
884 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
885 ErrorCode: []byte{0, 0, 0, 0},
886 },
887 },
888 wantErr: false,
889 },
890 {
891 name: "when path is not nested",
892 args: args{
893 cc: &ClientConn{
d4c152a4 894 Account: &Account{
187d6dc5 895 Access: func() accessBitmap {
d4c152a4
JH
896 var bits accessBitmap
897 bits.Set(accessCreateFolder)
187d6dc5 898 return bits
d4c152a4
JH
899 }(),
900 },
00d1ef67
JH
901 ID: &[]byte{0, 1},
902 Server: &Server{
903 Config: &Config{
904 FileRoot: "/Files",
905 },
b196a50a
JH
906 FS: func() *MockFileStore {
907 mfs := &MockFileStore{}
908 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
909 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
910 return mfs
911 }(),
00d1ef67
JH
912 },
913 },
914 t: NewTransaction(
d005ef04
JH
915 TranNewFolder, &[]byte{0, 1},
916 NewField(FieldFileName, []byte("testFolder")),
00d1ef67
JH
917 ),
918 },
00d1ef67
JH
919 wantRes: []Transaction{
920 {
921 clientID: &[]byte{0, 1},
922 Flags: 0x00,
923 IsReply: 0x01,
945b9813 924 Type: []byte{0, 0},
00d1ef67
JH
925 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
926 ErrorCode: []byte{0, 0, 0, 0},
927 },
928 },
929 wantErr: false,
930 },
931 {
8fc43f8e 932 name: "when Write returns an err",
00d1ef67
JH
933 args: args{
934 cc: &ClientConn{
d4c152a4 935 Account: &Account{
187d6dc5 936 Access: func() accessBitmap {
d4c152a4
JH
937 var bits accessBitmap
938 bits.Set(accessCreateFolder)
187d6dc5 939 return bits
d4c152a4
JH
940 }(),
941 },
00d1ef67
JH
942 ID: &[]byte{0, 1},
943 Server: &Server{
944 Config: &Config{
945 FileRoot: "/Files/",
946 },
b196a50a
JH
947 FS: func() *MockFileStore {
948 mfs := &MockFileStore{}
949 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
950 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
951 return mfs
952 }(),
00d1ef67
JH
953 },
954 },
955 t: NewTransaction(
d005ef04
JH
956 TranNewFolder, &[]byte{0, 1},
957 NewField(FieldFileName, []byte("testFolder")),
958 NewField(FieldFilePath, []byte{
00d1ef67
JH
959 0x00,
960 }),
961 ),
962 },
00d1ef67
JH
963 wantRes: []Transaction{},
964 wantErr: true,
965 },
966 {
d005ef04 967 name: "FieldFileName does not allow directory traversal",
00d1ef67
JH
968 args: args{
969 cc: &ClientConn{
d4c152a4 970 Account: &Account{
187d6dc5 971 Access: func() accessBitmap {
d4c152a4
JH
972 var bits accessBitmap
973 bits.Set(accessCreateFolder)
187d6dc5 974 return bits
d4c152a4
JH
975 }(),
976 },
00d1ef67
JH
977 ID: &[]byte{0, 1},
978 Server: &Server{
979 Config: &Config{
980 FileRoot: "/Files/",
981 },
b196a50a
JH
982 FS: func() *MockFileStore {
983 mfs := &MockFileStore{}
984 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
985 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
986 return mfs
987 }(),
00d1ef67
JH
988 },
989 },
990 t: NewTransaction(
d005ef04
JH
991 TranNewFolder, &[]byte{0, 1},
992 NewField(FieldFileName, []byte("../../testFolder")),
00d1ef67
JH
993 ),
994 },
00d1ef67
JH
995 wantRes: []Transaction{
996 {
997 clientID: &[]byte{0, 1},
998 Flags: 0x00,
999 IsReply: 0x01,
945b9813 1000 Type: []byte{0, 0},
00d1ef67
JH
1001 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
1002 ErrorCode: []byte{0, 0, 0, 0},
1003 },
92a7e455 1004 }, wantErr: false,
00d1ef67
JH
1005 },
1006 {
d005ef04 1007 name: "FieldFilePath does not allow directory traversal",
00d1ef67
JH
1008 args: args{
1009 cc: &ClientConn{
d4c152a4 1010 Account: &Account{
187d6dc5 1011 Access: func() accessBitmap {
d4c152a4
JH
1012 var bits accessBitmap
1013 bits.Set(accessCreateFolder)
187d6dc5 1014 return bits
d4c152a4
JH
1015 }(),
1016 },
00d1ef67
JH
1017 ID: &[]byte{0, 1},
1018 Server: &Server{
1019 Config: &Config{
1020 FileRoot: "/Files/",
1021 },
b196a50a
JH
1022 FS: func() *MockFileStore {
1023 mfs := &MockFileStore{}
1024 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
1025 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
1026 return mfs
1027 }(),
00d1ef67
JH
1028 },
1029 },
1030 t: NewTransaction(
d005ef04
JH
1031 TranNewFolder, &[]byte{0, 1},
1032 NewField(FieldFileName, []byte("testFolder")),
1033 NewField(FieldFilePath, []byte{
00d1ef67
JH
1034 0x00, 0x02,
1035 0x00, 0x00,
1036 0x03,
1037 0x2e, 0x2e, 0x2f,
1038 0x00, 0x00,
1039 0x03,
1040 0x66, 0x6f, 0x6f,
1041 }),
1042 ),
1043 },
00d1ef67
JH
1044 wantRes: []Transaction{
1045 {
1046 clientID: &[]byte{0, 1},
1047 Flags: 0x00,
1048 IsReply: 0x01,
945b9813 1049 Type: []byte{0, 0},
00d1ef67
JH
1050 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
1051 ErrorCode: []byte{0, 0, 0, 0},
1052 },
92a7e455 1053 }, wantErr: false,
00d1ef67
JH
1054 },
1055 }
1056 for _, tt := range tests {
1057 t.Run(tt.name, func(t *testing.T) {
00d1ef67
JH
1058 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
1059 if (err != nil) != tt.wantErr {
1060 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
1061 return
1062 }
d4c152a4 1063
00d1ef67
JH
1064 if !tranAssertEqual(t, tt.wantRes, gotRes) {
1065 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
1066 }
1067 })
1068 }
1069}
1070
92a7e455
JH
1071func TestHandleUploadFile(t *testing.T) {
1072 type args struct {
1073 cc *ClientConn
1074 t *Transaction
1075 }
1076 tests := []struct {
1077 name string
1078 args args
1079 wantRes []Transaction
1080 wantErr bool
1081 }{
1082 {
7e2e07da 1083 name: "when request is valid and user has Upload Anywhere permission",
92a7e455
JH
1084 args: args{
1085 cc: &ClientConn{
1086 Server: &Server{
df1ade54
JH
1087 FS: &OSFileStore{},
1088 fileTransfers: map[[4]byte]*FileTransfer{},
1089 Config: &Config{
1090 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1091 }},
1092 transfers: map[int]map[[4]byte]*FileTransfer{
1093 FileUpload: {},
92a7e455
JH
1094 },
1095 Account: &Account{
187d6dc5 1096 Access: func() accessBitmap {
92a7e455
JH
1097 var bits accessBitmap
1098 bits.Set(accessUploadFile)
7e2e07da 1099 bits.Set(accessUploadAnywhere)
187d6dc5 1100 return bits
92a7e455
JH
1101 }(),
1102 },
1103 },
1104 t: NewTransaction(
d005ef04
JH
1105 TranUploadFile, &[]byte{0, 1},
1106 NewField(FieldFileName, []byte("testFile")),
1107 NewField(FieldFilePath, []byte{
92a7e455
JH
1108 0x00, 0x01,
1109 0x00, 0x00,
1110 0x03,
1111 0x2e, 0x2e, 0x2f,
1112 }),
1113 ),
1114 },
1115 wantRes: []Transaction{
1116 {
1117 Flags: 0x00,
1118 IsReply: 0x01,
945b9813 1119 Type: []byte{0, 0},
92a7e455
JH
1120 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1121 ErrorCode: []byte{0, 0, 0, 0},
1122 Fields: []Field{
d005ef04 1123 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
92a7e455
JH
1124 },
1125 },
1126 },
1127 wantErr: false,
1128 },
1129 {
1130 name: "when user does not have required access",
1131 args: args{
1132 cc: &ClientConn{
1133 Account: &Account{
187d6dc5 1134 Access: func() accessBitmap {
92a7e455 1135 var bits accessBitmap
187d6dc5 1136 return bits
92a7e455
JH
1137 }(),
1138 },
92a7e455
JH
1139 },
1140 t: NewTransaction(
d005ef04
JH
1141 TranUploadFile, &[]byte{0, 1},
1142 NewField(FieldFileName, []byte("testFile")),
1143 NewField(FieldFilePath, []byte{
92a7e455
JH
1144 0x00, 0x01,
1145 0x00, 0x00,
1146 0x03,
1147 0x2e, 0x2e, 0x2f,
1148 }),
1149 ),
1150 },
1151 wantRes: []Transaction{
1152 {
1153 Flags: 0x00,
1154 IsReply: 0x01,
860861f2 1155 Type: []byte{0, 0},
92a7e455
JH
1156 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1157 ErrorCode: []byte{0, 0, 0, 1},
1158 Fields: []Field{
d005ef04 1159 NewField(FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
92a7e455
JH
1160 },
1161 },
1162 },
1163 wantErr: false,
1164 },
1165 }
1166 for _, tt := range tests {
1167 t.Run(tt.name, func(t *testing.T) {
1168 rand.Seed(1)
1169 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
1170 if (err != nil) != tt.wantErr {
1171 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
1172 return
1173 }
aebc4d36
JH
1174
1175 tranAssertEqual(t, tt.wantRes, gotRes)
92a7e455
JH
1176 })
1177 }
1178}
decc2fbf
JH
1179
1180func TestHandleMakeAlias(t *testing.T) {
1181 type args struct {
1182 cc *ClientConn
1183 t *Transaction
1184 }
1185 tests := []struct {
1186 name string
decc2fbf
JH
1187 args args
1188 wantRes []Transaction
1189 wantErr bool
1190 }{
1191 {
1192 name: "with valid input and required permissions",
decc2fbf
JH
1193 args: args{
1194 cc: &ClientConn{
02b446d8 1195 logger: NewTestLogger(),
decc2fbf 1196 Account: &Account{
187d6dc5 1197 Access: func() accessBitmap {
decc2fbf
JH
1198 var bits accessBitmap
1199 bits.Set(accessMakeAlias)
187d6dc5 1200 return bits
decc2fbf
JH
1201 }(),
1202 },
1203 Server: &Server{
1204 Config: &Config{
1205 FileRoot: func() string {
1206 path, _ := os.Getwd()
1207 return path + "/test/config/Files"
1208 }(),
1209 },
1210 Logger: NewTestLogger(),
b196a50a
JH
1211 FS: func() *MockFileStore {
1212 mfs := &MockFileStore{}
1213 path, _ := os.Getwd()
1214 mfs.On(
1215 "Symlink",
1216 path+"/test/config/Files/foo/testFile",
1217 path+"/test/config/Files/bar/testFile",
1218 ).Return(nil)
1219 return mfs
1220 }(),
decc2fbf
JH
1221 },
1222 },
1223 t: NewTransaction(
d005ef04
JH
1224 TranMakeFileAlias, &[]byte{0, 1},
1225 NewField(FieldFileName, []byte("testFile")),
1226 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1227 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
decc2fbf
JH
1228 ),
1229 },
1230 wantRes: []Transaction{
1231 {
1232 Flags: 0x00,
1233 IsReply: 0x01,
945b9813 1234 Type: []byte{0, 0},
decc2fbf
JH
1235 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1236 ErrorCode: []byte{0, 0, 0, 0},
1237 Fields: []Field(nil),
1238 },
1239 },
1240 wantErr: false,
1241 },
1242 {
1243 name: "when symlink returns an error",
decc2fbf
JH
1244 args: args{
1245 cc: &ClientConn{
02b446d8 1246 logger: NewTestLogger(),
decc2fbf 1247 Account: &Account{
187d6dc5 1248 Access: func() accessBitmap {
decc2fbf
JH
1249 var bits accessBitmap
1250 bits.Set(accessMakeAlias)
187d6dc5 1251 return bits
decc2fbf
JH
1252 }(),
1253 },
1254 Server: &Server{
1255 Config: &Config{
1256 FileRoot: func() string {
1257 path, _ := os.Getwd()
1258 return path + "/test/config/Files"
1259 }(),
1260 },
1261 Logger: NewTestLogger(),
b196a50a
JH
1262 FS: func() *MockFileStore {
1263 mfs := &MockFileStore{}
1264 path, _ := os.Getwd()
1265 mfs.On(
1266 "Symlink",
1267 path+"/test/config/Files/foo/testFile",
1268 path+"/test/config/Files/bar/testFile",
1269 ).Return(errors.New("ohno"))
1270 return mfs
1271 }(),
decc2fbf
JH
1272 },
1273 },
1274 t: NewTransaction(
d005ef04
JH
1275 TranMakeFileAlias, &[]byte{0, 1},
1276 NewField(FieldFileName, []byte("testFile")),
1277 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1278 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
decc2fbf
JH
1279 ),
1280 },
1281 wantRes: []Transaction{
1282 {
1283 Flags: 0x00,
1284 IsReply: 0x01,
860861f2 1285 Type: []byte{0, 0},
decc2fbf
JH
1286 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1287 ErrorCode: []byte{0, 0, 0, 1},
1288 Fields: []Field{
d005ef04 1289 NewField(FieldError, []byte("Error creating alias")),
decc2fbf
JH
1290 },
1291 },
1292 },
1293 wantErr: false,
1294 },
1295 {
b196a50a 1296 name: "when user does not have required permission",
decc2fbf
JH
1297 args: args{
1298 cc: &ClientConn{
02b446d8 1299 logger: NewTestLogger(),
decc2fbf 1300 Account: &Account{
187d6dc5 1301 Access: func() accessBitmap {
decc2fbf 1302 var bits accessBitmap
187d6dc5 1303 return bits
decc2fbf
JH
1304 }(),
1305 },
1306 Server: &Server{
1307 Config: &Config{
1308 FileRoot: func() string {
1309 path, _ := os.Getwd()
1310 return path + "/test/config/Files"
1311 }(),
1312 },
1313 },
1314 },
1315 t: NewTransaction(
d005ef04
JH
1316 TranMakeFileAlias, &[]byte{0, 1},
1317 NewField(FieldFileName, []byte("testFile")),
1318 NewField(FieldFilePath, []byte{
decc2fbf
JH
1319 0x00, 0x01,
1320 0x00, 0x00,
1321 0x03,
1322 0x2e, 0x2e, 0x2e,
1323 }),
d005ef04 1324 NewField(FieldFileNewPath, []byte{
decc2fbf
JH
1325 0x00, 0x01,
1326 0x00, 0x00,
1327 0x03,
1328 0x2e, 0x2e, 0x2e,
1329 }),
1330 ),
1331 },
1332 wantRes: []Transaction{
1333 {
1334 Flags: 0x00,
1335 IsReply: 0x01,
860861f2 1336 Type: []byte{0, 0},
decc2fbf
JH
1337 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1338 ErrorCode: []byte{0, 0, 0, 1},
1339 Fields: []Field{
d005ef04 1340 NewField(FieldError, []byte("You are not allowed to make aliases.")),
decc2fbf
JH
1341 },
1342 },
1343 },
1344 wantErr: false,
1345 },
1346 }
1347 for _, tt := range tests {
1348 t.Run(tt.name, func(t *testing.T) {
decc2fbf
JH
1349 gotRes, err := HandleMakeAlias(tt.args.cc, tt.args.t)
1350 if (err != nil) != tt.wantErr {
1351 t.Errorf("HandleMakeAlias(%v, %v)", tt.args.cc, tt.args.t)
1352 return
1353 }
1354
1355 tranAssertEqual(t, tt.wantRes, gotRes)
1356 })
1357 }
1358}
9ebf276d
JH
1359
1360func TestHandleGetUser(t *testing.T) {
1361 type args struct {
1362 cc *ClientConn
1363 t *Transaction
1364 }
1365 tests := []struct {
1366 name string
1367 args args
1368 wantRes []Transaction
1369 wantErr assert.ErrorAssertionFunc
1370 }{
1371 {
1372 name: "when account is valid",
1373 args: args{
1374 cc: &ClientConn{
1375 Account: &Account{
187d6dc5 1376 Access: func() accessBitmap {
9ebf276d
JH
1377 var bits accessBitmap
1378 bits.Set(accessOpenUser)
187d6dc5 1379 return bits
9ebf276d
JH
1380 }(),
1381 },
1382 Server: &Server{
1383 Accounts: map[string]*Account{
1384 "guest": {
1385 Login: "guest",
1386 Name: "Guest",
1387 Password: "password",
187d6dc5 1388 Access: accessBitmap{},
9ebf276d
JH
1389 },
1390 },
1391 },
1392 },
1393 t: NewTransaction(
d005ef04
JH
1394 TranGetUser, &[]byte{0, 1},
1395 NewField(FieldUserLogin, []byte("guest")),
9ebf276d
JH
1396 ),
1397 },
1398 wantRes: []Transaction{
1399 {
1400 Flags: 0x00,
1401 IsReply: 0x01,
945b9813 1402 Type: []byte{0, 0},
9ebf276d
JH
1403 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1404 ErrorCode: []byte{0, 0, 0, 0},
1405 Fields: []Field{
d005ef04 1406 NewField(FieldUserName, []byte("Guest")),
76d0c1f6 1407 NewField(FieldUserLogin, encodeString([]byte("guest"))),
d005ef04
JH
1408 NewField(FieldUserPassword, []byte("password")),
1409 NewField(FieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
9ebf276d
JH
1410 },
1411 },
1412 },
1413 wantErr: assert.NoError,
1414 },
1415 {
1416 name: "when user does not have required permission",
1417 args: args{
1418 cc: &ClientConn{
1419 Account: &Account{
187d6dc5 1420 Access: func() accessBitmap {
9ebf276d 1421 var bits accessBitmap
187d6dc5 1422 return bits
9ebf276d
JH
1423 }(),
1424 },
1425 Server: &Server{
1426 Accounts: map[string]*Account{},
1427 },
1428 },
1429 t: NewTransaction(
d005ef04
JH
1430 TranGetUser, &[]byte{0, 1},
1431 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1432 ),
1433 },
1434 wantRes: []Transaction{
1435 {
1436 Flags: 0x00,
1437 IsReply: 0x01,
860861f2 1438 Type: []byte{0, 0},
9ebf276d
JH
1439 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1440 ErrorCode: []byte{0, 0, 0, 1},
1441 Fields: []Field{
d005ef04 1442 NewField(FieldError, []byte("You are not allowed to view accounts.")),
9ebf276d
JH
1443 },
1444 },
1445 },
1446 wantErr: assert.NoError,
1447 },
1448 {
1449 name: "when account does not exist",
1450 args: args{
1451 cc: &ClientConn{
1452 Account: &Account{
187d6dc5 1453 Access: func() accessBitmap {
9ebf276d
JH
1454 var bits accessBitmap
1455 bits.Set(accessOpenUser)
187d6dc5 1456 return bits
9ebf276d
JH
1457 }(),
1458 },
1459 Server: &Server{
1460 Accounts: map[string]*Account{},
1461 },
1462 },
1463 t: NewTransaction(
d005ef04
JH
1464 TranGetUser, &[]byte{0, 1},
1465 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1466 ),
1467 },
1468 wantRes: []Transaction{
1469 {
1470 Flags: 0x00,
1471 IsReply: 0x01,
860861f2 1472 Type: []byte{0, 0},
9ebf276d
JH
1473 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1474 ErrorCode: []byte{0, 0, 0, 1},
1475 Fields: []Field{
d005ef04 1476 NewField(FieldError, []byte("Account does not exist.")),
9ebf276d
JH
1477 },
1478 },
1479 },
1480 wantErr: assert.NoError,
1481 },
1482 }
1483 for _, tt := range tests {
1484 t.Run(tt.name, func(t *testing.T) {
1485 gotRes, err := HandleGetUser(tt.args.cc, tt.args.t)
1486 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetUser(%v, %v)", tt.args.cc, tt.args.t)) {
1487 return
1488 }
1489
1490 tranAssertEqual(t, tt.wantRes, gotRes)
1491 })
1492 }
1493}
1494
1495func TestHandleDeleteUser(t *testing.T) {
1496 type args struct {
1497 cc *ClientConn
1498 t *Transaction
1499 }
1500 tests := []struct {
1501 name string
9ebf276d
JH
1502 args args
1503 wantRes []Transaction
1504 wantErr assert.ErrorAssertionFunc
1505 }{
1506 {
7cd900d6 1507 name: "when user dataFile",
9ebf276d
JH
1508 args: args{
1509 cc: &ClientConn{
1510 Account: &Account{
187d6dc5 1511 Access: func() accessBitmap {
9ebf276d
JH
1512 var bits accessBitmap
1513 bits.Set(accessDeleteUser)
187d6dc5 1514 return bits
9ebf276d
JH
1515 }(),
1516 },
1517 Server: &Server{
1518 Accounts: map[string]*Account{
1519 "testuser": {
1520 Login: "testuser",
1521 Name: "Testy McTest",
1522 Password: "password",
187d6dc5 1523 Access: accessBitmap{},
9ebf276d
JH
1524 },
1525 },
b196a50a
JH
1526 FS: func() *MockFileStore {
1527 mfs := &MockFileStore{}
1528 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1529 return mfs
1530 }(),
9ebf276d
JH
1531 },
1532 },
1533 t: NewTransaction(
d005ef04 1534 TranDeleteUser, &[]byte{0, 1},
76d0c1f6 1535 NewField(FieldUserLogin, encodeString([]byte("testuser"))),
9ebf276d
JH
1536 ),
1537 },
1538 wantRes: []Transaction{
1539 {
1540 Flags: 0x00,
1541 IsReply: 0x01,
945b9813 1542 Type: []byte{0, 0},
9ebf276d
JH
1543 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1544 ErrorCode: []byte{0, 0, 0, 0},
1545 Fields: []Field(nil),
1546 },
1547 },
1548 wantErr: assert.NoError,
1549 },
1550 {
b196a50a 1551 name: "when user does not have required permission",
9ebf276d
JH
1552 args: args{
1553 cc: &ClientConn{
1554 Account: &Account{
187d6dc5 1555 Access: func() accessBitmap {
9ebf276d 1556 var bits accessBitmap
187d6dc5 1557 return bits
9ebf276d
JH
1558 }(),
1559 },
1560 Server: &Server{
1561 Accounts: map[string]*Account{},
1562 },
1563 },
1564 t: NewTransaction(
d005ef04 1565 TranDeleteUser, &[]byte{0, 1},
76d0c1f6 1566 NewField(FieldUserLogin, encodeString([]byte("testuser"))),
9ebf276d
JH
1567 ),
1568 },
1569 wantRes: []Transaction{
1570 {
1571 Flags: 0x00,
1572 IsReply: 0x01,
860861f2 1573 Type: []byte{0, 0},
9ebf276d
JH
1574 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1575 ErrorCode: []byte{0, 0, 0, 1},
1576 Fields: []Field{
d005ef04 1577 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
9ebf276d
JH
1578 },
1579 },
1580 },
1581 wantErr: assert.NoError,
1582 },
1583 }
1584 for _, tt := range tests {
1585 t.Run(tt.name, func(t *testing.T) {
9ebf276d
JH
1586 gotRes, err := HandleDeleteUser(tt.args.cc, tt.args.t)
1587 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteUser(%v, %v)", tt.args.cc, tt.args.t)) {
1588 return
1589 }
1590
1591 tranAssertEqual(t, tt.wantRes, gotRes)
1592 })
1593 }
1594}
481631f6
JH
1595
1596func TestHandleGetMsgs(t *testing.T) {
1597 type args struct {
1598 cc *ClientConn
1599 t *Transaction
1600 }
1601 tests := []struct {
1602 name string
1603 args args
1604 wantRes []Transaction
1605 wantErr assert.ErrorAssertionFunc
1606 }{
1607 {
1608 name: "returns news data",
1609 args: args{
1610 cc: &ClientConn{
1611 Account: &Account{
187d6dc5 1612 Access: func() accessBitmap {
481631f6
JH
1613 var bits accessBitmap
1614 bits.Set(accessNewsReadArt)
187d6dc5 1615 return bits
481631f6
JH
1616 }(),
1617 },
1618 Server: &Server{
1619 FlatNews: []byte("TEST"),
1620 },
1621 },
1622 t: NewTransaction(
d005ef04 1623 TranGetMsgs, &[]byte{0, 1},
481631f6
JH
1624 ),
1625 },
1626 wantRes: []Transaction{
1627 {
1628 Flags: 0x00,
1629 IsReply: 0x01,
945b9813 1630 Type: []byte{0, 0},
481631f6
JH
1631 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1632 ErrorCode: []byte{0, 0, 0, 0},
1633 Fields: []Field{
d005ef04 1634 NewField(FieldData, []byte("TEST")),
481631f6
JH
1635 },
1636 },
1637 },
1638 wantErr: assert.NoError,
1639 },
1640 {
1641 name: "when user does not have required permission",
1642 args: args{
1643 cc: &ClientConn{
1644 Account: &Account{
187d6dc5 1645 Access: func() accessBitmap {
481631f6 1646 var bits accessBitmap
187d6dc5 1647 return bits
481631f6
JH
1648 }(),
1649 },
1650 Server: &Server{
1651 Accounts: map[string]*Account{},
1652 },
1653 },
1654 t: NewTransaction(
d005ef04 1655 TranGetMsgs, &[]byte{0, 1},
481631f6
JH
1656 ),
1657 },
1658 wantRes: []Transaction{
1659 {
1660 Flags: 0x00,
1661 IsReply: 0x01,
860861f2 1662 Type: []byte{0, 0},
481631f6
JH
1663 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1664 ErrorCode: []byte{0, 0, 0, 1},
1665 Fields: []Field{
d005ef04 1666 NewField(FieldError, []byte("You are not allowed to read news.")),
481631f6
JH
1667 },
1668 },
1669 },
1670 wantErr: assert.NoError,
1671 },
1672 }
1673 for _, tt := range tests {
1674 t.Run(tt.name, func(t *testing.T) {
1675 gotRes, err := HandleGetMsgs(tt.args.cc, tt.args.t)
1676 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetMsgs(%v, %v)", tt.args.cc, tt.args.t)) {
1677 return
1678 }
1679
1680 tranAssertEqual(t, tt.wantRes, gotRes)
1681 })
1682 }
1683}
1684
1685func TestHandleNewUser(t *testing.T) {
1686 type args struct {
1687 cc *ClientConn
1688 t *Transaction
1689 }
1690 tests := []struct {
1691 name string
1692 args args
1693 wantRes []Transaction
1694 wantErr assert.ErrorAssertionFunc
1695 }{
1696 {
1697 name: "when user does not have required permission",
1698 args: args{
1699 cc: &ClientConn{
1700 Account: &Account{
187d6dc5 1701 Access: func() accessBitmap {
481631f6 1702 var bits accessBitmap
187d6dc5 1703 return bits
481631f6
JH
1704 }(),
1705 },
1706 Server: &Server{
1707 Accounts: map[string]*Account{},
1708 },
1709 },
1710 t: NewTransaction(
d005ef04 1711 TranNewUser, &[]byte{0, 1},
481631f6
JH
1712 ),
1713 },
1714 wantRes: []Transaction{
1715 {
1716 Flags: 0x00,
1717 IsReply: 0x01,
860861f2 1718 Type: []byte{0, 0},
481631f6
JH
1719 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1720 ErrorCode: []byte{0, 0, 0, 1},
1721 Fields: []Field{
d005ef04 1722 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
481631f6
JH
1723 },
1724 },
1725 },
1726 wantErr: assert.NoError,
1727 },
ecb1fcd9
JH
1728 {
1729 name: "when user attempts to create account with greater access",
1730 args: args{
1731 cc: &ClientConn{
1732 Account: &Account{
1733 Access: func() accessBitmap {
1734 var bits accessBitmap
1735 bits.Set(accessCreateUser)
1736 return bits
1737 }(),
1738 },
1739 Server: &Server{
1740 Accounts: map[string]*Account{},
1741 },
1742 },
1743 t: NewTransaction(
d005ef04
JH
1744 TranNewUser, &[]byte{0, 1},
1745 NewField(FieldUserLogin, []byte("userB")),
ecb1fcd9 1746 NewField(
d005ef04 1747 FieldUserAccess,
ecb1fcd9
JH
1748 func() []byte {
1749 var bits accessBitmap
1750 bits.Set(accessDisconUser)
1751 return bits[:]
1752 }(),
1753 ),
1754 ),
1755 },
1756 wantRes: []Transaction{
1757 {
1758 Flags: 0x00,
1759 IsReply: 0x01,
860861f2 1760 Type: []byte{0, 0},
ecb1fcd9
JH
1761 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1762 ErrorCode: []byte{0, 0, 0, 1},
1763 Fields: []Field{
d005ef04 1764 NewField(FieldError, []byte("Cannot create account with more access than yourself.")),
ecb1fcd9
JH
1765 },
1766 },
1767 },
1768 wantErr: assert.NoError,
1769 },
481631f6
JH
1770 }
1771 for _, tt := range tests {
1772 t.Run(tt.name, func(t *testing.T) {
1773 gotRes, err := HandleNewUser(tt.args.cc, tt.args.t)
1774 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewUser(%v, %v)", tt.args.cc, tt.args.t)) {
1775 return
1776 }
1777
1778 tranAssertEqual(t, tt.wantRes, gotRes)
1779 })
1780 }
1781}
1782
1783func TestHandleListUsers(t *testing.T) {
1784 type args struct {
1785 cc *ClientConn
1786 t *Transaction
1787 }
1788 tests := []struct {
1789 name string
1790 args args
1791 wantRes []Transaction
1792 wantErr assert.ErrorAssertionFunc
1793 }{
1794 {
1795 name: "when user does not have required permission",
1796 args: args{
1797 cc: &ClientConn{
1798 Account: &Account{
187d6dc5 1799 Access: func() accessBitmap {
481631f6 1800 var bits accessBitmap
187d6dc5 1801 return bits
481631f6
JH
1802 }(),
1803 },
1804 Server: &Server{
1805 Accounts: map[string]*Account{},
1806 },
1807 },
1808 t: NewTransaction(
d005ef04 1809 TranNewUser, &[]byte{0, 1},
481631f6
JH
1810 ),
1811 },
1812 wantRes: []Transaction{
1813 {
1814 Flags: 0x00,
1815 IsReply: 0x01,
860861f2 1816 Type: []byte{0, 0},
481631f6
JH
1817 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1818 ErrorCode: []byte{0, 0, 0, 1},
1819 Fields: []Field{
d005ef04 1820 NewField(FieldError, []byte("You are not allowed to view accounts.")),
481631f6
JH
1821 },
1822 },
1823 },
1824 wantErr: assert.NoError,
1825 },
60ec6281
JH
1826 {
1827 name: "when user has required permission",
1828 args: args{
1829 cc: &ClientConn{
1830 Account: &Account{
187d6dc5 1831 Access: func() accessBitmap {
60ec6281
JH
1832 var bits accessBitmap
1833 bits.Set(accessOpenUser)
187d6dc5 1834 return bits
60ec6281
JH
1835 }(),
1836 },
1837 Server: &Server{
1838 Accounts: map[string]*Account{
1839 "guest": {
1840 Name: "guest",
1841 Login: "guest",
1842 Password: "zz",
187d6dc5 1843 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
60ec6281
JH
1844 },
1845 },
1846 },
1847 },
1848 t: NewTransaction(
d005ef04
JH
1849 TranGetClientInfoText, &[]byte{0, 1},
1850 NewField(FieldUserID, []byte{0, 1}),
60ec6281
JH
1851 ),
1852 },
1853 wantRes: []Transaction{
1854 {
1855 Flags: 0x00,
1856 IsReply: 0x01,
945b9813 1857 Type: []byte{0, 0},
60ec6281
JH
1858 ID: []byte{0, 0, 0, 0},
1859 ErrorCode: []byte{0, 0, 0, 0},
1860 Fields: []Field{
d005ef04 1861 NewField(FieldData, []byte{
60ec6281
JH
1862 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1863 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1864 0x00, 0x6a, 0x00, 0x01, 0x78,
1865 }),
1866 },
1867 },
1868 },
1869 wantErr: assert.NoError,
1870 },
481631f6
JH
1871 }
1872 for _, tt := range tests {
1873 t.Run(tt.name, func(t *testing.T) {
1874 gotRes, err := HandleListUsers(tt.args.cc, tt.args.t)
1875 if !tt.wantErr(t, err, fmt.Sprintf("HandleListUsers(%v, %v)", tt.args.cc, tt.args.t)) {
1876 return
1877 }
1878
1879 tranAssertEqual(t, tt.wantRes, gotRes)
1880 })
1881 }
1882}
1883
1884func TestHandleDownloadFile(t *testing.T) {
1885 type args struct {
1886 cc *ClientConn
1887 t *Transaction
1888 }
1889 tests := []struct {
1890 name string
1891 args args
1892 wantRes []Transaction
1893 wantErr assert.ErrorAssertionFunc
1894 }{
1895 {
1896 name: "when user does not have required permission",
1897 args: args{
1898 cc: &ClientConn{
1899 Account: &Account{
187d6dc5 1900 Access: func() accessBitmap {
481631f6 1901 var bits accessBitmap
187d6dc5 1902 return bits
481631f6
JH
1903 }(),
1904 },
1905 Server: &Server{},
1906 },
d005ef04 1907 t: NewTransaction(TranDownloadFile, &[]byte{0, 1}),
481631f6
JH
1908 },
1909 wantRes: []Transaction{
1910 {
1911 Flags: 0x00,
1912 IsReply: 0x01,
860861f2 1913 Type: []byte{0, 0},
481631f6
JH
1914 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1915 ErrorCode: []byte{0, 0, 0, 1},
1916 Fields: []Field{
d005ef04 1917 NewField(FieldError, []byte("You are not allowed to download files.")),
481631f6
JH
1918 },
1919 },
1920 },
1921 wantErr: assert.NoError,
1922 },
1923 {
1924 name: "with a valid file",
1925 args: args{
1926 cc: &ClientConn{
df1ade54
JH
1927 transfers: map[int]map[[4]byte]*FileTransfer{
1928 FileDownload: {},
1929 },
481631f6 1930 Account: &Account{
187d6dc5 1931 Access: func() accessBitmap {
481631f6
JH
1932 var bits accessBitmap
1933 bits.Set(accessDownloadFile)
187d6dc5 1934 return bits
481631f6
JH
1935 }(),
1936 },
1937 Server: &Server{
7cd900d6 1938 FS: &OSFileStore{},
df1ade54 1939 fileTransfers: map[[4]byte]*FileTransfer{},
481631f6
JH
1940 Config: &Config{
1941 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1942 },
1943 Accounts: map[string]*Account{},
1944 },
1945 },
1946 t: NewTransaction(
1947 accessDownloadFile,
1948 &[]byte{0, 1},
d005ef04
JH
1949 NewField(FieldFileName, []byte("testfile.txt")),
1950 NewField(FieldFilePath, []byte{0x0, 0x00}),
481631f6
JH
1951 ),
1952 },
1953 wantRes: []Transaction{
1954 {
1955 Flags: 0x00,
1956 IsReply: 0x01,
945b9813 1957 Type: []byte{0, 0},
481631f6
JH
1958 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1959 ErrorCode: []byte{0, 0, 0, 0},
1960 Fields: []Field{
d005ef04
JH
1961 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1962 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
1963 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1964 NewField(FieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
481631f6
JH
1965 },
1966 },
1967 },
1968 wantErr: assert.NoError,
1969 },
7cd900d6
JH
1970 {
1971 name: "when client requests to resume 1k test file at offset 256",
1972 args: args{
1973 cc: &ClientConn{
df1ade54
JH
1974 transfers: map[int]map[[4]byte]*FileTransfer{
1975 FileDownload: {},
1976 }, Account: &Account{
187d6dc5 1977 Access: func() accessBitmap {
7cd900d6
JH
1978 var bits accessBitmap
1979 bits.Set(accessDownloadFile)
187d6dc5 1980 return bits
7cd900d6
JH
1981 }(),
1982 },
1983 Server: &Server{
1984 FS: &OSFileStore{},
df1ade54 1985
7cd900d6
JH
1986 // FS: func() *MockFileStore {
1987 // path, _ := os.Getwd()
1988 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1989 // if err != nil {
1990 // panic(err)
1991 // }
1992 //
1993 // mfi := &MockFileInfo{}
1994 // mfi.On("Mode").Return(fs.FileMode(0))
1995 // mfs := &MockFileStore{}
1996 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1997 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1998 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1999 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
2000 //
2001 // return mfs
2002 // }(),
df1ade54 2003 fileTransfers: map[[4]byte]*FileTransfer{},
7cd900d6
JH
2004 Config: &Config{
2005 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
2006 },
2007 Accounts: map[string]*Account{},
2008 },
2009 },
2010 t: NewTransaction(
2011 accessDownloadFile,
2012 &[]byte{0, 1},
d005ef04
JH
2013 NewField(FieldFileName, []byte("testfile-1k")),
2014 NewField(FieldFilePath, []byte{0x00, 0x00}),
7cd900d6 2015 NewField(
d005ef04 2016 FieldFileResumeData,
7cd900d6
JH
2017 func() []byte {
2018 frd := FileResumeData{
2019 Format: [4]byte{},
2020 Version: [2]byte{},
2021 RSVD: [34]byte{},
2022 ForkCount: [2]byte{0, 2},
2023 ForkInfoList: []ForkInfoList{
2024 {
2025 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
2026 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
2027 RSVDA: [4]byte{},
2028 RSVDB: [4]byte{},
2029 },
2030 {
2031 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
2032 DataSize: [4]byte{0, 0, 0, 0},
2033 RSVDA: [4]byte{},
2034 RSVDB: [4]byte{},
2035 },
2036 },
2037 }
2038 b, _ := frd.BinaryMarshal()
2039 return b
2040 }(),
2041 ),
2042 ),
2043 },
2044 wantRes: []Transaction{
2045 {
2046 Flags: 0x00,
2047 IsReply: 0x01,
945b9813 2048 Type: []byte{0, 0},
7cd900d6
JH
2049 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2050 ErrorCode: []byte{0, 0, 0, 0},
2051 Fields: []Field{
d005ef04
JH
2052 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
2053 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
2054 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
2055 NewField(FieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
7cd900d6
JH
2056 },
2057 },
2058 },
2059 wantErr: assert.NoError,
2060 },
481631f6
JH
2061 }
2062 for _, tt := range tests {
2063 t.Run(tt.name, func(t *testing.T) {
481631f6
JH
2064 gotRes, err := HandleDownloadFile(tt.args.cc, tt.args.t)
2065 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadFile(%v, %v)", tt.args.cc, tt.args.t)) {
2066 return
2067 }
2068
2069 tranAssertEqual(t, tt.wantRes, gotRes)
2070 })
2071 }
2072}
d2810ae9
JH
2073
2074func TestHandleUpdateUser(t *testing.T) {
2075 type args struct {
2076 cc *ClientConn
2077 t *Transaction
2078 }
2079 tests := []struct {
2080 name string
2081 args args
2082 wantRes []Transaction
2083 wantErr assert.ErrorAssertionFunc
2084 }{
2085 {
2086 name: "when action is create user without required permission",
2087 args: args{
2088 cc: &ClientConn{
02b446d8 2089 logger: NewTestLogger(),
d2810ae9
JH
2090 Server: &Server{
2091 Logger: NewTestLogger(),
2092 },
2093 Account: &Account{
187d6dc5 2094 Access: func() accessBitmap {
d2810ae9 2095 var bits accessBitmap
187d6dc5 2096 return bits
d2810ae9
JH
2097 }(),
2098 },
2099 },
2100 t: NewTransaction(
d005ef04 2101 TranUpdateUser,
d2810ae9 2102 &[]byte{0, 0},
d005ef04 2103 NewField(FieldData, []byte{
d2810ae9
JH
2104 0x00, 0x04, // field count
2105
d005ef04 2106 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
2107 0x00, 0x03,
2108 0x9d, 0x9d, 0x9d,
2109
d005ef04 2110 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
2111 0x00, 0x03,
2112 0x9c, 0x9c, 0x9c,
2113
d005ef04 2114 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
2115 0x00, 0x03,
2116 0x61, 0x61, 0x61,
2117
d005ef04 2118 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
2119 0x00, 0x08,
2120 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2121 }),
2122 ),
2123 },
2124 wantRes: []Transaction{
2125 {
2126 Flags: 0x00,
2127 IsReply: 0x01,
860861f2 2128 Type: []byte{0, 0},
d2810ae9
JH
2129 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2130 ErrorCode: []byte{0, 0, 0, 1},
2131 Fields: []Field{
d005ef04 2132 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
d2810ae9
JH
2133 },
2134 },
2135 },
2136 wantErr: assert.NoError,
2137 },
2138 {
2139 name: "when action is modify user without required permission",
2140 args: args{
2141 cc: &ClientConn{
02b446d8 2142 logger: NewTestLogger(),
d2810ae9
JH
2143 Server: &Server{
2144 Logger: NewTestLogger(),
2145 Accounts: map[string]*Account{
2146 "bbb": {},
2147 },
2148 },
2149 Account: &Account{
187d6dc5 2150 Access: func() accessBitmap {
d2810ae9 2151 var bits accessBitmap
187d6dc5 2152 return bits
d2810ae9
JH
2153 }(),
2154 },
2155 },
2156 t: NewTransaction(
d005ef04 2157 TranUpdateUser,
d2810ae9 2158 &[]byte{0, 0},
d005ef04 2159 NewField(FieldData, []byte{
d2810ae9
JH
2160 0x00, 0x04, // field count
2161
d005ef04 2162 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
2163 0x00, 0x03,
2164 0x9d, 0x9d, 0x9d,
2165
d005ef04 2166 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
2167 0x00, 0x03,
2168 0x9c, 0x9c, 0x9c,
2169
d005ef04 2170 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
2171 0x00, 0x03,
2172 0x61, 0x61, 0x61,
2173
d005ef04 2174 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
2175 0x00, 0x08,
2176 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2177 }),
2178 ),
2179 },
2180 wantRes: []Transaction{
2181 {
2182 Flags: 0x00,
2183 IsReply: 0x01,
860861f2 2184 Type: []byte{0, 0},
d2810ae9
JH
2185 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2186 ErrorCode: []byte{0, 0, 0, 1},
2187 Fields: []Field{
d005ef04 2188 NewField(FieldError, []byte("You are not allowed to modify accounts.")),
d2810ae9
JH
2189 },
2190 },
2191 },
2192 wantErr: assert.NoError,
2193 },
2194 {
2195 name: "when action is delete user without required permission",
2196 args: args{
2197 cc: &ClientConn{
02b446d8 2198 logger: NewTestLogger(),
d2810ae9 2199 Server: &Server{
d2810ae9
JH
2200 Accounts: map[string]*Account{
2201 "bbb": {},
2202 },
2203 },
2204 Account: &Account{
187d6dc5 2205 Access: func() accessBitmap {
d2810ae9 2206 var bits accessBitmap
187d6dc5 2207 return bits
d2810ae9
JH
2208 }(),
2209 },
2210 },
2211 t: NewTransaction(
d005ef04 2212 TranUpdateUser,
d2810ae9 2213 &[]byte{0, 0},
d005ef04 2214 NewField(FieldData, []byte{
d2810ae9
JH
2215 0x00, 0x01,
2216 0x00, 0x65,
2217 0x00, 0x03,
2218 0x88, 0x9e, 0x8b,
2219 }),
2220 ),
2221 },
2222 wantRes: []Transaction{
2223 {
2224 Flags: 0x00,
2225 IsReply: 0x01,
860861f2 2226 Type: []byte{0, 0},
d2810ae9
JH
2227 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2228 ErrorCode: []byte{0, 0, 0, 1},
2229 Fields: []Field{
d005ef04 2230 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
d2810ae9
JH
2231 },
2232 },
2233 },
2234 wantErr: assert.NoError,
2235 },
2236 }
2237 for _, tt := range tests {
2238 t.Run(tt.name, func(t *testing.T) {
2239 gotRes, err := HandleUpdateUser(tt.args.cc, tt.args.t)
2240 if !tt.wantErr(t, err, fmt.Sprintf("HandleUpdateUser(%v, %v)", tt.args.cc, tt.args.t)) {
2241 return
2242 }
2243
2244 tranAssertEqual(t, tt.wantRes, gotRes)
2245 })
2246 }
2247}
d4c152a4
JH
2248
2249func TestHandleDelNewsArt(t *testing.T) {
2250 type args struct {
2251 cc *ClientConn
2252 t *Transaction
2253 }
2254 tests := []struct {
2255 name string
2256 args args
2257 wantRes []Transaction
2258 wantErr assert.ErrorAssertionFunc
2259 }{
2260 {
2261 name: "without required permission",
2262 args: args{
2263 cc: &ClientConn{
2264 Account: &Account{
187d6dc5 2265 Access: func() accessBitmap {
d4c152a4 2266 var bits accessBitmap
187d6dc5 2267 return bits
d4c152a4
JH
2268 }(),
2269 },
2270 },
2271 t: NewTransaction(
d005ef04 2272 TranDelNewsArt,
d4c152a4
JH
2273 &[]byte{0, 0},
2274 ),
2275 },
2276 wantRes: []Transaction{
2277 {
2278 Flags: 0x00,
2279 IsReply: 0x01,
860861f2 2280 Type: []byte{0, 0},
d4c152a4
JH
2281 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2282 ErrorCode: []byte{0, 0, 0, 1},
2283 Fields: []Field{
d005ef04 2284 NewField(FieldError, []byte("You are not allowed to delete news articles.")),
d4c152a4
JH
2285 },
2286 },
2287 },
2288 wantErr: assert.NoError,
2289 },
2290 }
2291 for _, tt := range tests {
2292 t.Run(tt.name, func(t *testing.T) {
2293 gotRes, err := HandleDelNewsArt(tt.args.cc, tt.args.t)
2294 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsArt(%v, %v)", tt.args.cc, tt.args.t)) {
2295 return
2296 }
2297 tranAssertEqual(t, tt.wantRes, gotRes)
2298 })
2299 }
2300}
2301
2302func TestHandleDisconnectUser(t *testing.T) {
2303 type args struct {
2304 cc *ClientConn
2305 t *Transaction
2306 }
2307 tests := []struct {
2308 name string
2309 args args
2310 wantRes []Transaction
2311 wantErr assert.ErrorAssertionFunc
2312 }{
2313 {
2314 name: "without required permission",
2315 args: args{
2316 cc: &ClientConn{
2317 Account: &Account{
187d6dc5 2318 Access: func() accessBitmap {
d4c152a4 2319 var bits accessBitmap
187d6dc5 2320 return bits
d4c152a4
JH
2321 }(),
2322 },
2323 },
2324 t: NewTransaction(
d005ef04 2325 TranDelNewsArt,
d4c152a4
JH
2326 &[]byte{0, 0},
2327 ),
2328 },
2329 wantRes: []Transaction{
2330 {
2331 Flags: 0x00,
2332 IsReply: 0x01,
860861f2 2333 Type: []byte{0, 0},
d4c152a4
JH
2334 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2335 ErrorCode: []byte{0, 0, 0, 1},
2336 Fields: []Field{
d005ef04 2337 NewField(FieldError, []byte("You are not allowed to disconnect users.")),
d4c152a4
JH
2338 },
2339 },
2340 },
2341 wantErr: assert.NoError,
2342 },
2343 {
2344 name: "when target user has 'cannot be disconnected' priv",
2345 args: args{
2346 cc: &ClientConn{
2347 Server: &Server{
2348 Clients: map[uint16]*ClientConn{
2349 uint16(1): {
2350 Account: &Account{
2351 Login: "unnamed",
187d6dc5 2352 Access: func() accessBitmap {
d4c152a4
JH
2353 var bits accessBitmap
2354 bits.Set(accessCannotBeDiscon)
187d6dc5 2355 return bits
d4c152a4
JH
2356 }(),
2357 },
2358 },
2359 },
2360 },
2361 Account: &Account{
187d6dc5 2362 Access: func() accessBitmap {
d4c152a4
JH
2363 var bits accessBitmap
2364 bits.Set(accessDisconUser)
187d6dc5 2365 return bits
d4c152a4
JH
2366 }(),
2367 },
2368 },
2369 t: NewTransaction(
d005ef04 2370 TranDelNewsArt,
d4c152a4 2371 &[]byte{0, 0},
d005ef04 2372 NewField(FieldUserID, []byte{0, 1}),
d4c152a4
JH
2373 ),
2374 },
2375 wantRes: []Transaction{
2376 {
2377 Flags: 0x00,
2378 IsReply: 0x01,
860861f2 2379 Type: []byte{0, 0},
d4c152a4
JH
2380 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2381 ErrorCode: []byte{0, 0, 0, 1},
2382 Fields: []Field{
d005ef04 2383 NewField(FieldError, []byte("unnamed is not allowed to be disconnected.")),
d4c152a4
JH
2384 },
2385 },
2386 },
2387 wantErr: assert.NoError,
2388 },
2389 }
2390 for _, tt := range tests {
2391 t.Run(tt.name, func(t *testing.T) {
2392 gotRes, err := HandleDisconnectUser(tt.args.cc, tt.args.t)
2393 if !tt.wantErr(t, err, fmt.Sprintf("HandleDisconnectUser(%v, %v)", tt.args.cc, tt.args.t)) {
2394 return
2395 }
2396 tranAssertEqual(t, tt.wantRes, gotRes)
2397 })
2398 }
2399}
aeec1015
JH
2400
2401func TestHandleSendInstantMsg(t *testing.T) {
2402 type args struct {
2403 cc *ClientConn
2404 t *Transaction
2405 }
2406 tests := []struct {
2407 name string
2408 args args
2409 wantRes []Transaction
2410 wantErr assert.ErrorAssertionFunc
2411 }{
69c2fb50
JH
2412 {
2413 name: "without required permission",
2414 args: args{
2415 cc: &ClientConn{
2416 Account: &Account{
187d6dc5 2417 Access: func() accessBitmap {
69c2fb50 2418 var bits accessBitmap
187d6dc5 2419 return bits
69c2fb50
JH
2420 }(),
2421 },
2422 },
2423 t: NewTransaction(
d005ef04 2424 TranDelNewsArt,
69c2fb50
JH
2425 &[]byte{0, 0},
2426 ),
2427 },
2428 wantRes: []Transaction{
2429 {
2430 Flags: 0x00,
2431 IsReply: 0x01,
860861f2 2432 Type: []byte{0, 0},
69c2fb50
JH
2433 ID: []byte{0, 0, 0, 0},
2434 ErrorCode: []byte{0, 0, 0, 1},
2435 Fields: []Field{
d005ef04 2436 NewField(FieldError, []byte("You are not allowed to send private messages.")),
69c2fb50
JH
2437 },
2438 },
2439 },
d0ba21fc 2440 wantErr: assert.Error,
69c2fb50 2441 },
aeec1015
JH
2442 {
2443 name: "when client 1 sends a message to client 2",
2444 args: args{
2445 cc: &ClientConn{
69c2fb50 2446 Account: &Account{
187d6dc5 2447 Access: func() accessBitmap {
69c2fb50
JH
2448 var bits accessBitmap
2449 bits.Set(accessSendPrivMsg)
187d6dc5 2450 return bits
69c2fb50
JH
2451 }(),
2452 },
aeec1015
JH
2453 ID: &[]byte{0, 1},
2454 UserName: []byte("User1"),
2455 Server: &Server{
2456 Clients: map[uint16]*ClientConn{
2457 uint16(2): {
2458 AutoReply: []byte(nil),
38f710ec 2459 Flags: []byte{0, 0},
aeec1015
JH
2460 },
2461 },
2462 },
2463 },
2464 t: NewTransaction(
d005ef04 2465 TranSendInstantMsg,
aeec1015 2466 &[]byte{0, 1},
d005ef04
JH
2467 NewField(FieldData, []byte("hai")),
2468 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2469 ),
2470 },
2471 wantRes: []Transaction{
2472 *NewTransaction(
d005ef04 2473 TranServerMsg,
aeec1015 2474 &[]byte{0, 2},
d005ef04
JH
2475 NewField(FieldData, []byte("hai")),
2476 NewField(FieldUserName, []byte("User1")),
2477 NewField(FieldUserID, []byte{0, 1}),
2478 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2479 ),
2480 {
2481 clientID: &[]byte{0, 1},
2482 Flags: 0x00,
2483 IsReply: 0x01,
945b9813 2484 Type: []byte{0, 0},
aeec1015
JH
2485 ID: []byte{0, 0, 0, 0},
2486 ErrorCode: []byte{0, 0, 0, 0},
2487 Fields: []Field(nil),
2488 },
2489 },
2490 wantErr: assert.NoError,
2491 },
2492 {
2493 name: "when client 2 has autoreply enabled",
2494 args: args{
2495 cc: &ClientConn{
69c2fb50 2496 Account: &Account{
187d6dc5 2497 Access: func() accessBitmap {
69c2fb50
JH
2498 var bits accessBitmap
2499 bits.Set(accessSendPrivMsg)
187d6dc5 2500 return bits
69c2fb50
JH
2501 }(),
2502 },
aeec1015
JH
2503 ID: &[]byte{0, 1},
2504 UserName: []byte("User1"),
2505 Server: &Server{
2506 Clients: map[uint16]*ClientConn{
2507 uint16(2): {
38f710ec 2508 Flags: []byte{0, 0},
aeec1015
JH
2509 ID: &[]byte{0, 2},
2510 UserName: []byte("User2"),
2511 AutoReply: []byte("autohai"),
2512 },
2513 },
2514 },
2515 },
2516 t: NewTransaction(
d005ef04 2517 TranSendInstantMsg,
aeec1015 2518 &[]byte{0, 1},
d005ef04
JH
2519 NewField(FieldData, []byte("hai")),
2520 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2521 ),
2522 },
2523 wantRes: []Transaction{
2524 *NewTransaction(
d005ef04 2525 TranServerMsg,
aeec1015 2526 &[]byte{0, 2},
d005ef04
JH
2527 NewField(FieldData, []byte("hai")),
2528 NewField(FieldUserName, []byte("User1")),
2529 NewField(FieldUserID, []byte{0, 1}),
2530 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2531 ),
2532 *NewTransaction(
d005ef04 2533 TranServerMsg,
aeec1015 2534 &[]byte{0, 1},
d005ef04
JH
2535 NewField(FieldData, []byte("autohai")),
2536 NewField(FieldUserName, []byte("User2")),
2537 NewField(FieldUserID, []byte{0, 2}),
2538 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2539 ),
2540 {
2541 clientID: &[]byte{0, 1},
2542 Flags: 0x00,
2543 IsReply: 0x01,
945b9813 2544 Type: []byte{0, 0},
aeec1015
JH
2545 ID: []byte{0, 0, 0, 0},
2546 ErrorCode: []byte{0, 0, 0, 0},
2547 Fields: []Field(nil),
2548 },
2549 },
2550 wantErr: assert.NoError,
2551 },
38f710ec
JH
2552 {
2553 name: "when client 2 has refuse private messages enabled",
2554 args: args{
2555 cc: &ClientConn{
2556 Account: &Account{
2557 Access: func() accessBitmap {
2558 var bits accessBitmap
2559 bits.Set(accessSendPrivMsg)
2560 return bits
2561 }(),
2562 },
2563 ID: &[]byte{0, 1},
2564 UserName: []byte("User1"),
2565 Server: &Server{
2566 Clients: map[uint16]*ClientConn{
2567 uint16(2): {
2568 Flags: []byte{255, 255},
2569 ID: &[]byte{0, 2},
2570 UserName: []byte("User2"),
2571 },
2572 },
2573 },
2574 },
2575 t: NewTransaction(
d005ef04 2576 TranSendInstantMsg,
38f710ec 2577 &[]byte{0, 1},
d005ef04
JH
2578 NewField(FieldData, []byte("hai")),
2579 NewField(FieldUserID, []byte{0, 2}),
38f710ec
JH
2580 ),
2581 },
2582 wantRes: []Transaction{
2583 *NewTransaction(
d005ef04 2584 TranServerMsg,
38f710ec 2585 &[]byte{0, 1},
d005ef04
JH
2586 NewField(FieldData, []byte("User2 does not accept private messages.")),
2587 NewField(FieldUserName, []byte("User2")),
2588 NewField(FieldUserID, []byte{0, 2}),
2589 NewField(FieldOptions, []byte{0, 2}),
38f710ec
JH
2590 ),
2591 {
2592 clientID: &[]byte{0, 1},
2593 Flags: 0x00,
2594 IsReply: 0x01,
945b9813 2595 Type: []byte{0, 0},
38f710ec
JH
2596 ID: []byte{0, 0, 0, 0},
2597 ErrorCode: []byte{0, 0, 0, 0},
2598 Fields: []Field(nil),
2599 },
2600 },
2601 wantErr: assert.NoError,
2602 },
aeec1015
JH
2603 }
2604 for _, tt := range tests {
2605 t.Run(tt.name, func(t *testing.T) {
2606 gotRes, err := HandleSendInstantMsg(tt.args.cc, tt.args.t)
2607 if !tt.wantErr(t, err, fmt.Sprintf("HandleSendInstantMsg(%v, %v)", tt.args.cc, tt.args.t)) {
2608 return
2609 }
2610
2611 tranAssertEqual(t, tt.wantRes, gotRes)
2612 })
2613 }
2614}
7cd900d6
JH
2615
2616func TestHandleDeleteFile(t *testing.T) {
2617 type args struct {
2618 cc *ClientConn
2619 t *Transaction
2620 }
2621 tests := []struct {
2622 name string
2623 args args
2624 wantRes []Transaction
2625 wantErr assert.ErrorAssertionFunc
2626 }{
2627 {
2628 name: "when user does not have required permission to delete a folder",
2629 args: args{
2630 cc: &ClientConn{
2631 Account: &Account{
187d6dc5 2632 Access: func() accessBitmap {
7cd900d6 2633 var bits accessBitmap
187d6dc5 2634 return bits
7cd900d6
JH
2635 }(),
2636 },
2637 Server: &Server{
2638 Config: &Config{
2639 FileRoot: func() string {
2640 return "/fakeRoot/Files"
2641 }(),
2642 },
2643 FS: func() *MockFileStore {
2644 mfi := &MockFileInfo{}
2645 mfi.On("Mode").Return(fs.FileMode(0))
2646 mfi.On("Size").Return(int64(100))
2647 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2648 mfi.On("IsDir").Return(false)
2649 mfi.On("Name").Return("testfile")
2650
2651 mfs := &MockFileStore{}
2652 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2653 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2654 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2655
2656 return mfs
2657 }(),
2658 Accounts: map[string]*Account{},
2659 },
2660 },
2661 t: NewTransaction(
d005ef04
JH
2662 TranDeleteFile, &[]byte{0, 1},
2663 NewField(FieldFileName, []byte("testfile")),
2664 NewField(FieldFilePath, []byte{
7cd900d6
JH
2665 0x00, 0x01,
2666 0x00, 0x00,
2667 0x03,
2668 0x61, 0x61, 0x61,
2669 }),
2670 ),
2671 },
2672 wantRes: []Transaction{
2673 {
2674 Flags: 0x00,
2675 IsReply: 0x01,
860861f2 2676 Type: []byte{0, 0},
7cd900d6
JH
2677 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2678 ErrorCode: []byte{0, 0, 0, 1},
2679 Fields: []Field{
d005ef04 2680 NewField(FieldError, []byte("You are not allowed to delete files.")),
7cd900d6
JH
2681 },
2682 },
2683 },
2684 wantErr: assert.NoError,
2685 },
2686 {
2687 name: "deletes all associated metadata files",
2688 args: args{
2689 cc: &ClientConn{
2690 Account: &Account{
187d6dc5 2691 Access: func() accessBitmap {
7cd900d6
JH
2692 var bits accessBitmap
2693 bits.Set(accessDeleteFile)
187d6dc5 2694 return bits
7cd900d6
JH
2695 }(),
2696 },
2697 Server: &Server{
2698 Config: &Config{
2699 FileRoot: func() string {
2700 return "/fakeRoot/Files"
2701 }(),
2702 },
2703 FS: func() *MockFileStore {
2704 mfi := &MockFileInfo{}
2705 mfi.On("Mode").Return(fs.FileMode(0))
2706 mfi.On("Size").Return(int64(100))
2707 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2708 mfi.On("IsDir").Return(false)
2709 mfi.On("Name").Return("testfile")
2710
2711 mfs := &MockFileStore{}
2712 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2713 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2714 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2715
2716 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2717 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2718 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2719 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2720
2721 return mfs
2722 }(),
2723 Accounts: map[string]*Account{},
2724 },
2725 },
2726 t: NewTransaction(
d005ef04
JH
2727 TranDeleteFile, &[]byte{0, 1},
2728 NewField(FieldFileName, []byte("testfile")),
2729 NewField(FieldFilePath, []byte{
7cd900d6
JH
2730 0x00, 0x01,
2731 0x00, 0x00,
2732 0x03,
2733 0x61, 0x61, 0x61,
2734 }),
2735 ),
2736 },
2737 wantRes: []Transaction{
2738 {
2739 Flags: 0x00,
2740 IsReply: 0x01,
945b9813 2741 Type: []byte{0, 0},
7cd900d6
JH
2742 ID: []byte{0x0, 0x0, 0x0, 0x0},
2743 ErrorCode: []byte{0, 0, 0, 0},
2744 Fields: []Field(nil),
2745 },
2746 },
2747 wantErr: assert.NoError,
2748 },
2749 }
2750 for _, tt := range tests {
2751 t.Run(tt.name, func(t *testing.T) {
2752 gotRes, err := HandleDeleteFile(tt.args.cc, tt.args.t)
2753 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteFile(%v, %v)", tt.args.cc, tt.args.t)) {
2754 return
2755 }
2756
2757 tranAssertEqual(t, tt.wantRes, gotRes)
2758
2759 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2760 })
2761 }
2762}
2e08be58
JH
2763
2764func TestHandleGetFileNameList(t *testing.T) {
2765 type args struct {
2766 cc *ClientConn
2767 t *Transaction
2768 }
2769 tests := []struct {
2770 name string
2771 args args
2772 wantRes []Transaction
2773 wantErr assert.ErrorAssertionFunc
2774 }{
2775 {
d005ef04 2776 name: "when FieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2e08be58
JH
2777 args: args{
2778 cc: &ClientConn{
2779 Account: &Account{
187d6dc5 2780 Access: func() accessBitmap {
2e08be58 2781 var bits accessBitmap
187d6dc5 2782 return bits
2e08be58
JH
2783 }(),
2784 },
2785 Server: &Server{
2786
2787 Config: &Config{
2788 FileRoot: func() string {
2789 path, _ := os.Getwd()
2790 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2791 }(),
2792 },
2793 },
2794 },
2795 t: NewTransaction(
d005ef04
JH
2796 TranGetFileNameList, &[]byte{0, 1},
2797 NewField(FieldFilePath, []byte{
2e08be58
JH
2798 0x00, 0x01,
2799 0x00, 0x00,
2800 0x08,
2801 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2802 }),
2803 ),
2804 },
2805 wantRes: []Transaction{
2806 {
2807 Flags: 0x00,
2808 IsReply: 0x01,
860861f2 2809 Type: []byte{0, 0},
2e08be58
JH
2810 ID: []byte{0, 0, 0, 0},
2811 ErrorCode: []byte{0, 0, 0, 1},
2812 Fields: []Field{
d005ef04 2813 NewField(FieldError, []byte("You are not allowed to view drop boxes.")),
2e08be58
JH
2814 },
2815 },
2816 },
2817 wantErr: assert.NoError,
2818 },
2819 {
2820 name: "with file root",
2821 args: args{
2822 cc: &ClientConn{
2823 Server: &Server{
2824 Config: &Config{
2825 FileRoot: func() string {
2826 path, _ := os.Getwd()
2827 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2828 }(),
2829 },
2830 },
2831 },
2832 t: NewTransaction(
d005ef04
JH
2833 TranGetFileNameList, &[]byte{0, 1},
2834 NewField(FieldFilePath, []byte{
2e08be58
JH
2835 0x00, 0x00,
2836 0x00, 0x00,
2837 }),
2838 ),
2839 },
2840 wantRes: []Transaction{
2841 {
2842 Flags: 0x00,
2843 IsReply: 0x01,
945b9813 2844 Type: []byte{0, 0},
2e08be58
JH
2845 ID: []byte{0, 0, 0, 0},
2846 ErrorCode: []byte{0, 0, 0, 0},
2847 Fields: []Field{
2848 NewField(
d005ef04 2849 FieldFileNameWithInfo,
2e08be58
JH
2850 func() []byte {
2851 fnwi := FileNameWithInfo{
2852 fileNameWithInfoHeader: fileNameWithInfoHeader{
2853 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2854 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2855 FileSize: [4]byte{0, 0, 0x04, 0},
2856 RSVD: [4]byte{},
2857 NameScript: [2]byte{},
2858 NameSize: [2]byte{0, 0x0b},
2859 },
2860 name: []byte("testfile-1k"),
2861 }
2862 b, _ := fnwi.MarshalBinary()
2863 return b
2864 }(),
2865 ),
2866 },
2867 },
2868 },
2869 wantErr: assert.NoError,
2870 },
2871 }
2872 for _, tt := range tests {
2873 t.Run(tt.name, func(t *testing.T) {
2874 gotRes, err := HandleGetFileNameList(tt.args.cc, tt.args.t)
2875 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetFileNameList(%v, %v)", tt.args.cc, tt.args.t)) {
2876 return
2877 }
2878
2879 tranAssertEqual(t, tt.wantRes, gotRes)
2880 })
2881 }
2882}
df1ade54
JH
2883
2884func TestHandleGetClientInfoText(t *testing.T) {
2885 type args struct {
2886 cc *ClientConn
2887 t *Transaction
2888 }
2889 tests := []struct {
2890 name string
2891 args args
2892 wantRes []Transaction
2893 wantErr assert.ErrorAssertionFunc
2894 }{
2895 {
2896 name: "when user does not have required permission",
2897 args: args{
2898 cc: &ClientConn{
2899 Account: &Account{
187d6dc5 2900 Access: func() accessBitmap {
df1ade54 2901 var bits accessBitmap
187d6dc5 2902 return bits
df1ade54
JH
2903 }(),
2904 },
2905 Server: &Server{
2906 Accounts: map[string]*Account{},
2907 },
2908 },
2909 t: NewTransaction(
d005ef04
JH
2910 TranGetClientInfoText, &[]byte{0, 1},
2911 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2912 ),
2913 },
2914 wantRes: []Transaction{
2915 {
2916 Flags: 0x00,
2917 IsReply: 0x01,
860861f2 2918 Type: []byte{0, 0},
df1ade54
JH
2919 ID: []byte{0, 0, 0, 0},
2920 ErrorCode: []byte{0, 0, 0, 1},
2921 Fields: []Field{
d005ef04 2922 NewField(FieldError, []byte("You are not allowed to get client info.")),
df1ade54
JH
2923 },
2924 },
2925 },
2926 wantErr: assert.NoError,
2927 },
2928 {
2929 name: "with a valid user",
2930 args: args{
2931 cc: &ClientConn{
2932 UserName: []byte("Testy McTest"),
2933 RemoteAddr: "1.2.3.4:12345",
2934 Account: &Account{
187d6dc5 2935 Access: func() accessBitmap {
df1ade54
JH
2936 var bits accessBitmap
2937 bits.Set(accessGetClientInfo)
187d6dc5 2938 return bits
df1ade54
JH
2939 }(),
2940 Name: "test",
2941 Login: "test",
2942 },
2943 Server: &Server{
2944 Accounts: map[string]*Account{},
2945 Clients: map[uint16]*ClientConn{
2946 uint16(1): {
2947 UserName: []byte("Testy McTest"),
2948 RemoteAddr: "1.2.3.4:12345",
2949 Account: &Account{
187d6dc5 2950 Access: func() accessBitmap {
df1ade54
JH
2951 var bits accessBitmap
2952 bits.Set(accessGetClientInfo)
187d6dc5 2953 return bits
df1ade54
JH
2954 }(),
2955 Name: "test",
2956 Login: "test",
2957 },
2958 },
2959 },
2960 },
2961 transfers: map[int]map[[4]byte]*FileTransfer{
2962 FileDownload: {},
2963 FileUpload: {},
2964 FolderDownload: {},
2965 FolderUpload: {},
2966 },
2967 },
2968 t: NewTransaction(
d005ef04
JH
2969 TranGetClientInfoText, &[]byte{0, 1},
2970 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2971 ),
2972 },
2973 wantRes: []Transaction{
2974 {
2975 Flags: 0x00,
2976 IsReply: 0x01,
945b9813 2977 Type: []byte{0, 0},
df1ade54
JH
2978 ID: []byte{0, 0, 0, 0},
2979 ErrorCode: []byte{0, 0, 0, 0},
2980 Fields: []Field{
d005ef04 2981 NewField(FieldData, []byte(
c8bfd606 2982 strings.ReplaceAll(`Nickname: Testy McTest
df1ade54
JH
2983Name: test
2984Account: test
2985Address: 1.2.3.4:12345
2986
2987-------- File Downloads ---------
2988
2989None.
2990
2991------- Folder Downloads --------
2992
2993None.
2994
2995--------- File Uploads ----------
2996
2997None.
2998
2999-------- Folder Uploads ---------
3000
3001None.
3002
3003------- Waiting Downloads -------
3004
3005None.
3006
c8bfd606 3007`, "\n", "\r")),
df1ade54 3008 ),
d005ef04 3009 NewField(FieldUserName, []byte("Testy McTest")),
df1ade54
JH
3010 },
3011 },
3012 },
3013 wantErr: assert.NoError,
3014 },
3015 }
3016 for _, tt := range tests {
3017 t.Run(tt.name, func(t *testing.T) {
3018 gotRes, err := HandleGetClientInfoText(tt.args.cc, tt.args.t)
3019 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetClientInfoText(%v, %v)", tt.args.cc, tt.args.t)) {
3020 return
3021 }
3022 tranAssertEqual(t, tt.wantRes, gotRes)
3023 })
3024 }
3025}
ea5d8c51
JH
3026
3027func TestHandleTranAgreed(t *testing.T) {
3028 type args struct {
3029 cc *ClientConn
3030 t *Transaction
3031 }
3032 tests := []struct {
3033 name string
3034 args args
3035 wantRes []Transaction
3036 wantErr assert.ErrorAssertionFunc
3037 }{
3038 {
3039 name: "normal request flow",
3040 args: args{
3041 cc: &ClientConn{
3042 Account: &Account{
187d6dc5 3043 Access: func() accessBitmap {
ea5d8c51
JH
3044 var bits accessBitmap
3045 bits.Set(accessDisconUser)
3046 bits.Set(accessAnyName)
187d6dc5 3047 return bits
ea5d8c51 3048 }()},
a7216f67
JH
3049 Icon: []byte{0, 1},
3050 Flags: []byte{0, 1},
3051 Version: []byte{0, 1},
ea5d8c51
JH
3052 ID: &[]byte{0, 1},
3053 logger: NewTestLogger(),
3054 Server: &Server{
3055 Config: &Config{
3056 BannerFile: "banner.jpg",
3057 },
3058 },
3059 },
3060 t: NewTransaction(
d005ef04
JH
3061 TranAgreed, nil,
3062 NewField(FieldUserName, []byte("username")),
3063 NewField(FieldUserIconID, []byte{0, 1}),
3064 NewField(FieldOptions, []byte{0, 0}),
ea5d8c51
JH
3065 ),
3066 },
3067 wantRes: []Transaction{
3068 {
3069 clientID: &[]byte{0, 1},
3070 Flags: 0x00,
3071 IsReply: 0x00,
3072 Type: []byte{0, 0x7a},
3073 ID: []byte{0, 0, 0, 0},
3074 ErrorCode: []byte{0, 0, 0, 0},
3075 Fields: []Field{
d005ef04 3076 NewField(FieldBannerType, []byte("JPEG")),
ea5d8c51
JH
3077 },
3078 },
3079 {
3080 clientID: &[]byte{0, 1},
3081 Flags: 0x00,
3082 IsReply: 0x01,
945b9813 3083 Type: []byte{0, 0},
ea5d8c51
JH
3084 ID: []byte{0, 0, 0, 0},
3085 ErrorCode: []byte{0, 0, 0, 0},
3086 Fields: []Field{},
3087 },
3088 },
3089 wantErr: assert.NoError,
3090 },
3091 }
3092 for _, tt := range tests {
3093 t.Run(tt.name, func(t *testing.T) {
3094 gotRes, err := HandleTranAgreed(tt.args.cc, tt.args.t)
3095 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranAgreed(%v, %v)", tt.args.cc, tt.args.t)) {
3096 return
3097 }
3098 tranAssertEqual(t, tt.wantRes, gotRes)
3099 })
3100 }
3101}
264b7c27
JH
3102
3103func TestHandleSetClientUserInfo(t *testing.T) {
3104 type args struct {
3105 cc *ClientConn
3106 t *Transaction
3107 }
3108 tests := []struct {
3109 name string
3110 args args
3111 wantRes []Transaction
3112 wantErr assert.ErrorAssertionFunc
3113 }{
3114 {
3115 name: "when client does not have accessAnyName",
3116 args: args{
3117 cc: &ClientConn{
3118 Account: &Account{
187d6dc5 3119 Access: func() accessBitmap {
264b7c27 3120 var bits accessBitmap
187d6dc5 3121 return bits
264b7c27
JH
3122 }(),
3123 },
3124 ID: &[]byte{0, 1},
3125 UserName: []byte("Guest"),
3126 Flags: []byte{0, 1},
3127 Server: &Server{
3128 Clients: map[uint16]*ClientConn{
3129 uint16(1): {
3130 ID: &[]byte{0, 1},
3131 },
3132 },
3133 },
3134 },
3135 t: NewTransaction(
d005ef04
JH
3136 TranSetClientUserInfo, nil,
3137 NewField(FieldUserIconID, []byte{0, 1}),
3138 NewField(FieldUserName, []byte("NOPE")),
264b7c27
JH
3139 ),
3140 },
3141 wantRes: []Transaction{
3142 {
3143 clientID: &[]byte{0, 1},
3144 Flags: 0x00,
3145 IsReply: 0x00,
3146 Type: []byte{0x01, 0x2d},
3147 ID: []byte{0, 0, 0, 0},
3148 ErrorCode: []byte{0, 0, 0, 0},
3149 Fields: []Field{
d005ef04
JH
3150 NewField(FieldUserID, []byte{0, 1}),
3151 NewField(FieldUserIconID, []byte{0, 1}),
3152 NewField(FieldUserFlags, []byte{0, 1}),
3153 NewField(FieldUserName, []byte("Guest"))},
264b7c27
JH
3154 },
3155 },
3156 wantErr: assert.NoError,
3157 },
3158 }
3159 for _, tt := range tests {
3160 t.Run(tt.name, func(t *testing.T) {
3161 gotRes, err := HandleSetClientUserInfo(tt.args.cc, tt.args.t)
3162 if !tt.wantErr(t, err, fmt.Sprintf("HandleSetClientUserInfo(%v, %v)", tt.args.cc, tt.args.t)) {
3163 return
3164 }
3165
3166 tranAssertEqual(t, tt.wantRes, gotRes)
3167 })
3168 }
3169}
8eb43f95
JH
3170
3171func TestHandleDelNewsItem(t *testing.T) {
3172 type args struct {
3173 cc *ClientConn
3174 t *Transaction
3175 }
3176 tests := []struct {
3177 name string
3178 args args
3179 wantRes []Transaction
3180 wantErr assert.ErrorAssertionFunc
3181 }{
3182 {
3183 name: "when user does not have permission to delete a news category",
3184 args: args{
3185 cc: &ClientConn{
3186 Account: &Account{
3187 Access: accessBitmap{},
3188 },
3189 ID: &[]byte{0, 1},
3190 Server: &Server{
3191 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3192 "test": {
3193 Type: []byte{0, 3},
3194 Count: nil,
3195 NameSize: 0,
3196 Name: "zz",
3197 },
3198 }},
3199 },
3200 },
3201 t: NewTransaction(
d005ef04
JH
3202 TranDelNewsItem, nil,
3203 NewField(FieldNewsPath,
8eb43f95
JH
3204 []byte{
3205 0, 1,
3206 0, 0,
3207 4,
3208 0x74, 0x65, 0x73, 0x74,
3209 },
3210 ),
3211 ),
3212 },
3213 wantRes: []Transaction{
3214 {
3215 clientID: &[]byte{0, 1},
3216 Flags: 0x00,
3217 IsReply: 0x01,
860861f2 3218 Type: []byte{0, 0},
8eb43f95
JH
3219 ID: []byte{0, 0, 0, 0},
3220 ErrorCode: []byte{0, 0, 0, 1},
3221 Fields: []Field{
d005ef04 3222 NewField(FieldError, []byte("You are not allowed to delete news categories.")),
8eb43f95
JH
3223 },
3224 },
3225 },
3226 wantErr: assert.NoError,
3227 },
3228 {
3229 name: "when user does not have permission to delete a news folder",
3230 args: args{
3231 cc: &ClientConn{
3232 Account: &Account{
3233 Access: accessBitmap{},
3234 },
3235 ID: &[]byte{0, 1},
3236 Server: &Server{
3237 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3238 "testcat": {
3239 Type: []byte{0, 2},
3240 Count: nil,
3241 NameSize: 0,
3242 Name: "test",
3243 },
3244 }},
3245 },
3246 },
3247 t: NewTransaction(
d005ef04
JH
3248 TranDelNewsItem, nil,
3249 NewField(FieldNewsPath,
8eb43f95
JH
3250 []byte{
3251 0, 1,
3252 0, 0,
3253 4,
3254 0x74, 0x65, 0x73, 0x74,
3255 },
3256 ),
3257 ),
3258 },
3259 wantRes: []Transaction{
3260 {
3261 clientID: &[]byte{0, 1},
3262 Flags: 0x00,
3263 IsReply: 0x01,
860861f2 3264 Type: []byte{0, 0},
8eb43f95
JH
3265 ID: []byte{0, 0, 0, 0},
3266 ErrorCode: []byte{0, 0, 0, 1},
3267 Fields: []Field{
d005ef04 3268 NewField(FieldError, []byte("You are not allowed to delete news folders.")),
8eb43f95
JH
3269 },
3270 },
3271 },
3272 wantErr: assert.NoError,
3273 },
3274 {
3275 name: "when user deletes a news folder",
3276 args: args{
3277 cc: &ClientConn{
3278 Account: &Account{
3279 Access: func() accessBitmap {
3280 var bits accessBitmap
3281 bits.Set(accessNewsDeleteFldr)
3282 return bits
3283 }(),
3284 },
3285 ID: &[]byte{0, 1},
3286 Server: &Server{
3287 ConfigDir: "/fakeConfigRoot",
3288 FS: func() *MockFileStore {
3289 mfs := &MockFileStore{}
3290 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3291 return mfs
3292 }(),
3293 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3294 "testcat": {
3295 Type: []byte{0, 2},
3296 Count: nil,
3297 NameSize: 0,
3298 Name: "test",
3299 },
3300 }},
3301 },
3302 },
3303 t: NewTransaction(
d005ef04
JH
3304 TranDelNewsItem, nil,
3305 NewField(FieldNewsPath,
8eb43f95
JH
3306 []byte{
3307 0, 1,
3308 0, 0,
3309 4,
3310 0x74, 0x65, 0x73, 0x74,
3311 },
3312 ),
3313 ),
3314 },
3315 wantRes: []Transaction{
3316 {
3317 clientID: &[]byte{0, 1},
3318 Flags: 0x00,
3319 IsReply: 0x01,
945b9813 3320 Type: []byte{0, 0},
8eb43f95
JH
3321 ID: []byte{0, 0, 0, 0},
3322 ErrorCode: []byte{0, 0, 0, 0},
3323 Fields: []Field{},
3324 },
3325 },
3326 wantErr: assert.NoError,
3327 },
3328 }
3329 for _, tt := range tests {
3330 t.Run(tt.name, func(t *testing.T) {
3331 gotRes, err := HandleDelNewsItem(tt.args.cc, tt.args.t)
3332 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsItem(%v, %v)", tt.args.cc, tt.args.t)) {
3333 return
3334 }
3335 tranAssertEqual(t, tt.wantRes, gotRes)
3336 })
3337 }
3338}
969e6481
JH
3339
3340func TestHandleDownloadBanner(t *testing.T) {
3341 type args struct {
3342 cc *ClientConn
3343 t *Transaction
3344 }
3345 tests := []struct {
3346 name string
3347 args args
3348 wantRes []Transaction
3349 wantErr assert.ErrorAssertionFunc
3350 }{
3351 {
3352 name: "returns expected response",
3353 args: args{
3354 cc: &ClientConn{
3355 ID: &[]byte{0, 1},
3356 transfers: map[int]map[[4]byte]*FileTransfer{
3357 bannerDownload: {},
3358 },
3359 Server: &Server{
3360 ConfigDir: "/config",
3361 Config: &Config{
3362 BannerFile: "banner.jpg",
3363 },
3364 fileTransfers: map[[4]byte]*FileTransfer{},
3365 FS: func() *MockFileStore {
3366 mfi := &MockFileInfo{}
3367 mfi.On("Size").Return(int64(100))
3368
3369 mfs := &MockFileStore{}
3370 mfs.On("Stat", "/config/banner.jpg").Return(mfi, nil)
3371 return mfs
3372 }(),
3373 },
3374 },
d005ef04 3375 t: NewTransaction(TranDownloadBanner, nil),
969e6481
JH
3376 },
3377 wantRes: []Transaction{
3378 {
3379 clientID: &[]byte{0, 1},
3380 Flags: 0x00,
3381 IsReply: 0x01,
945b9813 3382 Type: []byte{0, 0},
969e6481
JH
3383 ID: []byte{0, 0, 0, 0},
3384 ErrorCode: []byte{0, 0, 0, 0},
3385 Fields: []Field{
d005ef04
JH
3386 NewField(FieldRefNum, []byte{1, 2, 3, 4}),
3387 NewField(FieldTransferSize, []byte{0, 0, 0, 0x64}),
969e6481
JH
3388 },
3389 },
3390 },
3391 wantErr: assert.NoError,
3392 },
3393 }
3394 for _, tt := range tests {
3395 t.Run(tt.name, func(t *testing.T) {
3396 gotRes, err := HandleDownloadBanner(tt.args.cc, tt.args.t)
3397 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadBanner(%v, %v)", tt.args.cc, tt.args.t)) {
3398 return
3399 }
3400
3401 tranAssertEqual(t, tt.wantRes, gotRes)
3402 })
3403 }
3404}
8a1512f9
JH
3405
3406func TestHandleTranOldPostNews(t *testing.T) {
3407 type args struct {
3408 cc *ClientConn
3409 t *Transaction
3410 }
3411 tests := []struct {
3412 name string
3413 args args
3414 wantRes []Transaction
3415 wantErr assert.ErrorAssertionFunc
3416 }{
3417 {
3418 name: "when user does not have required permission",
3419 args: args{
3420 cc: &ClientConn{
3421 Account: &Account{
3422 Access: func() accessBitmap {
3423 var bits accessBitmap
3424 return bits
3425 }(),
3426 },
3427 },
3428 t: NewTransaction(
d005ef04
JH
3429 TranOldPostNews, &[]byte{0, 1},
3430 NewField(FieldData, []byte("hai")),
8a1512f9
JH
3431 ),
3432 },
3433 wantRes: []Transaction{
3434 {
3435 Flags: 0x00,
3436 IsReply: 0x01,
860861f2 3437 Type: []byte{0, 0},
8a1512f9
JH
3438 ID: []byte{0, 0, 0, 0},
3439 ErrorCode: []byte{0, 0, 0, 1},
3440 Fields: []Field{
d005ef04 3441 NewField(FieldError, []byte("You are not allowed to post news.")),
8a1512f9
JH
3442 },
3443 },
3444 },
3445 wantErr: assert.NoError,
3446 },
3447 {
3448 name: "when user posts news update",
3449 args: args{
3450 cc: &ClientConn{
3451 Account: &Account{
3452 Access: func() accessBitmap {
3453 var bits accessBitmap
3454 bits.Set(accessNewsPostArt)
3455 return bits
3456 }(),
3457 },
3458 Server: &Server{
3459 FS: func() *MockFileStore {
3460 mfs := &MockFileStore{}
3461 mfs.On("WriteFile", "/fakeConfigRoot/MessageBoard.txt", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3462 return mfs
3463 }(),
3464 ConfigDir: "/fakeConfigRoot",
3465 Config: &Config{},
3466 },
3467 },
3468 t: NewTransaction(
d005ef04
JH
3469 TranOldPostNews, &[]byte{0, 1},
3470 NewField(FieldData, []byte("hai")),
8a1512f9
JH
3471 ),
3472 },
3473 wantRes: []Transaction{
3474 {
3475 Flags: 0x00,
3476 IsReply: 0x01,
945b9813 3477 Type: []byte{0, 0},
8a1512f9
JH
3478 ID: []byte{0, 0, 0, 0},
3479 ErrorCode: []byte{0, 0, 0, 0},
3480 },
3481 },
3482 wantErr: assert.NoError,
3483 },
3484 }
3485 for _, tt := range tests {
3486 t.Run(tt.name, func(t *testing.T) {
3487 gotRes, err := HandleTranOldPostNews(tt.args.cc, tt.args.t)
3488 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranOldPostNews(%v, %v)", tt.args.cc, tt.args.t)) {
3489 return
3490 }
3491
3492 tranAssertEqual(t, tt.wantRes, gotRes)
3493 })
3494 }
3495}
c1c44744
JH
3496
3497func TestHandleInviteNewChat(t *testing.T) {
3498 type args struct {
3499 cc *ClientConn
3500 t *Transaction
3501 }
3502 tests := []struct {
3503 name string
3504 args args
3505 wantRes []Transaction
3506 wantErr assert.ErrorAssertionFunc
3507 }{
3508 {
3509 name: "when user does not have required permission",
3510 args: args{
3511 cc: &ClientConn{
3512 Account: &Account{
3513 Access: func() accessBitmap {
3514 var bits accessBitmap
3515 return bits
3516 }(),
3517 },
3518 },
d005ef04 3519 t: NewTransaction(TranInviteNewChat, &[]byte{0, 1}),
c1c44744
JH
3520 },
3521 wantRes: []Transaction{
3522 {
3523 Flags: 0x00,
3524 IsReply: 0x01,
860861f2 3525 Type: []byte{0, 0},
c1c44744
JH
3526 ID: []byte{0, 0, 0, 0},
3527 ErrorCode: []byte{0, 0, 0, 1},
3528 Fields: []Field{
d005ef04 3529 NewField(FieldError, []byte("You are not allowed to request private chat.")),
c1c44744
JH
3530 },
3531 },
3532 },
3533 wantErr: assert.NoError,
3534 },
3535 {
3536 name: "when userA invites userB to new private chat",
3537 args: args{
3538 cc: &ClientConn{
3539 ID: &[]byte{0, 1},
3540 Account: &Account{
3541 Access: func() accessBitmap {
3542 var bits accessBitmap
3543 bits.Set(accessOpenChat)
3544 return bits
3545 }(),
3546 },
3547 UserName: []byte("UserA"),
3548 Icon: []byte{0, 1},
3549 Flags: []byte{0, 0},
3550 Server: &Server{
3551 Clients: map[uint16]*ClientConn{
3552 uint16(2): {
3553 ID: &[]byte{0, 2},
3554 UserName: []byte("UserB"),
3555 Flags: []byte{0, 0},
3556 },
3557 },
3558 PrivateChats: make(map[uint32]*PrivateChat),
3559 },
3560 },
3561 t: NewTransaction(
d005ef04
JH
3562 TranInviteNewChat, &[]byte{0, 1},
3563 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
3564 ),
3565 },
3566 wantRes: []Transaction{
3567 {
3568 clientID: &[]byte{0, 2},
3569 Flags: 0x00,
3570 IsReply: 0x00,
3571 Type: []byte{0, 0x71},
3572 ID: []byte{0, 0, 0, 0},
3573 ErrorCode: []byte{0, 0, 0, 0},
3574 Fields: []Field{
d005ef04
JH
3575 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3576 NewField(FieldUserName, []byte("UserA")),
3577 NewField(FieldUserID, []byte{0, 1}),
c1c44744
JH
3578 },
3579 },
3580
3581 {
3582 clientID: &[]byte{0, 1},
3583 Flags: 0x00,
3584 IsReply: 0x01,
945b9813 3585 Type: []byte{0, 0},
c1c44744
JH
3586 ID: []byte{0, 0, 0, 0},
3587 ErrorCode: []byte{0, 0, 0, 0},
3588 Fields: []Field{
d005ef04
JH
3589 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3590 NewField(FieldUserName, []byte("UserA")),
3591 NewField(FieldUserID, []byte{0, 1}),
3592 NewField(FieldUserIconID, []byte{0, 1}),
3593 NewField(FieldUserFlags, []byte{0, 0}),
c1c44744
JH
3594 },
3595 },
3596 },
3597 wantErr: assert.NoError,
3598 },
3599 {
3600 name: "when userA invites userB to new private chat, but UserB has refuse private chat enabled",
3601 args: args{
3602 cc: &ClientConn{
3603 ID: &[]byte{0, 1},
3604 Account: &Account{
3605 Access: func() accessBitmap {
3606 var bits accessBitmap
3607 bits.Set(accessOpenChat)
3608 return bits
3609 }(),
3610 },
3611 UserName: []byte("UserA"),
3612 Icon: []byte{0, 1},
3613 Flags: []byte{0, 0},
3614 Server: &Server{
3615 Clients: map[uint16]*ClientConn{
3616 uint16(2): {
3617 ID: &[]byte{0, 2},
3618 UserName: []byte("UserB"),
3619 Flags: []byte{255, 255},
3620 },
3621 },
3622 PrivateChats: make(map[uint32]*PrivateChat),
3623 },
3624 },
3625 t: NewTransaction(
d005ef04
JH
3626 TranInviteNewChat, &[]byte{0, 1},
3627 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
3628 ),
3629 },
3630 wantRes: []Transaction{
3631 {
3632 clientID: &[]byte{0, 1},
3633 Flags: 0x00,
3634 IsReply: 0x00,
3635 Type: []byte{0, 0x68},
3636 ID: []byte{0, 0, 0, 0},
3637 ErrorCode: []byte{0, 0, 0, 0},
3638 Fields: []Field{
d005ef04
JH
3639 NewField(FieldData, []byte("UserB does not accept private chats.")),
3640 NewField(FieldUserName, []byte("UserB")),
3641 NewField(FieldUserID, []byte{0, 2}),
3642 NewField(FieldOptions, []byte{0, 2}),
c1c44744
JH
3643 },
3644 },
3645 {
3646 clientID: &[]byte{0, 1},
3647 Flags: 0x00,
3648 IsReply: 0x01,
945b9813 3649 Type: []byte{0, 0},
c1c44744
JH
3650 ID: []byte{0, 0, 0, 0},
3651 ErrorCode: []byte{0, 0, 0, 0},
3652 Fields: []Field{
d005ef04
JH
3653 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3654 NewField(FieldUserName, []byte("UserA")),
3655 NewField(FieldUserID, []byte{0, 1}),
3656 NewField(FieldUserIconID, []byte{0, 1}),
3657 NewField(FieldUserFlags, []byte{0, 0}),
c1c44744
JH
3658 },
3659 },
3660 },
3661 wantErr: assert.NoError,
3662 },
3663 }
3664 for _, tt := range tests {
3665 t.Run(tt.name, func(t *testing.T) {
3666 rand.Seed(1)
3667 gotRes, err := HandleInviteNewChat(tt.args.cc, tt.args.t)
3668 if !tt.wantErr(t, err, fmt.Sprintf("HandleInviteNewChat(%v, %v)", tt.args.cc, tt.args.t)) {
3669 return
3670 }
3671 tranAssertEqual(t, tt.wantRes, gotRes)
3672 })
3673 }
3674}
33265393
JH
3675
3676func TestHandleGetNewsArtData(t *testing.T) {
3677 type args struct {
3678 cc *ClientConn
3679 t *Transaction
3680 }
3681 tests := []struct {
3682 name string
3683 args args
3684 wantRes []Transaction
3685 wantErr assert.ErrorAssertionFunc
3686 }{
3687 {
3688 name: "when user does not have required permission",
3689 args: args{
3690 cc: &ClientConn{
3691 Account: &Account{
3692 Access: func() accessBitmap {
3693 var bits accessBitmap
3694 return bits
3695 }(),
3696 },
3697 Server: &Server{
3698 Accounts: map[string]*Account{},
3699 },
3700 },
3701 t: NewTransaction(
d005ef04 3702 TranGetNewsArtData, &[]byte{0, 1},
33265393
JH
3703 ),
3704 },
3705 wantRes: []Transaction{
3706 {
3707 Flags: 0x00,
3708 IsReply: 0x01,
860861f2 3709 Type: []byte{0, 0},
33265393
JH
3710 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
3711 ErrorCode: []byte{0, 0, 0, 1},
3712 Fields: []Field{
d005ef04 3713 NewField(FieldError, []byte("You are not allowed to read news.")),
33265393
JH
3714 },
3715 },
3716 },
3717 wantErr: assert.NoError,
3718 },
3719 }
3720 for _, tt := range tests {
3721 t.Run(tt.name, func(t *testing.T) {
3722 gotRes, err := HandleGetNewsArtData(tt.args.cc, tt.args.t)
3723 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetNewsArtData(%v, %v)", tt.args.cc, tt.args.t)) {
3724 return
3725 }
3726 tranAssertEqual(t, tt.wantRes, gotRes)
3727 })
3728 }
3729}
860861f2
JH
3730
3731func TestHandleGetNewsArtNameList(t *testing.T) {
3732 type args struct {
3733 cc *ClientConn
3734 t *Transaction
3735 }
3736 tests := []struct {
3737 name string
3738 args args
3739 wantRes []Transaction
3740 wantErr assert.ErrorAssertionFunc
3741 }{
3742 {
3743 name: "when user does not have required permission",
3744 args: args{
3745 cc: &ClientConn{
3746 Account: &Account{
3747 Access: func() accessBitmap {
3748 var bits accessBitmap
3749 return bits
3750 }(),
3751 },
3752 Server: &Server{
3753 Accounts: map[string]*Account{},
3754 },
3755 },
3756 t: NewTransaction(
d005ef04 3757 TranGetNewsArtNameList, &[]byte{0, 1},
860861f2
JH
3758 ),
3759 },
3760 wantRes: []Transaction{
3761 {
3762 Flags: 0x00,
3763 IsReply: 0x01,
3764 Type: []byte{0, 0},
3765 ErrorCode: []byte{0, 0, 0, 1},
3766 Fields: []Field{
d005ef04 3767 NewField(FieldError, []byte("You are not allowed to read news.")),
860861f2
JH
3768 },
3769 },
3770 },
3771 wantErr: assert.NoError,
3772 },
3773 }
3774 for _, tt := range tests {
3775 t.Run(tt.name, func(t *testing.T) {
3776 gotRes, err := HandleGetNewsArtNameList(tt.args.cc, tt.args.t)
3777 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetNewsArtNameList(%v, %v)", tt.args.cc, tt.args.t)) {
3778 return
3779 }
3780 tranAssertEqual(t, tt.wantRes, gotRes)
860861f2
JH
3781 })
3782 }
3783}
3784
3785func TestHandleNewNewsFldr(t *testing.T) {
3786 type args struct {
3787 cc *ClientConn
3788 t *Transaction
3789 }
3790 tests := []struct {
3791 name string
3792 args args
3793 wantRes []Transaction
3794 wantErr assert.ErrorAssertionFunc
3795 }{
3796 {
3797 name: "when user does not have required permission",
3798 args: args{
3799 cc: &ClientConn{
3800 Account: &Account{
3801 Access: func() accessBitmap {
3802 var bits accessBitmap
3803 return bits
3804 }(),
3805 },
3806 Server: &Server{
3807 Accounts: map[string]*Account{},
3808 },
3809 },
3810 t: NewTransaction(
d005ef04 3811 TranGetNewsArtNameList, &[]byte{0, 1},
860861f2
JH
3812 ),
3813 },
3814 wantRes: []Transaction{
3815 {
3816 Flags: 0x00,
3817 IsReply: 0x01,
3818 Type: []byte{0, 0},
3819 ErrorCode: []byte{0, 0, 0, 1},
3820 Fields: []Field{
d005ef04 3821 NewField(FieldError, []byte("You are not allowed to create news folders.")),
860861f2
JH
3822 },
3823 },
3824 },
3825 wantErr: assert.NoError,
3826 },
3827 {
3828 name: "with a valid request",
3829 args: args{
3830 cc: &ClientConn{
3831 Account: &Account{
3832 Access: func() accessBitmap {
3833 var bits accessBitmap
3834 bits.Set(accessNewsCreateFldr)
3835 return bits
3836 }(),
3837 },
3838 logger: NewTestLogger(),
3839 ID: &[]byte{0, 1},
3840 Server: &Server{
3841 ConfigDir: "/fakeConfigRoot",
3842 FS: func() *MockFileStore {
3843 mfs := &MockFileStore{}
3844 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil)
3845 return mfs
3846 }(),
3847 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3848 "test": {
3849 Type: []byte{0, 2},
3850 Count: nil,
3851 NameSize: 0,
3852 Name: "test",
3853 SubCats: make(map[string]NewsCategoryListData15),
3854 },
3855 }},
3856 },
3857 },
3858 t: NewTransaction(
d005ef04
JH
3859 TranGetNewsArtNameList, &[]byte{0, 1},
3860 NewField(FieldFileName, []byte("testFolder")),
3861 NewField(FieldNewsPath,
860861f2
JH
3862 []byte{
3863 0, 1,
3864 0, 0,
3865 4,
3866 0x74, 0x65, 0x73, 0x74,
3867 },
3868 ),
3869 ),
3870 },
3871 wantRes: []Transaction{
3872 {
3873 clientID: &[]byte{0, 1},
3874 Flags: 0x00,
3875 IsReply: 0x01,
3876 Type: []byte{0, 0},
3877 ID: []byte{0, 0, 0, 0},
3878 ErrorCode: []byte{0, 0, 0, 0},
3879 Fields: []Field{},
3880 },
3881 },
3882 wantErr: assert.NoError,
3883 },
3884 //{
3885 // name: "when there is an error writing the threaded news file",
3886 // args: args{
3887 // cc: &ClientConn{
3888 // Account: &Account{
3889 // Access: func() accessBitmap {
3890 // var bits accessBitmap
3891 // bits.Set(accessNewsCreateFldr)
3892 // return bits
3893 // }(),
3894 // },
3895 // logger: NewTestLogger(),
3896 // ID: &[]byte{0, 1},
3897 // Server: &Server{
3898 // ConfigDir: "/fakeConfigRoot",
3899 // FS: func() *MockFileStore {
3900 // mfs := &MockFileStore{}
3901 // mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(os.ErrNotExist)
3902 // return mfs
3903 // }(),
3904 // ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3905 // "test": {
3906 // Type: []byte{0, 2},
3907 // Count: nil,
3908 // NameSize: 0,
3909 // Name: "test",
3910 // SubCats: make(map[string]NewsCategoryListData15),
3911 // },
3912 // }},
3913 // },
3914 // },
3915 // t: NewTransaction(
d005ef04
JH
3916 // TranGetNewsArtNameList, &[]byte{0, 1},
3917 // NewField(FieldFileName, []byte("testFolder")),
3918 // NewField(FieldNewsPath,
860861f2
JH
3919 // []byte{
3920 // 0, 1,
3921 // 0, 0,
3922 // 4,
3923 // 0x74, 0x65, 0x73, 0x74,
3924 // },
3925 // ),
3926 // ),
3927 // },
3928 // wantRes: []Transaction{
3929 // {
3930 // clientID: &[]byte{0, 1},
3931 // Flags: 0x00,
3932 // IsReply: 0x01,
3933 // Type: []byte{0, 0},
3934 // ErrorCode: []byte{0, 0, 0, 1},
3935 // Fields: []Field{
d005ef04 3936 // NewField(FieldError, []byte("Error creating news folder.")),
860861f2
JH
3937 // },
3938 // },
3939 // },
3940 // wantErr: assert.Error,
aeb97482 3941 // },
860861f2
JH
3942 }
3943 for _, tt := range tests {
3944 t.Run(tt.name, func(t *testing.T) {
3945 gotRes, err := HandleNewNewsFldr(tt.args.cc, tt.args.t)
3946 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewNewsFldr(%v, %v)", tt.args.cc, tt.args.t)) {
3947 return
3948 }
3949 tranAssertEqual(t, tt.wantRes, gotRes)
3950 })
3951 }
3952}