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