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