]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
Fix failing tests
[rbdr/mobius] / hotline / transaction_handlers_test.go
1 package hotline
2
3 import (
4 "errors"
5 "fmt"
6 "github.com/stretchr/testify/assert"
7 "io/fs"
8 "math/rand"
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 wantErr bool
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[uint32]*PrivateChat{
34 uint32(1): {
35 Subject: "unset",
36 ClientConn: map[uint16]*ClientConn{
37 uint16(1): {
38 Account: &Account{
39 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
40 },
41 ID: &[]byte{0, 1},
42 },
43 uint16(2): {
44 Account: &Account{
45 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
46 },
47 ID: &[]byte{0, 2},
48 },
49 },
50 },
51 },
52 Clients: map[uint16]*ClientConn{
53 uint16(1): {
54 Account: &Account{
55 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
56 },
57 ID: &[]byte{0, 1},
58 },
59 uint16(2): {
60 Account: &Account{
61 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
62 },
63 ID: &[]byte{0, 2},
64 },
65 },
66 },
67 },
68 t: &Transaction{
69 Flags: 0x00,
70 IsReply: 0x00,
71 Type: []byte{0, 0x6a},
72 ID: []byte{0, 0, 0, 1},
73 ErrorCode: []byte{0, 0, 0, 0},
74 Fields: []Field{
75 NewField(fieldChatID, []byte{0, 0, 0, 1}),
76 NewField(fieldChatSubject, []byte("Test Subject")),
77 },
78 },
79 },
80 want: []Transaction{
81 {
82 clientID: &[]byte{0, 1},
83 Flags: 0x00,
84 IsReply: 0x00,
85 Type: []byte{0, 0x77},
86 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
87 ErrorCode: []byte{0, 0, 0, 0},
88 Fields: []Field{
89 NewField(fieldChatID, []byte{0, 0, 0, 1}),
90 NewField(fieldChatSubject, []byte("Test Subject")),
91 },
92 },
93 {
94 clientID: &[]byte{0, 2},
95 Flags: 0x00,
96 IsReply: 0x00,
97 Type: []byte{0, 0x77},
98 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
99 ErrorCode: []byte{0, 0, 0, 0},
100 Fields: []Field{
101 NewField(fieldChatID, []byte{0, 0, 0, 1}),
102 NewField(fieldChatSubject, []byte("Test Subject")),
103 },
104 },
105 },
106 wantErr: false,
107 },
108 }
109 for _, tt := range tests {
110 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
111
112 t.Run(tt.name, func(t *testing.T) {
113 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
114 if (err != nil) != tt.wantErr {
115 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
116 return
117 }
118 if !assert.Equal(t, tt.want, got) {
119 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
120 }
121 })
122 }
123 }
124
125 func TestHandleLeaveChat(t *testing.T) {
126 type args struct {
127 cc *ClientConn
128 t *Transaction
129 }
130 tests := []struct {
131 name string
132 args args
133 want []Transaction
134 wantErr bool
135 }{
136 {
137 name: "returns expected transactions",
138 args: args{
139 cc: &ClientConn{
140 ID: &[]byte{0, 2},
141 Server: &Server{
142 PrivateChats: map[uint32]*PrivateChat{
143 uint32(1): {
144 ClientConn: map[uint16]*ClientConn{
145 uint16(1): {
146 Account: &Account{
147 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
148 },
149 ID: &[]byte{0, 1},
150 },
151 uint16(2): {
152 Account: &Account{
153 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
154 },
155 ID: &[]byte{0, 2},
156 },
157 },
158 },
159 },
160 Clients: map[uint16]*ClientConn{
161 uint16(1): {
162 Account: &Account{
163 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
164 },
165 ID: &[]byte{0, 1},
166 },
167 uint16(2): {
168 Account: &Account{
169 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
170 },
171 ID: &[]byte{0, 2},
172 },
173 },
174 },
175 },
176 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
177 },
178 want: []Transaction{
179 {
180 clientID: &[]byte{0, 1},
181 Flags: 0x00,
182 IsReply: 0x00,
183 Type: []byte{0, 0x76},
184 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
185 ErrorCode: []byte{0, 0, 0, 0},
186 Fields: []Field{
187 NewField(fieldChatID, []byte{0, 0, 0, 1}),
188 NewField(fieldUserID, []byte{0, 2}),
189 },
190 },
191 },
192 wantErr: false,
193 },
194 }
195 for _, tt := range tests {
196 rand.Seed(1)
197 t.Run(tt.name, func(t *testing.T) {
198 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
199 if (err != nil) != tt.wantErr {
200 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
201 return
202 }
203 if !assert.Equal(t, tt.want, got) {
204 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
205 }
206 })
207 }
208 }
209
210 func TestHandleGetUserNameList(t *testing.T) {
211 type args struct {
212 cc *ClientConn
213 t *Transaction
214 }
215 tests := []struct {
216 name string
217 args args
218 want []Transaction
219 wantErr bool
220 }{
221 {
222 name: "replies with userlist transaction",
223 args: args{
224 cc: &ClientConn{
225
226 ID: &[]byte{1, 1},
227 Server: &Server{
228 Clients: map[uint16]*ClientConn{
229 uint16(1): {
230 ID: &[]byte{0, 1},
231 Icon: &[]byte{0, 2},
232 Flags: &[]byte{0, 3},
233 UserName: []byte{0, 4},
234 Agreed: true,
235 },
236 uint16(2): {
237 ID: &[]byte{0, 2},
238 Icon: &[]byte{0, 2},
239 Flags: &[]byte{0, 3},
240 UserName: []byte{0, 4},
241 Agreed: true,
242 },
243 uint16(3): {
244 ID: &[]byte{0, 3},
245 Icon: &[]byte{0, 2},
246 Flags: &[]byte{0, 3},
247 UserName: []byte{0, 4},
248 Agreed: false,
249 },
250 },
251 },
252 },
253 t: &Transaction{
254 ID: []byte{0, 0, 0, 1},
255 Type: []byte{0, 1},
256 },
257 },
258 want: []Transaction{
259 {
260 clientID: &[]byte{1, 1},
261 Flags: 0x00,
262 IsReply: 0x01,
263 Type: []byte{0, 1},
264 ID: []byte{0, 0, 0, 1},
265 ErrorCode: []byte{0, 0, 0, 0},
266 Fields: []Field{
267 NewField(
268 fieldUsernameWithInfo,
269 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
270 ),
271 NewField(
272 fieldUsernameWithInfo,
273 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
274 ),
275 },
276 },
277 },
278 wantErr: false,
279 },
280 }
281 for _, tt := range tests {
282 t.Run(tt.name, func(t *testing.T) {
283 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
284 if (err != nil) != tt.wantErr {
285 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
286 return
287 }
288 assert.Equal(t, tt.want, got)
289 })
290 }
291 }
292
293 func TestHandleChatSend(t *testing.T) {
294 type args struct {
295 cc *ClientConn
296 t *Transaction
297 }
298 tests := []struct {
299 name string
300 args args
301 want []Transaction
302 wantErr bool
303 }{
304 {
305 name: "sends chat msg transaction to all clients",
306 args: args{
307 cc: &ClientConn{
308 Account: &Account{
309 Access: func() *[]byte {
310 var bits accessBitmap
311 bits.Set(accessSendChat)
312 access := bits[:]
313 return &access
314 }(),
315 },
316 UserName: []byte{0x00, 0x01},
317 Server: &Server{
318 Clients: map[uint16]*ClientConn{
319 uint16(1): {
320 Account: &Account{
321 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
322 },
323 ID: &[]byte{0, 1},
324 },
325 uint16(2): {
326 Account: &Account{
327 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
328 },
329 ID: &[]byte{0, 2},
330 },
331 },
332 },
333 },
334 t: &Transaction{
335 Fields: []Field{
336 NewField(fieldData, []byte("hai")),
337 },
338 },
339 },
340 want: []Transaction{
341 {
342 clientID: &[]byte{0, 1},
343 Flags: 0x00,
344 IsReply: 0x00,
345 Type: []byte{0, 0x6a},
346 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
347 ErrorCode: []byte{0, 0, 0, 0},
348 Fields: []Field{
349 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
350 },
351 },
352 {
353 clientID: &[]byte{0, 2},
354 Flags: 0x00,
355 IsReply: 0x00,
356 Type: []byte{0, 0x6a},
357 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
358 ErrorCode: []byte{0, 0, 0, 0},
359 Fields: []Field{
360 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361 },
362 },
363 },
364 wantErr: false,
365 },
366 {
367 name: "when user does not have required permission",
368 args: args{
369 cc: &ClientConn{
370 Account: &Account{
371 Access: func() *[]byte {
372 var bits accessBitmap
373 access := bits[:]
374 return &access
375 }(),
376 },
377 Server: &Server{
378 Accounts: map[string]*Account{},
379 },
380 },
381 t: NewTransaction(
382 tranChatSend, &[]byte{0, 1},
383 NewField(fieldData, []byte("hai")),
384 ),
385 },
386 want: []Transaction{
387 {
388 Flags: 0x00,
389 IsReply: 0x01,
390 Type: []byte{0, 0x00},
391 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
392 ErrorCode: []byte{0, 0, 0, 1},
393 Fields: []Field{
394 NewField(fieldError, []byte("You are not allowed to participate in chat.")),
395 },
396 },
397 },
398 wantErr: false,
399 },
400 {
401 name: "sends chat msg as emote if fieldChatOptions is set",
402 args: args{
403 cc: &ClientConn{
404 Account: &Account{
405 Access: func() *[]byte {
406 var bits accessBitmap
407 bits.Set(accessSendChat)
408 access := bits[:]
409 return &access
410 }(),
411 },
412 UserName: []byte("Testy McTest"),
413 Server: &Server{
414 Clients: map[uint16]*ClientConn{
415 uint16(1): {
416 Account: &Account{
417 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
418 },
419 ID: &[]byte{0, 1},
420 },
421 uint16(2): {
422 Account: &Account{
423 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
424 },
425 ID: &[]byte{0, 2},
426 },
427 },
428 },
429 },
430 t: &Transaction{
431 Fields: []Field{
432 NewField(fieldData, []byte("performed action")),
433 NewField(fieldChatOptions, []byte{0x00, 0x01}),
434 },
435 },
436 },
437 want: []Transaction{
438 {
439 clientID: &[]byte{0, 1},
440 Flags: 0x00,
441 IsReply: 0x00,
442 Type: []byte{0, 0x6a},
443 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
444 ErrorCode: []byte{0, 0, 0, 0},
445 Fields: []Field{
446 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
447 },
448 },
449 {
450 clientID: &[]byte{0, 2},
451 Flags: 0x00,
452 IsReply: 0x00,
453 Type: []byte{0, 0x6a},
454 ID: []byte{0xf0, 0xc5, 0x34, 0x1e},
455 ErrorCode: []byte{0, 0, 0, 0},
456 Fields: []Field{
457 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
458 },
459 },
460 },
461 wantErr: false,
462 },
463 {
464 name: "only sends chat msg to clients with accessReadChat permission",
465 args: args{
466 cc: &ClientConn{
467 Account: &Account{
468 Access: func() *[]byte {
469 var bits accessBitmap
470 bits.Set(accessSendChat)
471 access := bits[:]
472 return &access
473 }(),
474 },
475 UserName: []byte{0x00, 0x01},
476 Server: &Server{
477 Clients: map[uint16]*ClientConn{
478 uint16(1): {
479 Account: &Account{
480 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
481 },
482 ID: &[]byte{0, 1},
483 },
484 uint16(2): {
485 Account: &Account{
486 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
487 },
488 ID: &[]byte{0, 2},
489 },
490 },
491 },
492 },
493 t: &Transaction{
494 Fields: []Field{
495 NewField(fieldData, []byte("hai")),
496 },
497 },
498 },
499 want: []Transaction{
500 {
501 clientID: &[]byte{0, 1},
502 Flags: 0x00,
503 IsReply: 0x00,
504 Type: []byte{0, 0x6a},
505 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
506 ErrorCode: []byte{0, 0, 0, 0},
507 Fields: []Field{
508 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
509 },
510 },
511 },
512 wantErr: false,
513 },
514 {
515 name: "only sends private chat msg to members of private chat",
516 args: args{
517 cc: &ClientConn{
518 Account: &Account{
519 Access: func() *[]byte {
520 var bits accessBitmap
521 bits.Set(accessSendChat)
522 access := bits[:]
523 return &access
524 }(),
525 },
526 UserName: []byte{0x00, 0x01},
527 Server: &Server{
528 PrivateChats: map[uint32]*PrivateChat{
529 uint32(1): {
530 ClientConn: map[uint16]*ClientConn{
531 uint16(1): {
532 ID: &[]byte{0, 1},
533 },
534 uint16(2): {
535 ID: &[]byte{0, 2},
536 },
537 },
538 },
539 },
540 Clients: map[uint16]*ClientConn{
541 uint16(1): {
542 Account: &Account{
543 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
544 },
545 ID: &[]byte{0, 1},
546 },
547 uint16(2): {
548 Account: &Account{
549 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
550 },
551 ID: &[]byte{0, 2},
552 },
553 uint16(3): {
554 Account: &Account{
555 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
556 },
557 ID: &[]byte{0, 3},
558 },
559 },
560 },
561 },
562 t: &Transaction{
563 Fields: []Field{
564 NewField(fieldData, []byte("hai")),
565 NewField(fieldChatID, []byte{0, 0, 0, 1}),
566 },
567 },
568 },
569 want: []Transaction{
570 {
571 clientID: &[]byte{0, 1},
572 Flags: 0x00,
573 IsReply: 0x00,
574 Type: []byte{0, 0x6a},
575 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
576 ErrorCode: []byte{0, 0, 0, 0},
577 Fields: []Field{
578 NewField(fieldChatID, []byte{0, 0, 0, 1}),
579 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
580 },
581 },
582 {
583 clientID: &[]byte{0, 2},
584 Flags: 0x00,
585 IsReply: 0x00,
586 Type: []byte{0, 0x6a},
587 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
588 ErrorCode: []byte{0, 0, 0, 0},
589 Fields: []Field{
590 NewField(fieldChatID, []byte{0, 0, 0, 1}),
591 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
592 },
593 },
594 },
595 wantErr: false,
596 },
597 }
598 for _, tt := range tests {
599 t.Run(tt.name, func(t *testing.T) {
600 got, err := HandleChatSend(tt.args.cc, tt.args.t)
601
602 if (err != nil) != tt.wantErr {
603 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
604 return
605 }
606 tranAssertEqual(t, tt.want, got)
607 })
608 }
609 }
610
611 func TestHandleGetFileInfo(t *testing.T) {
612 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
613
614 type args struct {
615 cc *ClientConn
616 t *Transaction
617 }
618 tests := []struct {
619 name string
620 args args
621 wantRes []Transaction
622 wantErr bool
623 }{
624 {
625 name: "returns expected fields when a valid file is requested",
626 args: args{
627 cc: &ClientConn{
628 ID: &[]byte{0x00, 0x01},
629 Server: &Server{
630 FS: &OSFileStore{},
631 Config: &Config{
632 FileRoot: func() string {
633 path, _ := os.Getwd()
634 return filepath.Join(path, "/test/config/Files")
635 }(),
636 },
637 },
638 },
639 t: NewTransaction(
640 tranGetFileInfo, nil,
641 NewField(fieldFileName, []byte("testfile.txt")),
642 NewField(fieldFilePath, []byte{0x00, 0x00}),
643 ),
644 },
645 wantRes: []Transaction{
646 {
647 clientID: &[]byte{0, 1},
648 Flags: 0x00,
649 IsReply: 0x01,
650 Type: []byte{0, 0xce},
651 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
652 ErrorCode: []byte{0, 0, 0, 0},
653 Fields: []Field{
654 NewField(fieldFileName, []byte("testfile.txt")),
655 NewField(fieldFileTypeString, []byte("Text File")),
656 NewField(fieldFileCreatorString, []byte("ttxt")),
657 NewField(fieldFileComment, []byte{}),
658 NewField(fieldFileType, []byte("TEXT")),
659 NewField(fieldFileCreateDate, make([]byte, 8)),
660 NewField(fieldFileModifyDate, make([]byte, 8)),
661 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
662 },
663 },
664 },
665 wantErr: false,
666 },
667 }
668 for _, tt := range tests {
669 t.Run(tt.name, func(t *testing.T) {
670 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
671
672 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
673 if (err != nil) != tt.wantErr {
674 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
675 return
676 }
677
678 // Clear the fileWrapper timestamp fields to work around problems running the tests in multiple timezones
679 // TODO: revisit how to test this by mocking the stat calls
680 gotRes[0].Fields[5].Data = make([]byte, 8)
681 gotRes[0].Fields[6].Data = make([]byte, 8)
682 if !assert.Equal(t, tt.wantRes, gotRes) {
683 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
684 }
685 })
686 }
687 }
688
689 func TestHandleNewFolder(t *testing.T) {
690 type args struct {
691 cc *ClientConn
692 t *Transaction
693 }
694 tests := []struct {
695 name string
696 args args
697 wantRes []Transaction
698 wantErr bool
699 }{
700 {
701 name: "without required permission",
702 args: args{
703 cc: &ClientConn{
704 Account: &Account{
705 Access: func() *[]byte {
706 var bits accessBitmap
707 access := bits[:]
708 return &access
709 }(),
710 },
711 },
712 t: NewTransaction(
713 accessCreateFolder,
714 &[]byte{0, 0},
715 ),
716 },
717 wantRes: []Transaction{
718 {
719 Flags: 0x00,
720 IsReply: 0x01,
721 Type: []byte{0, 0x00},
722 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
723 ErrorCode: []byte{0, 0, 0, 1},
724 Fields: []Field{
725 NewField(fieldError, []byte("You are not allowed to create folders.")),
726 },
727 },
728 },
729 wantErr: false,
730 },
731 {
732 name: "when path is nested",
733 args: args{
734 cc: &ClientConn{
735 Account: &Account{
736 Access: func() *[]byte {
737 var bits accessBitmap
738 bits.Set(accessCreateFolder)
739 access := bits[:]
740 return &access
741 }(),
742 },
743 ID: &[]byte{0, 1},
744 Server: &Server{
745 Config: &Config{
746 FileRoot: "/Files/",
747 },
748 FS: func() *MockFileStore {
749 mfs := &MockFileStore{}
750 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
751 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
752 return mfs
753 }(),
754 },
755 },
756 t: NewTransaction(
757 tranNewFolder, &[]byte{0, 1},
758 NewField(fieldFileName, []byte("testFolder")),
759 NewField(fieldFilePath, []byte{
760 0x00, 0x01,
761 0x00, 0x00,
762 0x03,
763 0x61, 0x61, 0x61,
764 }),
765 ),
766 },
767 wantRes: []Transaction{
768 {
769 clientID: &[]byte{0, 1},
770 Flags: 0x00,
771 IsReply: 0x01,
772 Type: []byte{0, 0xcd},
773 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
774 ErrorCode: []byte{0, 0, 0, 0},
775 },
776 },
777 wantErr: false,
778 },
779 {
780 name: "when path is not nested",
781 args: args{
782 cc: &ClientConn{
783 Account: &Account{
784 Access: func() *[]byte {
785 var bits accessBitmap
786 bits.Set(accessCreateFolder)
787 access := bits[:]
788 return &access
789 }(),
790 },
791 ID: &[]byte{0, 1},
792 Server: &Server{
793 Config: &Config{
794 FileRoot: "/Files",
795 },
796 FS: func() *MockFileStore {
797 mfs := &MockFileStore{}
798 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
799 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
800 return mfs
801 }(),
802 },
803 },
804 t: NewTransaction(
805 tranNewFolder, &[]byte{0, 1},
806 NewField(fieldFileName, []byte("testFolder")),
807 ),
808 },
809 wantRes: []Transaction{
810 {
811 clientID: &[]byte{0, 1},
812 Flags: 0x00,
813 IsReply: 0x01,
814 Type: []byte{0, 0xcd},
815 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
816 ErrorCode: []byte{0, 0, 0, 0},
817 },
818 },
819 wantErr: false,
820 },
821 {
822 name: "when UnmarshalBinary returns an err",
823 args: args{
824 cc: &ClientConn{
825 Account: &Account{
826 Access: func() *[]byte {
827 var bits accessBitmap
828 bits.Set(accessCreateFolder)
829 access := bits[:]
830 return &access
831 }(),
832 },
833 ID: &[]byte{0, 1},
834 Server: &Server{
835 Config: &Config{
836 FileRoot: "/Files/",
837 },
838 FS: func() *MockFileStore {
839 mfs := &MockFileStore{}
840 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
841 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
842 return mfs
843 }(),
844 },
845 },
846 t: NewTransaction(
847 tranNewFolder, &[]byte{0, 1},
848 NewField(fieldFileName, []byte("testFolder")),
849 NewField(fieldFilePath, []byte{
850 0x00,
851 }),
852 ),
853 },
854 wantRes: []Transaction{},
855 wantErr: true,
856 },
857 {
858 name: "fieldFileName does not allow directory traversal",
859 args: args{
860 cc: &ClientConn{
861 Account: &Account{
862 Access: func() *[]byte {
863 var bits accessBitmap
864 bits.Set(accessCreateFolder)
865 access := bits[:]
866 return &access
867 }(),
868 },
869 ID: &[]byte{0, 1},
870 Server: &Server{
871 Config: &Config{
872 FileRoot: "/Files/",
873 },
874 FS: func() *MockFileStore {
875 mfs := &MockFileStore{}
876 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
877 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
878 return mfs
879 }(),
880 },
881 },
882 t: NewTransaction(
883 tranNewFolder, &[]byte{0, 1},
884 NewField(fieldFileName, []byte("../../testFolder")),
885 ),
886 },
887 wantRes: []Transaction{
888 {
889 clientID: &[]byte{0, 1},
890 Flags: 0x00,
891 IsReply: 0x01,
892 Type: []byte{0, 0xcd},
893 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
894 ErrorCode: []byte{0, 0, 0, 0},
895 },
896 }, wantErr: false,
897 },
898 {
899 name: "fieldFilePath does not allow directory traversal",
900 args: args{
901 cc: &ClientConn{
902 Account: &Account{
903 Access: func() *[]byte {
904 var bits accessBitmap
905 bits.Set(accessCreateFolder)
906 access := bits[:]
907 return &access
908 }(),
909 },
910 ID: &[]byte{0, 1},
911 Server: &Server{
912 Config: &Config{
913 FileRoot: "/Files/",
914 },
915 FS: func() *MockFileStore {
916 mfs := &MockFileStore{}
917 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
918 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
919 return mfs
920 }(),
921 },
922 },
923 t: NewTransaction(
924 tranNewFolder, &[]byte{0, 1},
925 NewField(fieldFileName, []byte("testFolder")),
926 NewField(fieldFilePath, []byte{
927 0x00, 0x02,
928 0x00, 0x00,
929 0x03,
930 0x2e, 0x2e, 0x2f,
931 0x00, 0x00,
932 0x03,
933 0x66, 0x6f, 0x6f,
934 }),
935 ),
936 },
937 wantRes: []Transaction{
938 {
939 clientID: &[]byte{0, 1},
940 Flags: 0x00,
941 IsReply: 0x01,
942 Type: []byte{0, 0xcd},
943 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
944 ErrorCode: []byte{0, 0, 0, 0},
945 },
946 }, wantErr: false,
947 },
948 }
949 for _, tt := range tests {
950 t.Run(tt.name, func(t *testing.T) {
951
952 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
953 if (err != nil) != tt.wantErr {
954 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
955 return
956 }
957
958 if !tranAssertEqual(t, tt.wantRes, gotRes) {
959 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
960 }
961 })
962 }
963 }
964
965 func TestHandleUploadFile(t *testing.T) {
966 type args struct {
967 cc *ClientConn
968 t *Transaction
969 }
970 tests := []struct {
971 name string
972 args args
973 wantRes []Transaction
974 wantErr bool
975 }{
976 {
977 name: "when request is valid and user has Upload Anywhere permission",
978 args: args{
979 cc: &ClientConn{
980 Server: &Server{
981 FileTransfers: map[uint32]*FileTransfer{},
982 },
983 Account: &Account{
984 Access: func() *[]byte {
985 var bits accessBitmap
986 bits.Set(accessUploadFile)
987 bits.Set(accessUploadAnywhere)
988 access := bits[:]
989 return &access
990 }(),
991 },
992 },
993 t: NewTransaction(
994 tranUploadFile, &[]byte{0, 1},
995 NewField(fieldFileName, []byte("testFile")),
996 NewField(fieldFilePath, []byte{
997 0x00, 0x01,
998 0x00, 0x00,
999 0x03,
1000 0x2e, 0x2e, 0x2f,
1001 }),
1002 ),
1003 },
1004 wantRes: []Transaction{
1005 {
1006 Flags: 0x00,
1007 IsReply: 0x01,
1008 Type: []byte{0, 0xcb},
1009 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1010 ErrorCode: []byte{0, 0, 0, 0},
1011 Fields: []Field{
1012 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
1013 },
1014 },
1015 },
1016 wantErr: false,
1017 },
1018 {
1019 name: "when user does not have required access",
1020 args: args{
1021 cc: &ClientConn{
1022 Account: &Account{
1023 Access: func() *[]byte {
1024 var bits accessBitmap
1025 access := bits[:]
1026 return &access
1027 }(),
1028 },
1029 Server: &Server{
1030 FileTransfers: map[uint32]*FileTransfer{},
1031 },
1032 },
1033 t: NewTransaction(
1034 tranUploadFile, &[]byte{0, 1},
1035 NewField(fieldFileName, []byte("testFile")),
1036 NewField(fieldFilePath, []byte{
1037 0x00, 0x01,
1038 0x00, 0x00,
1039 0x03,
1040 0x2e, 0x2e, 0x2f,
1041 }),
1042 ),
1043 },
1044 wantRes: []Transaction{
1045 {
1046 Flags: 0x00,
1047 IsReply: 0x01,
1048 Type: []byte{0, 0x00},
1049 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1050 ErrorCode: []byte{0, 0, 0, 1},
1051 Fields: []Field{
1052 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
1053 },
1054 },
1055 },
1056 wantErr: false,
1057 },
1058 }
1059 for _, tt := range tests {
1060 t.Run(tt.name, func(t *testing.T) {
1061 rand.Seed(1)
1062 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
1063 if (err != nil) != tt.wantErr {
1064 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
1065 return
1066 }
1067
1068 tranAssertEqual(t, tt.wantRes, gotRes)
1069
1070 })
1071 }
1072 }
1073
1074 func TestHandleMakeAlias(t *testing.T) {
1075 type args struct {
1076 cc *ClientConn
1077 t *Transaction
1078 }
1079 tests := []struct {
1080 name string
1081 args args
1082 wantRes []Transaction
1083 wantErr bool
1084 }{
1085 {
1086 name: "with valid input and required permissions",
1087 args: args{
1088 cc: &ClientConn{
1089 logger: NewTestLogger(),
1090 Account: &Account{
1091 Access: func() *[]byte {
1092 var bits accessBitmap
1093 bits.Set(accessMakeAlias)
1094 access := bits[:]
1095 return &access
1096 }(),
1097 },
1098 Server: &Server{
1099 Config: &Config{
1100 FileRoot: func() string {
1101 path, _ := os.Getwd()
1102 return path + "/test/config/Files"
1103 }(),
1104 },
1105 Logger: NewTestLogger(),
1106 FS: func() *MockFileStore {
1107 mfs := &MockFileStore{}
1108 path, _ := os.Getwd()
1109 mfs.On(
1110 "Symlink",
1111 path+"/test/config/Files/foo/testFile",
1112 path+"/test/config/Files/bar/testFile",
1113 ).Return(nil)
1114 return mfs
1115 }(),
1116 },
1117 },
1118 t: NewTransaction(
1119 tranMakeFileAlias, &[]byte{0, 1},
1120 NewField(fieldFileName, []byte("testFile")),
1121 NewField(fieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1122 NewField(fieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1123 ),
1124 },
1125 wantRes: []Transaction{
1126 {
1127 Flags: 0x00,
1128 IsReply: 0x01,
1129 Type: []byte{0, 0xd1},
1130 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1131 ErrorCode: []byte{0, 0, 0, 0},
1132 Fields: []Field(nil),
1133 },
1134 },
1135 wantErr: false,
1136 },
1137 {
1138 name: "when symlink returns an error",
1139 args: args{
1140 cc: &ClientConn{
1141 logger: NewTestLogger(),
1142 Account: &Account{
1143 Access: func() *[]byte {
1144 var bits accessBitmap
1145 bits.Set(accessMakeAlias)
1146 access := bits[:]
1147 return &access
1148 }(),
1149 },
1150 Server: &Server{
1151 Config: &Config{
1152 FileRoot: func() string {
1153 path, _ := os.Getwd()
1154 return path + "/test/config/Files"
1155 }(),
1156 },
1157 Logger: NewTestLogger(),
1158 FS: func() *MockFileStore {
1159 mfs := &MockFileStore{}
1160 path, _ := os.Getwd()
1161 mfs.On(
1162 "Symlink",
1163 path+"/test/config/Files/foo/testFile",
1164 path+"/test/config/Files/bar/testFile",
1165 ).Return(errors.New("ohno"))
1166 return mfs
1167 }(),
1168 },
1169 },
1170 t: NewTransaction(
1171 tranMakeFileAlias, &[]byte{0, 1},
1172 NewField(fieldFileName, []byte("testFile")),
1173 NewField(fieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1174 NewField(fieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1175 ),
1176 },
1177 wantRes: []Transaction{
1178 {
1179 Flags: 0x00,
1180 IsReply: 0x01,
1181 Type: []byte{0, 0x00},
1182 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1183 ErrorCode: []byte{0, 0, 0, 1},
1184 Fields: []Field{
1185 NewField(fieldError, []byte("Error creating alias")),
1186 },
1187 },
1188 },
1189 wantErr: false,
1190 },
1191 {
1192 name: "when user does not have required permission",
1193 args: args{
1194 cc: &ClientConn{
1195 logger: NewTestLogger(),
1196 Account: &Account{
1197 Access: func() *[]byte {
1198 var bits accessBitmap
1199 access := bits[:]
1200 return &access
1201 }(),
1202 },
1203 Server: &Server{
1204 Config: &Config{
1205 FileRoot: func() string {
1206 path, _ := os.Getwd()
1207 return path + "/test/config/Files"
1208 }(),
1209 },
1210 },
1211 },
1212 t: NewTransaction(
1213 tranMakeFileAlias, &[]byte{0, 1},
1214 NewField(fieldFileName, []byte("testFile")),
1215 NewField(fieldFilePath, []byte{
1216 0x00, 0x01,
1217 0x00, 0x00,
1218 0x03,
1219 0x2e, 0x2e, 0x2e,
1220 }),
1221 NewField(fieldFileNewPath, []byte{
1222 0x00, 0x01,
1223 0x00, 0x00,
1224 0x03,
1225 0x2e, 0x2e, 0x2e,
1226 }),
1227 ),
1228 },
1229 wantRes: []Transaction{
1230 {
1231 Flags: 0x00,
1232 IsReply: 0x01,
1233 Type: []byte{0, 0x00},
1234 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1235 ErrorCode: []byte{0, 0, 0, 1},
1236 Fields: []Field{
1237 NewField(fieldError, []byte("You are not allowed to make aliases.")),
1238 },
1239 },
1240 },
1241 wantErr: false,
1242 },
1243 }
1244 for _, tt := range tests {
1245 t.Run(tt.name, func(t *testing.T) {
1246 gotRes, err := HandleMakeAlias(tt.args.cc, tt.args.t)
1247 if (err != nil) != tt.wantErr {
1248 t.Errorf("HandleMakeAlias(%v, %v)", tt.args.cc, tt.args.t)
1249 return
1250 }
1251
1252 tranAssertEqual(t, tt.wantRes, gotRes)
1253 })
1254 }
1255 }
1256
1257 func TestHandleGetUser(t *testing.T) {
1258 type args struct {
1259 cc *ClientConn
1260 t *Transaction
1261 }
1262 tests := []struct {
1263 name string
1264 args args
1265 wantRes []Transaction
1266 wantErr assert.ErrorAssertionFunc
1267 }{
1268 {
1269 name: "when account is valid",
1270 args: args{
1271 cc: &ClientConn{
1272 Account: &Account{
1273 Access: func() *[]byte {
1274 var bits accessBitmap
1275 bits.Set(accessOpenUser)
1276 access := bits[:]
1277 return &access
1278 }(),
1279 },
1280 Server: &Server{
1281 Accounts: map[string]*Account{
1282 "guest": {
1283 Login: "guest",
1284 Name: "Guest",
1285 Password: "password",
1286 Access: &[]byte{1},
1287 },
1288 },
1289 },
1290 },
1291 t: NewTransaction(
1292 tranGetUser, &[]byte{0, 1},
1293 NewField(fieldUserLogin, []byte("guest")),
1294 ),
1295 },
1296 wantRes: []Transaction{
1297 {
1298 Flags: 0x00,
1299 IsReply: 0x01,
1300 Type: []byte{0x01, 0x60},
1301 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1302 ErrorCode: []byte{0, 0, 0, 0},
1303 Fields: []Field{
1304 NewField(fieldUserName, []byte("Guest")),
1305 NewField(fieldUserLogin, negateString([]byte("guest"))),
1306 NewField(fieldUserPassword, []byte("password")),
1307 NewField(fieldUserAccess, []byte{1}),
1308 },
1309 },
1310 },
1311 wantErr: assert.NoError,
1312 },
1313 {
1314 name: "when user does not have required permission",
1315 args: args{
1316 cc: &ClientConn{
1317 Account: &Account{
1318 Access: func() *[]byte {
1319 var bits accessBitmap
1320 access := bits[:]
1321 return &access
1322 }(),
1323 },
1324 Server: &Server{
1325 Accounts: map[string]*Account{},
1326 },
1327 },
1328 t: NewTransaction(
1329 tranGetUser, &[]byte{0, 1},
1330 NewField(fieldUserLogin, []byte("nonExistentUser")),
1331 ),
1332 },
1333 wantRes: []Transaction{
1334 {
1335 Flags: 0x00,
1336 IsReply: 0x01,
1337 Type: []byte{0, 0x00},
1338 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1339 ErrorCode: []byte{0, 0, 0, 1},
1340 Fields: []Field{
1341 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1342 },
1343 },
1344 },
1345 wantErr: assert.NoError,
1346 },
1347 {
1348 name: "when account does not exist",
1349 args: args{
1350 cc: &ClientConn{
1351 Account: &Account{
1352 Access: func() *[]byte {
1353 var bits accessBitmap
1354 bits.Set(accessOpenUser)
1355 access := bits[:]
1356 return &access
1357 }(),
1358 },
1359 Server: &Server{
1360 Accounts: map[string]*Account{},
1361 },
1362 },
1363 t: NewTransaction(
1364 tranGetUser, &[]byte{0, 1},
1365 NewField(fieldUserLogin, []byte("nonExistentUser")),
1366 ),
1367 },
1368 wantRes: []Transaction{
1369 {
1370 Flags: 0x00,
1371 IsReply: 0x01,
1372 Type: []byte{0, 0x00},
1373 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1374 ErrorCode: []byte{0, 0, 0, 1},
1375 Fields: []Field{
1376 NewField(fieldError, []byte("Account does not exist.")),
1377 },
1378 },
1379 },
1380 wantErr: assert.NoError,
1381 },
1382 }
1383 for _, tt := range tests {
1384 t.Run(tt.name, func(t *testing.T) {
1385 gotRes, err := HandleGetUser(tt.args.cc, tt.args.t)
1386 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetUser(%v, %v)", tt.args.cc, tt.args.t)) {
1387 return
1388 }
1389
1390 tranAssertEqual(t, tt.wantRes, gotRes)
1391 })
1392 }
1393 }
1394
1395 func TestHandleDeleteUser(t *testing.T) {
1396 type args struct {
1397 cc *ClientConn
1398 t *Transaction
1399 }
1400 tests := []struct {
1401 name string
1402 args args
1403 wantRes []Transaction
1404 wantErr assert.ErrorAssertionFunc
1405 }{
1406 {
1407 name: "when user dataFile",
1408 args: args{
1409 cc: &ClientConn{
1410 Account: &Account{
1411 Access: func() *[]byte {
1412 var bits accessBitmap
1413 bits.Set(accessDeleteUser)
1414 access := bits[:]
1415 return &access
1416 }(),
1417 },
1418 Server: &Server{
1419 Accounts: map[string]*Account{
1420 "testuser": {
1421 Login: "testuser",
1422 Name: "Testy McTest",
1423 Password: "password",
1424 Access: &[]byte{1},
1425 },
1426 },
1427 FS: func() *MockFileStore {
1428 mfs := &MockFileStore{}
1429 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1430 return mfs
1431 }(),
1432 },
1433 },
1434 t: NewTransaction(
1435 tranDeleteUser, &[]byte{0, 1},
1436 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1437 ),
1438 },
1439 wantRes: []Transaction{
1440 {
1441 Flags: 0x00,
1442 IsReply: 0x01,
1443 Type: []byte{0x1, 0x5f},
1444 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1445 ErrorCode: []byte{0, 0, 0, 0},
1446 Fields: []Field(nil),
1447 },
1448 },
1449 wantErr: assert.NoError,
1450 },
1451 {
1452 name: "when user does not have required permission",
1453 args: args{
1454 cc: &ClientConn{
1455 Account: &Account{
1456 Access: func() *[]byte {
1457 var bits accessBitmap
1458 access := bits[:]
1459 return &access
1460 }(),
1461 },
1462 Server: &Server{
1463 Accounts: map[string]*Account{},
1464 },
1465 },
1466 t: NewTransaction(
1467 tranDeleteUser, &[]byte{0, 1},
1468 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1469 ),
1470 },
1471 wantRes: []Transaction{
1472 {
1473 Flags: 0x00,
1474 IsReply: 0x01,
1475 Type: []byte{0, 0x00},
1476 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1477 ErrorCode: []byte{0, 0, 0, 1},
1478 Fields: []Field{
1479 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
1480 },
1481 },
1482 },
1483 wantErr: assert.NoError,
1484 },
1485 }
1486 for _, tt := range tests {
1487 t.Run(tt.name, func(t *testing.T) {
1488 gotRes, err := HandleDeleteUser(tt.args.cc, tt.args.t)
1489 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteUser(%v, %v)", tt.args.cc, tt.args.t)) {
1490 return
1491 }
1492
1493 tranAssertEqual(t, tt.wantRes, gotRes)
1494 })
1495 }
1496 }
1497
1498 func TestHandleGetMsgs(t *testing.T) {
1499 type args struct {
1500 cc *ClientConn
1501 t *Transaction
1502 }
1503 tests := []struct {
1504 name string
1505 args args
1506 wantRes []Transaction
1507 wantErr assert.ErrorAssertionFunc
1508 }{
1509 {
1510 name: "returns news data",
1511 args: args{
1512 cc: &ClientConn{
1513 Account: &Account{
1514 Access: func() *[]byte {
1515 var bits accessBitmap
1516 bits.Set(accessNewsReadArt)
1517 access := bits[:]
1518 return &access
1519 }(),
1520 },
1521 Server: &Server{
1522 FlatNews: []byte("TEST"),
1523 },
1524 },
1525 t: NewTransaction(
1526 tranGetMsgs, &[]byte{0, 1},
1527 ),
1528 },
1529 wantRes: []Transaction{
1530 {
1531 Flags: 0x00,
1532 IsReply: 0x01,
1533 Type: []byte{0, 0x65},
1534 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1535 ErrorCode: []byte{0, 0, 0, 0},
1536 Fields: []Field{
1537 NewField(fieldData, []byte("TEST")),
1538 },
1539 },
1540 },
1541 wantErr: assert.NoError,
1542 },
1543 {
1544 name: "when user does not have required permission",
1545 args: args{
1546 cc: &ClientConn{
1547 Account: &Account{
1548 Access: func() *[]byte {
1549 var bits accessBitmap
1550 access := bits[:]
1551 return &access
1552 }(),
1553 },
1554 Server: &Server{
1555 Accounts: map[string]*Account{},
1556 },
1557 },
1558 t: NewTransaction(
1559 tranGetMsgs, &[]byte{0, 1},
1560 ),
1561 },
1562 wantRes: []Transaction{
1563 {
1564 Flags: 0x00,
1565 IsReply: 0x01,
1566 Type: []byte{0, 0x00},
1567 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1568 ErrorCode: []byte{0, 0, 0, 1},
1569 Fields: []Field{
1570 NewField(fieldError, []byte("You are not allowed to read news.")),
1571 },
1572 },
1573 },
1574 wantErr: assert.NoError,
1575 },
1576 }
1577 for _, tt := range tests {
1578 t.Run(tt.name, func(t *testing.T) {
1579 gotRes, err := HandleGetMsgs(tt.args.cc, tt.args.t)
1580 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetMsgs(%v, %v)", tt.args.cc, tt.args.t)) {
1581 return
1582 }
1583
1584 tranAssertEqual(t, tt.wantRes, gotRes)
1585 })
1586 }
1587 }
1588
1589 func TestHandleNewUser(t *testing.T) {
1590 type args struct {
1591 cc *ClientConn
1592 t *Transaction
1593 }
1594 tests := []struct {
1595 name string
1596 args args
1597 wantRes []Transaction
1598 wantErr assert.ErrorAssertionFunc
1599 }{
1600 {
1601 name: "when user does not have required permission",
1602 args: args{
1603 cc: &ClientConn{
1604 Account: &Account{
1605 Access: func() *[]byte {
1606 var bits accessBitmap
1607 access := bits[:]
1608 return &access
1609 }(),
1610 },
1611 Server: &Server{
1612 Accounts: map[string]*Account{},
1613 },
1614 },
1615 t: NewTransaction(
1616 tranNewUser, &[]byte{0, 1},
1617 ),
1618 },
1619 wantRes: []Transaction{
1620 {
1621 Flags: 0x00,
1622 IsReply: 0x01,
1623 Type: []byte{0, 0x00},
1624 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1625 ErrorCode: []byte{0, 0, 0, 1},
1626 Fields: []Field{
1627 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1628 },
1629 },
1630 },
1631 wantErr: assert.NoError,
1632 },
1633 }
1634 for _, tt := range tests {
1635 t.Run(tt.name, func(t *testing.T) {
1636 gotRes, err := HandleNewUser(tt.args.cc, tt.args.t)
1637 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewUser(%v, %v)", tt.args.cc, tt.args.t)) {
1638 return
1639 }
1640
1641 tranAssertEqual(t, tt.wantRes, gotRes)
1642 })
1643 }
1644 }
1645
1646 func TestHandleListUsers(t *testing.T) {
1647 type args struct {
1648 cc *ClientConn
1649 t *Transaction
1650 }
1651 tests := []struct {
1652 name string
1653 args args
1654 wantRes []Transaction
1655 wantErr assert.ErrorAssertionFunc
1656 }{
1657 {
1658 name: "when user does not have required permission",
1659 args: args{
1660 cc: &ClientConn{
1661 Account: &Account{
1662 Access: func() *[]byte {
1663 var bits accessBitmap
1664 access := bits[:]
1665 return &access
1666 }(),
1667 },
1668 Server: &Server{
1669 Accounts: map[string]*Account{},
1670 },
1671 },
1672 t: NewTransaction(
1673 tranNewUser, &[]byte{0, 1},
1674 ),
1675 },
1676 wantRes: []Transaction{
1677 {
1678 Flags: 0x00,
1679 IsReply: 0x01,
1680 Type: []byte{0, 0x00},
1681 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1682 ErrorCode: []byte{0, 0, 0, 1},
1683 Fields: []Field{
1684 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1685 },
1686 },
1687 },
1688 wantErr: assert.NoError,
1689 },
1690 }
1691 for _, tt := range tests {
1692 t.Run(tt.name, func(t *testing.T) {
1693 gotRes, err := HandleListUsers(tt.args.cc, tt.args.t)
1694 if !tt.wantErr(t, err, fmt.Sprintf("HandleListUsers(%v, %v)", tt.args.cc, tt.args.t)) {
1695 return
1696 }
1697
1698 tranAssertEqual(t, tt.wantRes, gotRes)
1699 })
1700 }
1701 }
1702
1703 func TestHandleDownloadFile(t *testing.T) {
1704 type args struct {
1705 cc *ClientConn
1706 t *Transaction
1707 }
1708 tests := []struct {
1709 name string
1710 args args
1711 wantRes []Transaction
1712 wantErr assert.ErrorAssertionFunc
1713 }{
1714 {
1715 name: "when user does not have required permission",
1716 args: args{
1717 cc: &ClientConn{
1718 Account: &Account{
1719 Access: func() *[]byte {
1720 var bits accessBitmap
1721 access := bits[:]
1722 return &access
1723 }(),
1724 },
1725 Server: &Server{},
1726 },
1727 t: NewTransaction(tranDownloadFile, &[]byte{0, 1}),
1728 },
1729 wantRes: []Transaction{
1730 {
1731 Flags: 0x00,
1732 IsReply: 0x01,
1733 Type: []byte{0, 0x00},
1734 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1735 ErrorCode: []byte{0, 0, 0, 1},
1736 Fields: []Field{
1737 NewField(fieldError, []byte("You are not allowed to download files.")),
1738 },
1739 },
1740 },
1741 wantErr: assert.NoError,
1742 },
1743 {
1744 name: "with a valid file",
1745 args: args{
1746 cc: &ClientConn{
1747 Transfers: make(map[int][]*FileTransfer),
1748 Account: &Account{
1749 Access: func() *[]byte {
1750 var bits accessBitmap
1751 bits.Set(accessDownloadFile)
1752 access := bits[:]
1753 return &access
1754 }(),
1755 },
1756 Server: &Server{
1757 FS: &OSFileStore{},
1758 FileTransfers: make(map[uint32]*FileTransfer),
1759 Config: &Config{
1760 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1761 },
1762 Accounts: map[string]*Account{},
1763 },
1764 },
1765 t: NewTransaction(
1766 accessDownloadFile,
1767 &[]byte{0, 1},
1768 NewField(fieldFileName, []byte("testfile.txt")),
1769 NewField(fieldFilePath, []byte{0x0, 0x00}),
1770 ),
1771 },
1772 wantRes: []Transaction{
1773 {
1774 Flags: 0x00,
1775 IsReply: 0x01,
1776 Type: []byte{0, 0x2},
1777 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1778 ErrorCode: []byte{0, 0, 0, 0},
1779 Fields: []Field{
1780 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1781 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1782 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1783 NewField(fieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1784 },
1785 },
1786 },
1787 wantErr: assert.NoError,
1788 },
1789 {
1790 name: "when client requests to resume 1k test file at offset 256",
1791 args: args{
1792 cc: &ClientConn{
1793 Transfers: make(map[int][]*FileTransfer),
1794 Account: &Account{
1795 Access: func() *[]byte {
1796 var bits accessBitmap
1797 bits.Set(accessDownloadFile)
1798 access := bits[:]
1799 return &access
1800 }(),
1801 },
1802 Server: &Server{
1803 FS: &OSFileStore{},
1804 // FS: func() *MockFileStore {
1805 // path, _ := os.Getwd()
1806 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1807 // if err != nil {
1808 // panic(err)
1809 // }
1810 //
1811 // mfi := &MockFileInfo{}
1812 // mfi.On("Mode").Return(fs.FileMode(0))
1813 // mfs := &MockFileStore{}
1814 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1815 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1816 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1817 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1818 //
1819 // return mfs
1820 // }(),
1821 FileTransfers: make(map[uint32]*FileTransfer),
1822 Config: &Config{
1823 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1824 },
1825 Accounts: map[string]*Account{},
1826 },
1827 },
1828 t: NewTransaction(
1829 accessDownloadFile,
1830 &[]byte{0, 1},
1831 NewField(fieldFileName, []byte("testfile-1k")),
1832 NewField(fieldFilePath, []byte{0x00, 0x00}),
1833 NewField(
1834 fieldFileResumeData,
1835 func() []byte {
1836 frd := FileResumeData{
1837 Format: [4]byte{},
1838 Version: [2]byte{},
1839 RSVD: [34]byte{},
1840 ForkCount: [2]byte{0, 2},
1841 ForkInfoList: []ForkInfoList{
1842 {
1843 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1844 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
1845 RSVDA: [4]byte{},
1846 RSVDB: [4]byte{},
1847 },
1848 {
1849 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1850 DataSize: [4]byte{0, 0, 0, 0},
1851 RSVDA: [4]byte{},
1852 RSVDB: [4]byte{},
1853 },
1854 },
1855 }
1856 b, _ := frd.BinaryMarshal()
1857 return b
1858 }(),
1859 ),
1860 ),
1861 },
1862 wantRes: []Transaction{
1863 {
1864 Flags: 0x00,
1865 IsReply: 0x01,
1866 Type: []byte{0, 0x2},
1867 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1868 ErrorCode: []byte{0, 0, 0, 0},
1869 Fields: []Field{
1870 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1871 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1872 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1873 NewField(fieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
1874 },
1875 },
1876 },
1877 wantErr: assert.NoError,
1878 },
1879 }
1880 for _, tt := range tests {
1881 t.Run(tt.name, func(t *testing.T) {
1882 gotRes, err := HandleDownloadFile(tt.args.cc, tt.args.t)
1883 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadFile(%v, %v)", tt.args.cc, tt.args.t)) {
1884 return
1885 }
1886
1887 tranAssertEqual(t, tt.wantRes, gotRes)
1888 })
1889 }
1890 }
1891
1892 func TestHandleUpdateUser(t *testing.T) {
1893 type args struct {
1894 cc *ClientConn
1895 t *Transaction
1896 }
1897 tests := []struct {
1898 name string
1899 args args
1900 wantRes []Transaction
1901 wantErr assert.ErrorAssertionFunc
1902 }{
1903 {
1904 name: "when action is create user without required permission",
1905 args: args{
1906 cc: &ClientConn{
1907 logger: NewTestLogger(),
1908 Server: &Server{
1909 Logger: NewTestLogger(),
1910 },
1911 Account: &Account{
1912 Access: func() *[]byte {
1913 var bits accessBitmap
1914 access := bits[:]
1915 return &access
1916 }(),
1917 },
1918 },
1919 t: NewTransaction(
1920 tranUpdateUser,
1921 &[]byte{0, 0},
1922 NewField(fieldData, []byte{
1923 0x00, 0x04, // field count
1924
1925 0x00, 0x69, // fieldUserLogin = 105
1926 0x00, 0x03,
1927 0x9d, 0x9d, 0x9d,
1928
1929 0x00, 0x6a, // fieldUserPassword = 106
1930 0x00, 0x03,
1931 0x9c, 0x9c, 0x9c,
1932
1933 0x00, 0x66, // fieldUserName = 102
1934 0x00, 0x03,
1935 0x61, 0x61, 0x61,
1936
1937 0x00, 0x6e, // fieldUserAccess = 110
1938 0x00, 0x08,
1939 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1940 }),
1941 ),
1942 },
1943 wantRes: []Transaction{
1944 {
1945 Flags: 0x00,
1946 IsReply: 0x01,
1947 Type: []byte{0, 0x00},
1948 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1949 ErrorCode: []byte{0, 0, 0, 1},
1950 Fields: []Field{
1951 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1952 },
1953 },
1954 },
1955 wantErr: assert.NoError,
1956 },
1957 {
1958 name: "when action is modify user without required permission",
1959 args: args{
1960 cc: &ClientConn{
1961 logger: NewTestLogger(),
1962 Server: &Server{
1963 Logger: NewTestLogger(),
1964 Accounts: map[string]*Account{
1965 "bbb": {},
1966 },
1967 },
1968 Account: &Account{
1969 Access: func() *[]byte {
1970 var bits accessBitmap
1971 access := bits[:]
1972 return &access
1973 }(),
1974 },
1975 },
1976 t: NewTransaction(
1977 tranUpdateUser,
1978 &[]byte{0, 0},
1979 NewField(fieldData, []byte{
1980 0x00, 0x04, // field count
1981
1982 0x00, 0x69, // fieldUserLogin = 105
1983 0x00, 0x03,
1984 0x9d, 0x9d, 0x9d,
1985
1986 0x00, 0x6a, // fieldUserPassword = 106
1987 0x00, 0x03,
1988 0x9c, 0x9c, 0x9c,
1989
1990 0x00, 0x66, // fieldUserName = 102
1991 0x00, 0x03,
1992 0x61, 0x61, 0x61,
1993
1994 0x00, 0x6e, // fieldUserAccess = 110
1995 0x00, 0x08,
1996 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1997 }),
1998 ),
1999 },
2000 wantRes: []Transaction{
2001 {
2002 Flags: 0x00,
2003 IsReply: 0x01,
2004 Type: []byte{0, 0x00},
2005 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2006 ErrorCode: []byte{0, 0, 0, 1},
2007 Fields: []Field{
2008 NewField(fieldError, []byte("You are not allowed to modify accounts.")),
2009 },
2010 },
2011 },
2012 wantErr: assert.NoError,
2013 },
2014 {
2015 name: "when action is delete user without required permission",
2016 args: args{
2017 cc: &ClientConn{
2018 logger: NewTestLogger(),
2019 Server: &Server{
2020 Accounts: map[string]*Account{
2021 "bbb": {},
2022 },
2023 },
2024 Account: &Account{
2025 Access: func() *[]byte {
2026 var bits accessBitmap
2027 access := bits[:]
2028 return &access
2029 }(),
2030 },
2031 },
2032 t: NewTransaction(
2033 tranUpdateUser,
2034 &[]byte{0, 0},
2035 NewField(fieldData, []byte{
2036 0x00, 0x01,
2037 0x00, 0x65,
2038 0x00, 0x03,
2039 0x88, 0x9e, 0x8b,
2040 }),
2041 ),
2042 },
2043 wantRes: []Transaction{
2044 {
2045 Flags: 0x00,
2046 IsReply: 0x01,
2047 Type: []byte{0, 0x00},
2048 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2049 ErrorCode: []byte{0, 0, 0, 1},
2050 Fields: []Field{
2051 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
2052 },
2053 },
2054 },
2055 wantErr: assert.NoError,
2056 },
2057 }
2058 for _, tt := range tests {
2059 t.Run(tt.name, func(t *testing.T) {
2060 gotRes, err := HandleUpdateUser(tt.args.cc, tt.args.t)
2061 if !tt.wantErr(t, err, fmt.Sprintf("HandleUpdateUser(%v, %v)", tt.args.cc, tt.args.t)) {
2062 return
2063 }
2064
2065 tranAssertEqual(t, tt.wantRes, gotRes)
2066 })
2067 }
2068 }
2069
2070 func TestHandleDelNewsArt(t *testing.T) {
2071 type args struct {
2072 cc *ClientConn
2073 t *Transaction
2074 }
2075 tests := []struct {
2076 name string
2077 args args
2078 wantRes []Transaction
2079 wantErr assert.ErrorAssertionFunc
2080 }{
2081 {
2082 name: "without required permission",
2083 args: args{
2084 cc: &ClientConn{
2085 Account: &Account{
2086 Access: func() *[]byte {
2087 var bits accessBitmap
2088 access := bits[:]
2089 return &access
2090 }(),
2091 },
2092 },
2093 t: NewTransaction(
2094 tranDelNewsArt,
2095 &[]byte{0, 0},
2096 ),
2097 },
2098 wantRes: []Transaction{
2099 {
2100 Flags: 0x00,
2101 IsReply: 0x01,
2102 Type: []byte{0, 0x00},
2103 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2104 ErrorCode: []byte{0, 0, 0, 1},
2105 Fields: []Field{
2106 NewField(fieldError, []byte("You are not allowed to delete news articles.")),
2107 },
2108 },
2109 },
2110 wantErr: assert.NoError,
2111 },
2112 }
2113 for _, tt := range tests {
2114 t.Run(tt.name, func(t *testing.T) {
2115 gotRes, err := HandleDelNewsArt(tt.args.cc, tt.args.t)
2116 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsArt(%v, %v)", tt.args.cc, tt.args.t)) {
2117 return
2118 }
2119 tranAssertEqual(t, tt.wantRes, gotRes)
2120 })
2121 }
2122 }
2123
2124 func TestHandleDisconnectUser(t *testing.T) {
2125 type args struct {
2126 cc *ClientConn
2127 t *Transaction
2128 }
2129 tests := []struct {
2130 name string
2131 args args
2132 wantRes []Transaction
2133 wantErr assert.ErrorAssertionFunc
2134 }{
2135 {
2136 name: "without required permission",
2137 args: args{
2138 cc: &ClientConn{
2139 Account: &Account{
2140 Access: func() *[]byte {
2141 var bits accessBitmap
2142 access := bits[:]
2143 return &access
2144 }(),
2145 },
2146 },
2147 t: NewTransaction(
2148 tranDelNewsArt,
2149 &[]byte{0, 0},
2150 ),
2151 },
2152 wantRes: []Transaction{
2153 {
2154 Flags: 0x00,
2155 IsReply: 0x01,
2156 Type: []byte{0, 0x00},
2157 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2158 ErrorCode: []byte{0, 0, 0, 1},
2159 Fields: []Field{
2160 NewField(fieldError, []byte("You are not allowed to disconnect users.")),
2161 },
2162 },
2163 },
2164 wantErr: assert.NoError,
2165 },
2166 {
2167 name: "when target user has 'cannot be disconnected' priv",
2168 args: args{
2169 cc: &ClientConn{
2170 Server: &Server{
2171 Clients: map[uint16]*ClientConn{
2172 uint16(1): {
2173 Account: &Account{
2174 Login: "unnamed",
2175 Access: func() *[]byte {
2176 var bits accessBitmap
2177 bits.Set(accessCannotBeDiscon)
2178 access := bits[:]
2179 return &access
2180 }(),
2181 },
2182 },
2183 },
2184 },
2185 Account: &Account{
2186 Access: func() *[]byte {
2187 var bits accessBitmap
2188 bits.Set(accessDisconUser)
2189 access := bits[:]
2190 return &access
2191 }(),
2192 },
2193 },
2194 t: NewTransaction(
2195 tranDelNewsArt,
2196 &[]byte{0, 0},
2197 NewField(fieldUserID, []byte{0, 1}),
2198 ),
2199 },
2200 wantRes: []Transaction{
2201 {
2202 Flags: 0x00,
2203 IsReply: 0x01,
2204 Type: []byte{0, 0x00},
2205 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2206 ErrorCode: []byte{0, 0, 0, 1},
2207 Fields: []Field{
2208 NewField(fieldError, []byte("unnamed is not allowed to be disconnected.")),
2209 },
2210 },
2211 },
2212 wantErr: assert.NoError,
2213 },
2214 }
2215 for _, tt := range tests {
2216 t.Run(tt.name, func(t *testing.T) {
2217 gotRes, err := HandleDisconnectUser(tt.args.cc, tt.args.t)
2218 if !tt.wantErr(t, err, fmt.Sprintf("HandleDisconnectUser(%v, %v)", tt.args.cc, tt.args.t)) {
2219 return
2220 }
2221 tranAssertEqual(t, tt.wantRes, gotRes)
2222 })
2223 }
2224 }
2225
2226 func TestHandleSendInstantMsg(t *testing.T) {
2227 type args struct {
2228 cc *ClientConn
2229 t *Transaction
2230 }
2231 tests := []struct {
2232 name string
2233 args args
2234 wantRes []Transaction
2235 wantErr assert.ErrorAssertionFunc
2236 }{
2237 {
2238 name: "when client 1 sends a message to client 2",
2239 args: args{
2240 cc: &ClientConn{
2241 ID: &[]byte{0, 1},
2242 UserName: []byte("User1"),
2243 Server: &Server{
2244 Clients: map[uint16]*ClientConn{
2245 uint16(2): {
2246 AutoReply: []byte(nil),
2247 },
2248 },
2249 },
2250 },
2251 t: NewTransaction(
2252 tranSendInstantMsg,
2253 &[]byte{0, 1},
2254 NewField(fieldData, []byte("hai")),
2255 NewField(fieldUserID, []byte{0, 2}),
2256 ),
2257 },
2258 wantRes: []Transaction{
2259 *NewTransaction(
2260 tranServerMsg,
2261 &[]byte{0, 2},
2262 NewField(fieldData, []byte("hai")),
2263 NewField(fieldUserName, []byte("User1")),
2264 NewField(fieldUserID, []byte{0, 1}),
2265 NewField(fieldOptions, []byte{0, 1}),
2266 ),
2267 {
2268 clientID: &[]byte{0, 1},
2269 Flags: 0x00,
2270 IsReply: 0x01,
2271 Type: []byte{0x0, 0x6c},
2272 ID: []byte{0, 0, 0, 0},
2273 ErrorCode: []byte{0, 0, 0, 0},
2274 Fields: []Field(nil),
2275 },
2276 },
2277 wantErr: assert.NoError,
2278 },
2279 {
2280 name: "when client 2 has autoreply enabled",
2281 args: args{
2282 cc: &ClientConn{
2283 ID: &[]byte{0, 1},
2284 UserName: []byte("User1"),
2285 Server: &Server{
2286 Clients: map[uint16]*ClientConn{
2287 uint16(2): {
2288 ID: &[]byte{0, 2},
2289 UserName: []byte("User2"),
2290 AutoReply: []byte("autohai"),
2291 },
2292 },
2293 },
2294 },
2295 t: NewTransaction(
2296 tranSendInstantMsg,
2297 &[]byte{0, 1},
2298 NewField(fieldData, []byte("hai")),
2299 NewField(fieldUserID, []byte{0, 2}),
2300 ),
2301 },
2302 wantRes: []Transaction{
2303 *NewTransaction(
2304 tranServerMsg,
2305 &[]byte{0, 2},
2306 NewField(fieldData, []byte("hai")),
2307 NewField(fieldUserName, []byte("User1")),
2308 NewField(fieldUserID, []byte{0, 1}),
2309 NewField(fieldOptions, []byte{0, 1}),
2310 ),
2311 *NewTransaction(
2312 tranServerMsg,
2313 &[]byte{0, 1},
2314 NewField(fieldData, []byte("autohai")),
2315 NewField(fieldUserName, []byte("User2")),
2316 NewField(fieldUserID, []byte{0, 2}),
2317 NewField(fieldOptions, []byte{0, 1}),
2318 ),
2319 {
2320 clientID: &[]byte{0, 1},
2321 Flags: 0x00,
2322 IsReply: 0x01,
2323 Type: []byte{0x0, 0x6c},
2324 ID: []byte{0, 0, 0, 0},
2325 ErrorCode: []byte{0, 0, 0, 0},
2326 Fields: []Field(nil),
2327 },
2328 },
2329 wantErr: assert.NoError,
2330 },
2331 }
2332 for _, tt := range tests {
2333 t.Run(tt.name, func(t *testing.T) {
2334 gotRes, err := HandleSendInstantMsg(tt.args.cc, tt.args.t)
2335 if !tt.wantErr(t, err, fmt.Sprintf("HandleSendInstantMsg(%v, %v)", tt.args.cc, tt.args.t)) {
2336 return
2337 }
2338
2339 tranAssertEqual(t, tt.wantRes, gotRes)
2340 })
2341 }
2342 }
2343
2344 func TestHandleDeleteFile(t *testing.T) {
2345 type args struct {
2346 cc *ClientConn
2347 t *Transaction
2348 }
2349 tests := []struct {
2350 name string
2351 args args
2352 wantRes []Transaction
2353 wantErr assert.ErrorAssertionFunc
2354 }{
2355 {
2356 name: "when user does not have required permission to delete a folder",
2357 args: args{
2358 cc: &ClientConn{
2359 Account: &Account{
2360 Access: func() *[]byte {
2361 var bits accessBitmap
2362 access := bits[:]
2363 return &access
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 return mfs
2386 }(),
2387 Accounts: map[string]*Account{},
2388 },
2389 },
2390 t: NewTransaction(
2391 tranDeleteFile, &[]byte{0, 1},
2392 NewField(fieldFileName, []byte("testfile")),
2393 NewField(fieldFilePath, []byte{
2394 0x00, 0x01,
2395 0x00, 0x00,
2396 0x03,
2397 0x61, 0x61, 0x61,
2398 }),
2399 ),
2400 },
2401 wantRes: []Transaction{
2402 {
2403 Flags: 0x00,
2404 IsReply: 0x01,
2405 Type: []byte{0, 0x00},
2406 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2407 ErrorCode: []byte{0, 0, 0, 1},
2408 Fields: []Field{
2409 NewField(fieldError, []byte("You are not allowed to delete files.")),
2410 },
2411 },
2412 },
2413 wantErr: assert.NoError,
2414 },
2415 {
2416 name: "deletes all associated metadata files",
2417 args: args{
2418 cc: &ClientConn{
2419 Account: &Account{
2420 Access: func() *[]byte {
2421 var bits accessBitmap
2422 bits.Set(accessDeleteFile)
2423 access := bits[:]
2424 return &access
2425 }(),
2426 },
2427 Server: &Server{
2428 Config: &Config{
2429 FileRoot: func() string {
2430 return "/fakeRoot/Files"
2431 }(),
2432 },
2433 FS: func() *MockFileStore {
2434 mfi := &MockFileInfo{}
2435 mfi.On("Mode").Return(fs.FileMode(0))
2436 mfi.On("Size").Return(int64(100))
2437 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2438 mfi.On("IsDir").Return(false)
2439 mfi.On("Name").Return("testfile")
2440
2441 mfs := &MockFileStore{}
2442 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2443 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2444 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2445
2446 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2447 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2448 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2449 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2450
2451 return mfs
2452 }(),
2453 Accounts: map[string]*Account{},
2454 },
2455 },
2456 t: NewTransaction(
2457 tranDeleteFile, &[]byte{0, 1},
2458 NewField(fieldFileName, []byte("testfile")),
2459 NewField(fieldFilePath, []byte{
2460 0x00, 0x01,
2461 0x00, 0x00,
2462 0x03,
2463 0x61, 0x61, 0x61,
2464 }),
2465 ),
2466 },
2467 wantRes: []Transaction{
2468 {
2469 Flags: 0x00,
2470 IsReply: 0x01,
2471 Type: []byte{0x0, 0xcc},
2472 ID: []byte{0x0, 0x0, 0x0, 0x0},
2473 ErrorCode: []byte{0, 0, 0, 0},
2474 Fields: []Field(nil),
2475 },
2476 },
2477 wantErr: assert.NoError,
2478 },
2479 }
2480 for _, tt := range tests {
2481 t.Run(tt.name, func(t *testing.T) {
2482 gotRes, err := HandleDeleteFile(tt.args.cc, tt.args.t)
2483 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteFile(%v, %v)", tt.args.cc, tt.args.t)) {
2484 return
2485 }
2486
2487 tranAssertEqual(t, tt.wantRes, gotRes)
2488
2489 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2490 })
2491 }
2492 }
2493
2494 func TestHandleGetFileNameList(t *testing.T) {
2495 type args struct {
2496 cc *ClientConn
2497 t *Transaction
2498 }
2499 tests := []struct {
2500 name string
2501 args args
2502 wantRes []Transaction
2503 wantErr assert.ErrorAssertionFunc
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() *[]byte {
2511 var bits accessBitmap
2512 access := bits[:]
2513 return &access
2514 }(),
2515 },
2516 Server: &Server{
2517
2518 Config: &Config{
2519 FileRoot: func() string {
2520 path, _ := os.Getwd()
2521 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2522 }(),
2523 },
2524 },
2525 },
2526 t: NewTransaction(
2527 tranGetFileNameList, &[]byte{0, 1},
2528 NewField(fieldFilePath, []byte{
2529 0x00, 0x01,
2530 0x00, 0x00,
2531 0x08,
2532 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2533 }),
2534 ),
2535 },
2536 wantRes: []Transaction{
2537 {
2538 Flags: 0x00,
2539 IsReply: 0x01,
2540 Type: []byte{0, 0x00},
2541 ID: []byte{0, 0, 0, 0},
2542 ErrorCode: []byte{0, 0, 0, 1},
2543 Fields: []Field{
2544 NewField(fieldError, []byte("You are not allowed to view drop boxes.")),
2545 },
2546 },
2547 },
2548 wantErr: assert.NoError,
2549 },
2550 {
2551 name: "with file root",
2552 args: args{
2553 cc: &ClientConn{
2554 Server: &Server{
2555 Config: &Config{
2556 FileRoot: func() string {
2557 path, _ := os.Getwd()
2558 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2559 }(),
2560 },
2561 },
2562 },
2563 t: NewTransaction(
2564 tranGetFileNameList, &[]byte{0, 1},
2565 NewField(fieldFilePath, []byte{
2566 0x00, 0x00,
2567 0x00, 0x00,
2568 }),
2569 ),
2570 },
2571 wantRes: []Transaction{
2572 {
2573 Flags: 0x00,
2574 IsReply: 0x01,
2575 Type: []byte{0, 0xc8},
2576 ID: []byte{0, 0, 0, 0},
2577 ErrorCode: []byte{0, 0, 0, 0},
2578 Fields: []Field{
2579 NewField(
2580 fieldFileNameWithInfo,
2581 func() []byte {
2582 fnwi := FileNameWithInfo{
2583 fileNameWithInfoHeader: fileNameWithInfoHeader{
2584 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2585 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2586 FileSize: [4]byte{0, 0, 0x04, 0},
2587 RSVD: [4]byte{},
2588 NameScript: [2]byte{},
2589 NameSize: [2]byte{0, 0x0b},
2590 },
2591 name: []byte("testfile-1k"),
2592 }
2593 b, _ := fnwi.MarshalBinary()
2594 return b
2595 }(),
2596 ),
2597 },
2598 },
2599 },
2600 wantErr: assert.NoError,
2601 },
2602 }
2603 for _, tt := range tests {
2604 t.Run(tt.name, func(t *testing.T) {
2605 gotRes, err := HandleGetFileNameList(tt.args.cc, tt.args.t)
2606 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetFileNameList(%v, %v)", tt.args.cc, tt.args.t)) {
2607 return
2608 }
2609
2610 tranAssertEqual(t, tt.wantRes, gotRes)
2611 })
2612 }
2613 }