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