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