]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
Fix more filepaths
[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 Account: &Account{
1090 Access: func() *[]byte {
1091 var bits accessBitmap
1092 bits.Set(accessMakeAlias)
1093 access := bits[:]
1094 return &access
1095 }(),
1096 },
1097 Server: &Server{
1098 Config: &Config{
1099 FileRoot: func() string {
1100 path, _ := os.Getwd()
1101 return path + "/test/config/Files"
1102 }(),
1103 },
1104 Logger: NewTestLogger(),
1105 FS: func() *MockFileStore {
1106 mfs := &MockFileStore{}
1107 path, _ := os.Getwd()
1108 mfs.On(
1109 "Symlink",
1110 path+"/test/config/Files/foo/testFile",
1111 path+"/test/config/Files/bar/testFile",
1112 ).Return(nil)
1113 return mfs
1114 }(),
1115 },
1116 },
1117 t: NewTransaction(
1118 tranMakeFileAlias, &[]byte{0, 1},
1119 NewField(fieldFileName, []byte("testFile")),
1120 NewField(fieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1121 NewField(fieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1122 ),
1123 },
1124 wantRes: []Transaction{
1125 {
1126 Flags: 0x00,
1127 IsReply: 0x01,
1128 Type: []byte{0, 0xd1},
1129 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1130 ErrorCode: []byte{0, 0, 0, 0},
1131 Fields: []Field(nil),
1132 },
1133 },
1134 wantErr: false,
1135 },
1136 {
1137 name: "when symlink returns an error",
1138 args: args{
1139 cc: &ClientConn{
1140 Account: &Account{
1141 Access: func() *[]byte {
1142 var bits accessBitmap
1143 bits.Set(accessMakeAlias)
1144 access := bits[:]
1145 return &access
1146 }(),
1147 },
1148 Server: &Server{
1149 Config: &Config{
1150 FileRoot: func() string {
1151 path, _ := os.Getwd()
1152 return path + "/test/config/Files"
1153 }(),
1154 },
1155 Logger: NewTestLogger(),
1156 FS: func() *MockFileStore {
1157 mfs := &MockFileStore{}
1158 path, _ := os.Getwd()
1159 mfs.On(
1160 "Symlink",
1161 path+"/test/config/Files/foo/testFile",
1162 path+"/test/config/Files/bar/testFile",
1163 ).Return(errors.New("ohno"))
1164 return mfs
1165 }(),
1166 },
1167 },
1168 t: NewTransaction(
1169 tranMakeFileAlias, &[]byte{0, 1},
1170 NewField(fieldFileName, []byte("testFile")),
1171 NewField(fieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1172 NewField(fieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1173 ),
1174 },
1175 wantRes: []Transaction{
1176 {
1177 Flags: 0x00,
1178 IsReply: 0x01,
1179 Type: []byte{0, 0x00},
1180 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1181 ErrorCode: []byte{0, 0, 0, 1},
1182 Fields: []Field{
1183 NewField(fieldError, []byte("Error creating alias")),
1184 },
1185 },
1186 },
1187 wantErr: false,
1188 },
1189 {
1190 name: "when user does not have required permission",
1191 args: args{
1192 cc: &ClientConn{
1193 Account: &Account{
1194 Access: func() *[]byte {
1195 var bits accessBitmap
1196 access := bits[:]
1197 return &access
1198 }(),
1199 },
1200 Server: &Server{
1201 Config: &Config{
1202 FileRoot: func() string {
1203 path, _ := os.Getwd()
1204 return path + "/test/config/Files"
1205 }(),
1206 },
1207 },
1208 },
1209 t: NewTransaction(
1210 tranMakeFileAlias, &[]byte{0, 1},
1211 NewField(fieldFileName, []byte("testFile")),
1212 NewField(fieldFilePath, []byte{
1213 0x00, 0x01,
1214 0x00, 0x00,
1215 0x03,
1216 0x2e, 0x2e, 0x2e,
1217 }),
1218 NewField(fieldFileNewPath, []byte{
1219 0x00, 0x01,
1220 0x00, 0x00,
1221 0x03,
1222 0x2e, 0x2e, 0x2e,
1223 }),
1224 ),
1225 },
1226 wantRes: []Transaction{
1227 {
1228 Flags: 0x00,
1229 IsReply: 0x01,
1230 Type: []byte{0, 0x00},
1231 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1232 ErrorCode: []byte{0, 0, 0, 1},
1233 Fields: []Field{
1234 NewField(fieldError, []byte("You are not allowed to make aliases.")),
1235 },
1236 },
1237 },
1238 wantErr: false,
1239 },
1240 }
1241 for _, tt := range tests {
1242 t.Run(tt.name, func(t *testing.T) {
1243 gotRes, err := HandleMakeAlias(tt.args.cc, tt.args.t)
1244 if (err != nil) != tt.wantErr {
1245 t.Errorf("HandleMakeAlias(%v, %v)", tt.args.cc, tt.args.t)
1246 return
1247 }
1248
1249 tranAssertEqual(t, tt.wantRes, gotRes)
1250 })
1251 }
1252 }
1253
1254 func TestHandleGetUser(t *testing.T) {
1255 type args struct {
1256 cc *ClientConn
1257 t *Transaction
1258 }
1259 tests := []struct {
1260 name string
1261 args args
1262 wantRes []Transaction
1263 wantErr assert.ErrorAssertionFunc
1264 }{
1265 {
1266 name: "when account is valid",
1267 args: args{
1268 cc: &ClientConn{
1269 Account: &Account{
1270 Access: func() *[]byte {
1271 var bits accessBitmap
1272 bits.Set(accessOpenUser)
1273 access := bits[:]
1274 return &access
1275 }(),
1276 },
1277 Server: &Server{
1278 Accounts: map[string]*Account{
1279 "guest": {
1280 Login: "guest",
1281 Name: "Guest",
1282 Password: "password",
1283 Access: &[]byte{1},
1284 },
1285 },
1286 },
1287 },
1288 t: NewTransaction(
1289 tranGetUser, &[]byte{0, 1},
1290 NewField(fieldUserLogin, []byte("guest")),
1291 ),
1292 },
1293 wantRes: []Transaction{
1294 {
1295 Flags: 0x00,
1296 IsReply: 0x01,
1297 Type: []byte{0x01, 0x60},
1298 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1299 ErrorCode: []byte{0, 0, 0, 0},
1300 Fields: []Field{
1301 NewField(fieldUserName, []byte("Guest")),
1302 NewField(fieldUserLogin, negateString([]byte("guest"))),
1303 NewField(fieldUserPassword, []byte("password")),
1304 NewField(fieldUserAccess, []byte{1}),
1305 },
1306 },
1307 },
1308 wantErr: assert.NoError,
1309 },
1310 {
1311 name: "when user does not have required permission",
1312 args: args{
1313 cc: &ClientConn{
1314 Account: &Account{
1315 Access: func() *[]byte {
1316 var bits accessBitmap
1317 access := bits[:]
1318 return &access
1319 }(),
1320 },
1321 Server: &Server{
1322 Accounts: map[string]*Account{},
1323 },
1324 },
1325 t: NewTransaction(
1326 tranGetUser, &[]byte{0, 1},
1327 NewField(fieldUserLogin, []byte("nonExistentUser")),
1328 ),
1329 },
1330 wantRes: []Transaction{
1331 {
1332 Flags: 0x00,
1333 IsReply: 0x01,
1334 Type: []byte{0, 0x00},
1335 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1336 ErrorCode: []byte{0, 0, 0, 1},
1337 Fields: []Field{
1338 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1339 },
1340 },
1341 },
1342 wantErr: assert.NoError,
1343 },
1344 {
1345 name: "when account does not exist",
1346 args: args{
1347 cc: &ClientConn{
1348 Account: &Account{
1349 Access: func() *[]byte {
1350 var bits accessBitmap
1351 bits.Set(accessOpenUser)
1352 access := bits[:]
1353 return &access
1354 }(),
1355 },
1356 Server: &Server{
1357 Accounts: map[string]*Account{},
1358 },
1359 },
1360 t: NewTransaction(
1361 tranGetUser, &[]byte{0, 1},
1362 NewField(fieldUserLogin, []byte("nonExistentUser")),
1363 ),
1364 },
1365 wantRes: []Transaction{
1366 {
1367 Flags: 0x00,
1368 IsReply: 0x01,
1369 Type: []byte{0, 0x00},
1370 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1371 ErrorCode: []byte{0, 0, 0, 1},
1372 Fields: []Field{
1373 NewField(fieldError, []byte("Account does not exist.")),
1374 },
1375 },
1376 },
1377 wantErr: assert.NoError,
1378 },
1379 }
1380 for _, tt := range tests {
1381 t.Run(tt.name, func(t *testing.T) {
1382 gotRes, err := HandleGetUser(tt.args.cc, tt.args.t)
1383 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetUser(%v, %v)", tt.args.cc, tt.args.t)) {
1384 return
1385 }
1386
1387 tranAssertEqual(t, tt.wantRes, gotRes)
1388 })
1389 }
1390 }
1391
1392 func TestHandleDeleteUser(t *testing.T) {
1393 type args struct {
1394 cc *ClientConn
1395 t *Transaction
1396 }
1397 tests := []struct {
1398 name string
1399 args args
1400 wantRes []Transaction
1401 wantErr assert.ErrorAssertionFunc
1402 }{
1403 {
1404 name: "when user dataFile",
1405 args: args{
1406 cc: &ClientConn{
1407 Account: &Account{
1408 Access: func() *[]byte {
1409 var bits accessBitmap
1410 bits.Set(accessDeleteUser)
1411 access := bits[:]
1412 return &access
1413 }(),
1414 },
1415 Server: &Server{
1416 Accounts: map[string]*Account{
1417 "testuser": {
1418 Login: "testuser",
1419 Name: "Testy McTest",
1420 Password: "password",
1421 Access: &[]byte{1},
1422 },
1423 },
1424 FS: func() *MockFileStore {
1425 mfs := &MockFileStore{}
1426 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1427 return mfs
1428 }(),
1429 },
1430 },
1431 t: NewTransaction(
1432 tranDeleteUser, &[]byte{0, 1},
1433 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1434 ),
1435 },
1436 wantRes: []Transaction{
1437 {
1438 Flags: 0x00,
1439 IsReply: 0x01,
1440 Type: []byte{0x1, 0x5f},
1441 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1442 ErrorCode: []byte{0, 0, 0, 0},
1443 Fields: []Field(nil),
1444 },
1445 },
1446 wantErr: assert.NoError,
1447 },
1448 {
1449 name: "when user does not have required permission",
1450 args: args{
1451 cc: &ClientConn{
1452 Account: &Account{
1453 Access: func() *[]byte {
1454 var bits accessBitmap
1455 access := bits[:]
1456 return &access
1457 }(),
1458 },
1459 Server: &Server{
1460 Accounts: map[string]*Account{},
1461 },
1462 },
1463 t: NewTransaction(
1464 tranDeleteUser, &[]byte{0, 1},
1465 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1466 ),
1467 },
1468 wantRes: []Transaction{
1469 {
1470 Flags: 0x00,
1471 IsReply: 0x01,
1472 Type: []byte{0, 0x00},
1473 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1474 ErrorCode: []byte{0, 0, 0, 1},
1475 Fields: []Field{
1476 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
1477 },
1478 },
1479 },
1480 wantErr: assert.NoError,
1481 },
1482 }
1483 for _, tt := range tests {
1484 t.Run(tt.name, func(t *testing.T) {
1485 gotRes, err := HandleDeleteUser(tt.args.cc, tt.args.t)
1486 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteUser(%v, %v)", tt.args.cc, tt.args.t)) {
1487 return
1488 }
1489
1490 tranAssertEqual(t, tt.wantRes, gotRes)
1491 })
1492 }
1493 }
1494
1495 func TestHandleGetMsgs(t *testing.T) {
1496 type args struct {
1497 cc *ClientConn
1498 t *Transaction
1499 }
1500 tests := []struct {
1501 name string
1502 args args
1503 wantRes []Transaction
1504 wantErr assert.ErrorAssertionFunc
1505 }{
1506 {
1507 name: "returns news data",
1508 args: args{
1509 cc: &ClientConn{
1510 Account: &Account{
1511 Access: func() *[]byte {
1512 var bits accessBitmap
1513 bits.Set(accessNewsReadArt)
1514 access := bits[:]
1515 return &access
1516 }(),
1517 },
1518 Server: &Server{
1519 FlatNews: []byte("TEST"),
1520 },
1521 },
1522 t: NewTransaction(
1523 tranGetMsgs, &[]byte{0, 1},
1524 ),
1525 },
1526 wantRes: []Transaction{
1527 {
1528 Flags: 0x00,
1529 IsReply: 0x01,
1530 Type: []byte{0, 0x65},
1531 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1532 ErrorCode: []byte{0, 0, 0, 0},
1533 Fields: []Field{
1534 NewField(fieldData, []byte("TEST")),
1535 },
1536 },
1537 },
1538 wantErr: assert.NoError,
1539 },
1540 {
1541 name: "when user does not have required permission",
1542 args: args{
1543 cc: &ClientConn{
1544 Account: &Account{
1545 Access: func() *[]byte {
1546 var bits accessBitmap
1547 access := bits[:]
1548 return &access
1549 }(),
1550 },
1551 Server: &Server{
1552 Accounts: map[string]*Account{},
1553 },
1554 },
1555 t: NewTransaction(
1556 tranGetMsgs, &[]byte{0, 1},
1557 ),
1558 },
1559 wantRes: []Transaction{
1560 {
1561 Flags: 0x00,
1562 IsReply: 0x01,
1563 Type: []byte{0, 0x00},
1564 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1565 ErrorCode: []byte{0, 0, 0, 1},
1566 Fields: []Field{
1567 NewField(fieldError, []byte("You are not allowed to read news.")),
1568 },
1569 },
1570 },
1571 wantErr: assert.NoError,
1572 },
1573 }
1574 for _, tt := range tests {
1575 t.Run(tt.name, func(t *testing.T) {
1576 gotRes, err := HandleGetMsgs(tt.args.cc, tt.args.t)
1577 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetMsgs(%v, %v)", tt.args.cc, tt.args.t)) {
1578 return
1579 }
1580
1581 tranAssertEqual(t, tt.wantRes, gotRes)
1582 })
1583 }
1584 }
1585
1586 func TestHandleNewUser(t *testing.T) {
1587 type args struct {
1588 cc *ClientConn
1589 t *Transaction
1590 }
1591 tests := []struct {
1592 name string
1593 args args
1594 wantRes []Transaction
1595 wantErr assert.ErrorAssertionFunc
1596 }{
1597 {
1598 name: "when user does not have required permission",
1599 args: args{
1600 cc: &ClientConn{
1601 Account: &Account{
1602 Access: func() *[]byte {
1603 var bits accessBitmap
1604 access := bits[:]
1605 return &access
1606 }(),
1607 },
1608 Server: &Server{
1609 Accounts: map[string]*Account{},
1610 },
1611 },
1612 t: NewTransaction(
1613 tranNewUser, &[]byte{0, 1},
1614 ),
1615 },
1616 wantRes: []Transaction{
1617 {
1618 Flags: 0x00,
1619 IsReply: 0x01,
1620 Type: []byte{0, 0x00},
1621 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1622 ErrorCode: []byte{0, 0, 0, 1},
1623 Fields: []Field{
1624 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1625 },
1626 },
1627 },
1628 wantErr: assert.NoError,
1629 },
1630 }
1631 for _, tt := range tests {
1632 t.Run(tt.name, func(t *testing.T) {
1633 gotRes, err := HandleNewUser(tt.args.cc, tt.args.t)
1634 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewUser(%v, %v)", tt.args.cc, tt.args.t)) {
1635 return
1636 }
1637
1638 tranAssertEqual(t, tt.wantRes, gotRes)
1639 })
1640 }
1641 }
1642
1643 func TestHandleListUsers(t *testing.T) {
1644 type args struct {
1645 cc *ClientConn
1646 t *Transaction
1647 }
1648 tests := []struct {
1649 name string
1650 args args
1651 wantRes []Transaction
1652 wantErr assert.ErrorAssertionFunc
1653 }{
1654 {
1655 name: "when user does not have required permission",
1656 args: args{
1657 cc: &ClientConn{
1658 Account: &Account{
1659 Access: func() *[]byte {
1660 var bits accessBitmap
1661 access := bits[:]
1662 return &access
1663 }(),
1664 },
1665 Server: &Server{
1666 Accounts: map[string]*Account{},
1667 },
1668 },
1669 t: NewTransaction(
1670 tranNewUser, &[]byte{0, 1},
1671 ),
1672 },
1673 wantRes: []Transaction{
1674 {
1675 Flags: 0x00,
1676 IsReply: 0x01,
1677 Type: []byte{0, 0x00},
1678 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1679 ErrorCode: []byte{0, 0, 0, 1},
1680 Fields: []Field{
1681 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1682 },
1683 },
1684 },
1685 wantErr: assert.NoError,
1686 },
1687 }
1688 for _, tt := range tests {
1689 t.Run(tt.name, func(t *testing.T) {
1690 gotRes, err := HandleListUsers(tt.args.cc, tt.args.t)
1691 if !tt.wantErr(t, err, fmt.Sprintf("HandleListUsers(%v, %v)", tt.args.cc, tt.args.t)) {
1692 return
1693 }
1694
1695 tranAssertEqual(t, tt.wantRes, gotRes)
1696 })
1697 }
1698 }
1699
1700 func TestHandleDownloadFile(t *testing.T) {
1701 type args struct {
1702 cc *ClientConn
1703 t *Transaction
1704 }
1705 tests := []struct {
1706 name string
1707 args args
1708 wantRes []Transaction
1709 wantErr assert.ErrorAssertionFunc
1710 }{
1711 {
1712 name: "when user does not have required permission",
1713 args: args{
1714 cc: &ClientConn{
1715 Account: &Account{
1716 Access: func() *[]byte {
1717 var bits accessBitmap
1718 access := bits[:]
1719 return &access
1720 }(),
1721 },
1722 Server: &Server{},
1723 },
1724 t: NewTransaction(tranDownloadFile, &[]byte{0, 1}),
1725 },
1726 wantRes: []Transaction{
1727 {
1728 Flags: 0x00,
1729 IsReply: 0x01,
1730 Type: []byte{0, 0x00},
1731 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1732 ErrorCode: []byte{0, 0, 0, 1},
1733 Fields: []Field{
1734 NewField(fieldError, []byte("You are not allowed to download files.")),
1735 },
1736 },
1737 },
1738 wantErr: assert.NoError,
1739 },
1740 {
1741 name: "with a valid file",
1742 args: args{
1743 cc: &ClientConn{
1744 Transfers: make(map[int][]*FileTransfer),
1745 Account: &Account{
1746 Access: func() *[]byte {
1747 var bits accessBitmap
1748 bits.Set(accessDownloadFile)
1749 access := bits[:]
1750 return &access
1751 }(),
1752 },
1753 Server: &Server{
1754 FS: &OSFileStore{},
1755 FileTransfers: make(map[uint32]*FileTransfer),
1756 Config: &Config{
1757 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1758 },
1759 Accounts: map[string]*Account{},
1760 },
1761 },
1762 t: NewTransaction(
1763 accessDownloadFile,
1764 &[]byte{0, 1},
1765 NewField(fieldFileName, []byte("testfile.txt")),
1766 NewField(fieldFilePath, []byte{0x0, 0x00}),
1767 ),
1768 },
1769 wantRes: []Transaction{
1770 {
1771 Flags: 0x00,
1772 IsReply: 0x01,
1773 Type: []byte{0, 0x2},
1774 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1775 ErrorCode: []byte{0, 0, 0, 0},
1776 Fields: []Field{
1777 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1778 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1779 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1780 NewField(fieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1781 },
1782 },
1783 },
1784 wantErr: assert.NoError,
1785 },
1786 {
1787 name: "when client requests to resume 1k test file at offset 256",
1788 args: args{
1789 cc: &ClientConn{
1790 Transfers: make(map[int][]*FileTransfer),
1791 Account: &Account{
1792 Access: func() *[]byte {
1793 var bits accessBitmap
1794 bits.Set(accessDownloadFile)
1795 access := bits[:]
1796 return &access
1797 }(),
1798 },
1799 Server: &Server{
1800 FS: &OSFileStore{},
1801 // FS: func() *MockFileStore {
1802 // path, _ := os.Getwd()
1803 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1804 // if err != nil {
1805 // panic(err)
1806 // }
1807 //
1808 // mfi := &MockFileInfo{}
1809 // mfi.On("Mode").Return(fs.FileMode(0))
1810 // mfs := &MockFileStore{}
1811 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1812 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1813 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1814 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1815 //
1816 // return mfs
1817 // }(),
1818 FileTransfers: make(map[uint32]*FileTransfer),
1819 Config: &Config{
1820 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1821 },
1822 Accounts: map[string]*Account{},
1823 },
1824 },
1825 t: NewTransaction(
1826 accessDownloadFile,
1827 &[]byte{0, 1},
1828 NewField(fieldFileName, []byte("testfile-1k")),
1829 NewField(fieldFilePath, []byte{0x00, 0x00}),
1830 NewField(
1831 fieldFileResumeData,
1832 func() []byte {
1833 frd := FileResumeData{
1834 Format: [4]byte{},
1835 Version: [2]byte{},
1836 RSVD: [34]byte{},
1837 ForkCount: [2]byte{0, 2},
1838 ForkInfoList: []ForkInfoList{
1839 {
1840 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1841 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
1842 RSVDA: [4]byte{},
1843 RSVDB: [4]byte{},
1844 },
1845 {
1846 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1847 DataSize: [4]byte{0, 0, 0, 0},
1848 RSVDA: [4]byte{},
1849 RSVDB: [4]byte{},
1850 },
1851 },
1852 }
1853 b, _ := frd.BinaryMarshal()
1854 return b
1855 }(),
1856 ),
1857 ),
1858 },
1859 wantRes: []Transaction{
1860 {
1861 Flags: 0x00,
1862 IsReply: 0x01,
1863 Type: []byte{0, 0x2},
1864 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1865 ErrorCode: []byte{0, 0, 0, 0},
1866 Fields: []Field{
1867 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1868 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1869 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1870 NewField(fieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
1871 },
1872 },
1873 },
1874 wantErr: assert.NoError,
1875 },
1876 }
1877 for _, tt := range tests {
1878 t.Run(tt.name, func(t *testing.T) {
1879 gotRes, err := HandleDownloadFile(tt.args.cc, tt.args.t)
1880 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadFile(%v, %v)", tt.args.cc, tt.args.t)) {
1881 return
1882 }
1883
1884 tranAssertEqual(t, tt.wantRes, gotRes)
1885 })
1886 }
1887 }
1888
1889 func TestHandleUpdateUser(t *testing.T) {
1890 type args struct {
1891 cc *ClientConn
1892 t *Transaction
1893 }
1894 tests := []struct {
1895 name string
1896 args args
1897 wantRes []Transaction
1898 wantErr assert.ErrorAssertionFunc
1899 }{
1900 {
1901 name: "when action is create user without required permission",
1902 args: args{
1903 cc: &ClientConn{
1904 Server: &Server{
1905 Logger: NewTestLogger(),
1906 },
1907 Account: &Account{
1908 Access: func() *[]byte {
1909 var bits accessBitmap
1910 access := bits[:]
1911 return &access
1912 }(),
1913 },
1914 },
1915 t: NewTransaction(
1916 tranUpdateUser,
1917 &[]byte{0, 0},
1918 NewField(fieldData, []byte{
1919 0x00, 0x04, // field count
1920
1921 0x00, 0x69, // fieldUserLogin = 105
1922 0x00, 0x03,
1923 0x9d, 0x9d, 0x9d,
1924
1925 0x00, 0x6a, // fieldUserPassword = 106
1926 0x00, 0x03,
1927 0x9c, 0x9c, 0x9c,
1928
1929 0x00, 0x66, // fieldUserName = 102
1930 0x00, 0x03,
1931 0x61, 0x61, 0x61,
1932
1933 0x00, 0x6e, // fieldUserAccess = 110
1934 0x00, 0x08,
1935 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1936 }),
1937 ),
1938 },
1939 wantRes: []Transaction{
1940 {
1941 Flags: 0x00,
1942 IsReply: 0x01,
1943 Type: []byte{0, 0x00},
1944 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1945 ErrorCode: []byte{0, 0, 0, 1},
1946 Fields: []Field{
1947 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1948 },
1949 },
1950 },
1951 wantErr: assert.NoError,
1952 },
1953 {
1954 name: "when action is modify user without required permission",
1955 args: args{
1956 cc: &ClientConn{
1957 Server: &Server{
1958 Logger: NewTestLogger(),
1959 Accounts: map[string]*Account{
1960 "bbb": {},
1961 },
1962 },
1963 Account: &Account{
1964 Access: func() *[]byte {
1965 var bits accessBitmap
1966 access := bits[:]
1967 return &access
1968 }(),
1969 },
1970 },
1971 t: NewTransaction(
1972 tranUpdateUser,
1973 &[]byte{0, 0},
1974 NewField(fieldData, []byte{
1975 0x00, 0x04, // field count
1976
1977 0x00, 0x69, // fieldUserLogin = 105
1978 0x00, 0x03,
1979 0x9d, 0x9d, 0x9d,
1980
1981 0x00, 0x6a, // fieldUserPassword = 106
1982 0x00, 0x03,
1983 0x9c, 0x9c, 0x9c,
1984
1985 0x00, 0x66, // fieldUserName = 102
1986 0x00, 0x03,
1987 0x61, 0x61, 0x61,
1988
1989 0x00, 0x6e, // fieldUserAccess = 110
1990 0x00, 0x08,
1991 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1992 }),
1993 ),
1994 },
1995 wantRes: []Transaction{
1996 {
1997 Flags: 0x00,
1998 IsReply: 0x01,
1999 Type: []byte{0, 0x00},
2000 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2001 ErrorCode: []byte{0, 0, 0, 1},
2002 Fields: []Field{
2003 NewField(fieldError, []byte("You are not allowed to modify accounts.")),
2004 },
2005 },
2006 },
2007 wantErr: assert.NoError,
2008 },
2009 {
2010 name: "when action is delete user without required permission",
2011 args: args{
2012 cc: &ClientConn{
2013 Server: &Server{
2014 Logger: NewTestLogger(),
2015 Accounts: map[string]*Account{
2016 "bbb": {},
2017 },
2018 },
2019 Account: &Account{
2020 Access: func() *[]byte {
2021 var bits accessBitmap
2022 access := bits[:]
2023 return &access
2024 }(),
2025 },
2026 },
2027 t: NewTransaction(
2028 tranUpdateUser,
2029 &[]byte{0, 0},
2030 NewField(fieldData, []byte{
2031 0x00, 0x01,
2032 0x00, 0x65,
2033 0x00, 0x03,
2034 0x88, 0x9e, 0x8b,
2035 }),
2036 ),
2037 },
2038 wantRes: []Transaction{
2039 {
2040 Flags: 0x00,
2041 IsReply: 0x01,
2042 Type: []byte{0, 0x00},
2043 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2044 ErrorCode: []byte{0, 0, 0, 1},
2045 Fields: []Field{
2046 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
2047 },
2048 },
2049 },
2050 wantErr: assert.NoError,
2051 },
2052 }
2053 for _, tt := range tests {
2054 t.Run(tt.name, func(t *testing.T) {
2055 gotRes, err := HandleUpdateUser(tt.args.cc, tt.args.t)
2056 if !tt.wantErr(t, err, fmt.Sprintf("HandleUpdateUser(%v, %v)", tt.args.cc, tt.args.t)) {
2057 return
2058 }
2059
2060 tranAssertEqual(t, tt.wantRes, gotRes)
2061 })
2062 }
2063 }
2064
2065 func TestHandleDelNewsArt(t *testing.T) {
2066 type args struct {
2067 cc *ClientConn
2068 t *Transaction
2069 }
2070 tests := []struct {
2071 name string
2072 args args
2073 wantRes []Transaction
2074 wantErr assert.ErrorAssertionFunc
2075 }{
2076 {
2077 name: "without required permission",
2078 args: args{
2079 cc: &ClientConn{
2080 Account: &Account{
2081 Access: func() *[]byte {
2082 var bits accessBitmap
2083 access := bits[:]
2084 return &access
2085 }(),
2086 },
2087 },
2088 t: NewTransaction(
2089 tranDelNewsArt,
2090 &[]byte{0, 0},
2091 ),
2092 },
2093 wantRes: []Transaction{
2094 {
2095 Flags: 0x00,
2096 IsReply: 0x01,
2097 Type: []byte{0, 0x00},
2098 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2099 ErrorCode: []byte{0, 0, 0, 1},
2100 Fields: []Field{
2101 NewField(fieldError, []byte("You are not allowed to delete news articles.")),
2102 },
2103 },
2104 },
2105 wantErr: assert.NoError,
2106 },
2107 }
2108 for _, tt := range tests {
2109 t.Run(tt.name, func(t *testing.T) {
2110 gotRes, err := HandleDelNewsArt(tt.args.cc, tt.args.t)
2111 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsArt(%v, %v)", tt.args.cc, tt.args.t)) {
2112 return
2113 }
2114 tranAssertEqual(t, tt.wantRes, gotRes)
2115 })
2116 }
2117 }
2118
2119 func TestHandleDisconnectUser(t *testing.T) {
2120 type args struct {
2121 cc *ClientConn
2122 t *Transaction
2123 }
2124 tests := []struct {
2125 name string
2126 args args
2127 wantRes []Transaction
2128 wantErr assert.ErrorAssertionFunc
2129 }{
2130 {
2131 name: "without required permission",
2132 args: args{
2133 cc: &ClientConn{
2134 Account: &Account{
2135 Access: func() *[]byte {
2136 var bits accessBitmap
2137 access := bits[:]
2138 return &access
2139 }(),
2140 },
2141 },
2142 t: NewTransaction(
2143 tranDelNewsArt,
2144 &[]byte{0, 0},
2145 ),
2146 },
2147 wantRes: []Transaction{
2148 {
2149 Flags: 0x00,
2150 IsReply: 0x01,
2151 Type: []byte{0, 0x00},
2152 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2153 ErrorCode: []byte{0, 0, 0, 1},
2154 Fields: []Field{
2155 NewField(fieldError, []byte("You are not allowed to disconnect users.")),
2156 },
2157 },
2158 },
2159 wantErr: assert.NoError,
2160 },
2161 {
2162 name: "when target user has 'cannot be disconnected' priv",
2163 args: args{
2164 cc: &ClientConn{
2165 Server: &Server{
2166 Clients: map[uint16]*ClientConn{
2167 uint16(1): {
2168 Account: &Account{
2169 Login: "unnamed",
2170 Access: func() *[]byte {
2171 var bits accessBitmap
2172 bits.Set(accessCannotBeDiscon)
2173 access := bits[:]
2174 return &access
2175 }(),
2176 },
2177 },
2178 },
2179 },
2180 Account: &Account{
2181 Access: func() *[]byte {
2182 var bits accessBitmap
2183 bits.Set(accessDisconUser)
2184 access := bits[:]
2185 return &access
2186 }(),
2187 },
2188 },
2189 t: NewTransaction(
2190 tranDelNewsArt,
2191 &[]byte{0, 0},
2192 NewField(fieldUserID, []byte{0, 1}),
2193 ),
2194 },
2195 wantRes: []Transaction{
2196 {
2197 Flags: 0x00,
2198 IsReply: 0x01,
2199 Type: []byte{0, 0x00},
2200 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2201 ErrorCode: []byte{0, 0, 0, 1},
2202 Fields: []Field{
2203 NewField(fieldError, []byte("unnamed is not allowed to be disconnected.")),
2204 },
2205 },
2206 },
2207 wantErr: assert.NoError,
2208 },
2209 }
2210 for _, tt := range tests {
2211 t.Run(tt.name, func(t *testing.T) {
2212 gotRes, err := HandleDisconnectUser(tt.args.cc, tt.args.t)
2213 if !tt.wantErr(t, err, fmt.Sprintf("HandleDisconnectUser(%v, %v)", tt.args.cc, tt.args.t)) {
2214 return
2215 }
2216 tranAssertEqual(t, tt.wantRes, gotRes)
2217 })
2218 }
2219 }
2220
2221 func TestHandleSendInstantMsg(t *testing.T) {
2222 type args struct {
2223 cc *ClientConn
2224 t *Transaction
2225 }
2226 tests := []struct {
2227 name string
2228 args args
2229 wantRes []Transaction
2230 wantErr assert.ErrorAssertionFunc
2231 }{
2232 {
2233 name: "when client 1 sends a message to client 2",
2234 args: args{
2235 cc: &ClientConn{
2236 ID: &[]byte{0, 1},
2237 UserName: []byte("User1"),
2238 Server: &Server{
2239 Clients: map[uint16]*ClientConn{
2240 uint16(2): {
2241 AutoReply: []byte(nil),
2242 },
2243 },
2244 },
2245 },
2246 t: NewTransaction(
2247 tranSendInstantMsg,
2248 &[]byte{0, 1},
2249 NewField(fieldData, []byte("hai")),
2250 NewField(fieldUserID, []byte{0, 2}),
2251 ),
2252 },
2253 wantRes: []Transaction{
2254 *NewTransaction(
2255 tranServerMsg,
2256 &[]byte{0, 2},
2257 NewField(fieldData, []byte("hai")),
2258 NewField(fieldUserName, []byte("User1")),
2259 NewField(fieldUserID, []byte{0, 1}),
2260 NewField(fieldOptions, []byte{0, 1}),
2261 ),
2262 {
2263 clientID: &[]byte{0, 1},
2264 Flags: 0x00,
2265 IsReply: 0x01,
2266 Type: []byte{0x0, 0x6c},
2267 ID: []byte{0, 0, 0, 0},
2268 ErrorCode: []byte{0, 0, 0, 0},
2269 Fields: []Field(nil),
2270 },
2271 },
2272 wantErr: assert.NoError,
2273 },
2274 {
2275 name: "when client 2 has autoreply enabled",
2276 args: args{
2277 cc: &ClientConn{
2278 ID: &[]byte{0, 1},
2279 UserName: []byte("User1"),
2280 Server: &Server{
2281 Clients: map[uint16]*ClientConn{
2282 uint16(2): {
2283 ID: &[]byte{0, 2},
2284 UserName: []byte("User2"),
2285 AutoReply: []byte("autohai"),
2286 },
2287 },
2288 },
2289 },
2290 t: NewTransaction(
2291 tranSendInstantMsg,
2292 &[]byte{0, 1},
2293 NewField(fieldData, []byte("hai")),
2294 NewField(fieldUserID, []byte{0, 2}),
2295 ),
2296 },
2297 wantRes: []Transaction{
2298 *NewTransaction(
2299 tranServerMsg,
2300 &[]byte{0, 2},
2301 NewField(fieldData, []byte("hai")),
2302 NewField(fieldUserName, []byte("User1")),
2303 NewField(fieldUserID, []byte{0, 1}),
2304 NewField(fieldOptions, []byte{0, 1}),
2305 ),
2306 *NewTransaction(
2307 tranServerMsg,
2308 &[]byte{0, 1},
2309 NewField(fieldData, []byte("autohai")),
2310 NewField(fieldUserName, []byte("User2")),
2311 NewField(fieldUserID, []byte{0, 2}),
2312 NewField(fieldOptions, []byte{0, 1}),
2313 ),
2314 {
2315 clientID: &[]byte{0, 1},
2316 Flags: 0x00,
2317 IsReply: 0x01,
2318 Type: []byte{0x0, 0x6c},
2319 ID: []byte{0, 0, 0, 0},
2320 ErrorCode: []byte{0, 0, 0, 0},
2321 Fields: []Field(nil),
2322 },
2323 },
2324 wantErr: assert.NoError,
2325 },
2326 }
2327 for _, tt := range tests {
2328 t.Run(tt.name, func(t *testing.T) {
2329 gotRes, err := HandleSendInstantMsg(tt.args.cc, tt.args.t)
2330 if !tt.wantErr(t, err, fmt.Sprintf("HandleSendInstantMsg(%v, %v)", tt.args.cc, tt.args.t)) {
2331 return
2332 }
2333
2334 tranAssertEqual(t, tt.wantRes, gotRes)
2335 })
2336 }
2337 }
2338
2339 func TestHandleDeleteFile(t *testing.T) {
2340 type args struct {
2341 cc *ClientConn
2342 t *Transaction
2343 }
2344 tests := []struct {
2345 name string
2346 args args
2347 wantRes []Transaction
2348 wantErr assert.ErrorAssertionFunc
2349 }{
2350 {
2351 name: "when user does not have required permission to delete a folder",
2352 args: args{
2353 cc: &ClientConn{
2354 Account: &Account{
2355 Access: func() *[]byte {
2356 var bits accessBitmap
2357 access := bits[:]
2358 return &access
2359 }(),
2360 },
2361 Server: &Server{
2362 Config: &Config{
2363 FileRoot: func() string {
2364 return "/fakeRoot/Files"
2365 }(),
2366 },
2367 FS: func() *MockFileStore {
2368 mfi := &MockFileInfo{}
2369 mfi.On("Mode").Return(fs.FileMode(0))
2370 mfi.On("Size").Return(int64(100))
2371 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2372 mfi.On("IsDir").Return(false)
2373 mfi.On("Name").Return("testfile")
2374
2375 mfs := &MockFileStore{}
2376 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2377 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2378 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2379
2380 return mfs
2381 }(),
2382 Accounts: map[string]*Account{},
2383 },
2384 },
2385 t: NewTransaction(
2386 tranDeleteFile, &[]byte{0, 1},
2387 NewField(fieldFileName, []byte("testfile")),
2388 NewField(fieldFilePath, []byte{
2389 0x00, 0x01,
2390 0x00, 0x00,
2391 0x03,
2392 0x61, 0x61, 0x61,
2393 }),
2394 ),
2395 },
2396 wantRes: []Transaction{
2397 {
2398 Flags: 0x00,
2399 IsReply: 0x01,
2400 Type: []byte{0, 0x00},
2401 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2402 ErrorCode: []byte{0, 0, 0, 1},
2403 Fields: []Field{
2404 NewField(fieldError, []byte("You are not allowed to delete files.")),
2405 },
2406 },
2407 },
2408 wantErr: assert.NoError,
2409 },
2410 {
2411 name: "deletes all associated metadata files",
2412 args: args{
2413 cc: &ClientConn{
2414 Account: &Account{
2415 Access: func() *[]byte {
2416 var bits accessBitmap
2417 bits.Set(accessDeleteFile)
2418 access := bits[:]
2419 return &access
2420 }(),
2421 },
2422 Server: &Server{
2423 Config: &Config{
2424 FileRoot: func() string {
2425 return "/fakeRoot/Files"
2426 }(),
2427 },
2428 FS: func() *MockFileStore {
2429 mfi := &MockFileInfo{}
2430 mfi.On("Mode").Return(fs.FileMode(0))
2431 mfi.On("Size").Return(int64(100))
2432 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2433 mfi.On("IsDir").Return(false)
2434 mfi.On("Name").Return("testfile")
2435
2436 mfs := &MockFileStore{}
2437 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2438 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2439 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2440
2441 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2442 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2443 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2444 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2445
2446 return mfs
2447 }(),
2448 Accounts: map[string]*Account{},
2449 },
2450 },
2451 t: NewTransaction(
2452 tranDeleteFile, &[]byte{0, 1},
2453 NewField(fieldFileName, []byte("testfile")),
2454 NewField(fieldFilePath, []byte{
2455 0x00, 0x01,
2456 0x00, 0x00,
2457 0x03,
2458 0x61, 0x61, 0x61,
2459 }),
2460 ),
2461 },
2462 wantRes: []Transaction{
2463 {
2464 Flags: 0x00,
2465 IsReply: 0x01,
2466 Type: []byte{0x0, 0xcc},
2467 ID: []byte{0x0, 0x0, 0x0, 0x0},
2468 ErrorCode: []byte{0, 0, 0, 0},
2469 Fields: []Field(nil),
2470 },
2471 },
2472 wantErr: assert.NoError,
2473 },
2474 }
2475 for _, tt := range tests {
2476 t.Run(tt.name, func(t *testing.T) {
2477 gotRes, err := HandleDeleteFile(tt.args.cc, tt.args.t)
2478 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteFile(%v, %v)", tt.args.cc, tt.args.t)) {
2479 return
2480 }
2481
2482 tranAssertEqual(t, tt.wantRes, gotRes)
2483
2484 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2485 })
2486 }
2487 }
2488
2489 func TestHandleGetFileNameList(t *testing.T) {
2490 type args struct {
2491 cc *ClientConn
2492 t *Transaction
2493 }
2494 tests := []struct {
2495 name string
2496 args args
2497 wantRes []Transaction
2498 wantErr assert.ErrorAssertionFunc
2499 }{
2500 {
2501 name: "when fieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2502 args: args{
2503 cc: &ClientConn{
2504 Account: &Account{
2505 Access: func() *[]byte {
2506 var bits accessBitmap
2507 access := bits[:]
2508 return &access
2509 }(),
2510 },
2511 Server: &Server{
2512
2513 Config: &Config{
2514 FileRoot: func() string {
2515 path, _ := os.Getwd()
2516 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2517 }(),
2518 },
2519 },
2520 },
2521 t: NewTransaction(
2522 tranGetFileNameList, &[]byte{0, 1},
2523 NewField(fieldFilePath, []byte{
2524 0x00, 0x01,
2525 0x00, 0x00,
2526 0x08,
2527 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2528 }),
2529 ),
2530 },
2531 wantRes: []Transaction{
2532 {
2533 Flags: 0x00,
2534 IsReply: 0x01,
2535 Type: []byte{0, 0x00},
2536 ID: []byte{0, 0, 0, 0},
2537 ErrorCode: []byte{0, 0, 0, 1},
2538 Fields: []Field{
2539 NewField(fieldError, []byte("You are not allowed to view drop boxes.")),
2540 },
2541 },
2542 },
2543 wantErr: assert.NoError,
2544 },
2545 {
2546 name: "with file root",
2547 args: args{
2548 cc: &ClientConn{
2549 Server: &Server{
2550 Config: &Config{
2551 FileRoot: func() string {
2552 path, _ := os.Getwd()
2553 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2554 }(),
2555 },
2556 },
2557 },
2558 t: NewTransaction(
2559 tranGetFileNameList, &[]byte{0, 1},
2560 NewField(fieldFilePath, []byte{
2561 0x00, 0x00,
2562 0x00, 0x00,
2563 }),
2564 ),
2565 },
2566 wantRes: []Transaction{
2567 {
2568 Flags: 0x00,
2569 IsReply: 0x01,
2570 Type: []byte{0, 0xc8},
2571 ID: []byte{0, 0, 0, 0},
2572 ErrorCode: []byte{0, 0, 0, 0},
2573 Fields: []Field{
2574 NewField(
2575 fieldFileNameWithInfo,
2576 func() []byte {
2577 fnwi := FileNameWithInfo{
2578 fileNameWithInfoHeader: fileNameWithInfoHeader{
2579 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2580 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2581 FileSize: [4]byte{0, 0, 0x04, 0},
2582 RSVD: [4]byte{},
2583 NameScript: [2]byte{},
2584 NameSize: [2]byte{0, 0x0b},
2585 },
2586 name: []byte("testfile-1k"),
2587 }
2588 b, _ := fnwi.MarshalBinary()
2589 return b
2590 }(),
2591 ),
2592 },
2593 },
2594 },
2595 wantErr: assert.NoError,
2596 },
2597 }
2598 for _, tt := range tests {
2599 t.Run(tt.name, func(t *testing.T) {
2600 gotRes, err := HandleGetFileNameList(tt.args.cc, tt.args.t)
2601 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetFileNameList(%v, %v)", tt.args.cc, tt.args.t)) {
2602 return
2603 }
2604
2605 tranAssertEqual(t, tt.wantRes, gotRes)
2606 })
2607 }
2608 }