]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
Fix inconsistent sorting of user list
[rbdr/mobius] / hotline / transaction_handlers_test.go
1 package hotline
2
3 import (
4 "github.com/stretchr/testify/assert"
5 "io/fs"
6 "math/rand"
7 "os"
8 "reflect"
9 "testing"
10 )
11
12 func TestHandleSetChatSubject(t *testing.T) {
13 type args struct {
14 cc *ClientConn
15 t *Transaction
16 }
17 tests := []struct {
18 name string
19 args args
20 want []Transaction
21 wantErr bool
22 }{
23 {
24 name: "sends chat subject to private chat members",
25 args: args{
26 cc: &ClientConn{
27 UserName: []byte{0x00, 0x01},
28 Server: &Server{
29 PrivateChats: map[uint32]*PrivateChat{
30 uint32(1): {
31 Subject: "unset",
32 ClientConn: map[uint16]*ClientConn{
33 uint16(1): {
34 Account: &Account{
35 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
36 },
37 ID: &[]byte{0, 1},
38 },
39 uint16(2): {
40 Account: &Account{
41 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
42 },
43 ID: &[]byte{0, 2},
44 },
45 },
46 },
47 },
48 Clients: map[uint16]*ClientConn{
49 uint16(1): {
50 Account: &Account{
51 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
52 },
53 ID: &[]byte{0, 1},
54 },
55 uint16(2): {
56 Account: &Account{
57 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
58 },
59 ID: &[]byte{0, 2},
60 },
61 },
62 },
63 },
64 t: &Transaction{
65 Flags: 0x00,
66 IsReply: 0x00,
67 Type: []byte{0, 0x6a},
68 ID: []byte{0, 0, 0, 1},
69 ErrorCode: []byte{0, 0, 0, 0},
70 Fields: []Field{
71 NewField(fieldChatID, []byte{0, 0, 0, 1}),
72 NewField(fieldChatSubject, []byte("Test Subject")),
73 },
74 },
75 },
76 want: []Transaction{
77 {
78 clientID: &[]byte{0, 1},
79 Flags: 0x00,
80 IsReply: 0x00,
81 Type: []byte{0, 0x77},
82 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
83 ErrorCode: []byte{0, 0, 0, 0},
84 Fields: []Field{
85 NewField(fieldChatID, []byte{0, 0, 0, 1}),
86 NewField(fieldChatSubject, []byte("Test Subject")),
87 },
88 },
89 {
90 clientID: &[]byte{0, 2},
91 Flags: 0x00,
92 IsReply: 0x00,
93 Type: []byte{0, 0x77},
94 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
95 ErrorCode: []byte{0, 0, 0, 0},
96 Fields: []Field{
97 NewField(fieldChatID, []byte{0, 0, 0, 1}),
98 NewField(fieldChatSubject, []byte("Test Subject")),
99 },
100 },
101 },
102 wantErr: false,
103 },
104 }
105 for _, tt := range tests {
106 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
107
108 t.Run(tt.name, func(t *testing.T) {
109 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
110 if (err != nil) != tt.wantErr {
111 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
112 return
113 }
114 if !assert.Equal(t, tt.want, got) {
115 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
116 }
117 })
118 }
119 }
120
121 func TestHandleLeaveChat(t *testing.T) {
122 type args struct {
123 cc *ClientConn
124 t *Transaction
125 }
126 tests := []struct {
127 name string
128 args args
129 want []Transaction
130 wantErr bool
131 }{
132 {
133 name: "returns expected transactions",
134 args: args{
135 cc: &ClientConn{
136 ID: &[]byte{0, 2},
137 Server: &Server{
138 PrivateChats: map[uint32]*PrivateChat{
139 uint32(1): {
140 ClientConn: map[uint16]*ClientConn{
141 uint16(1): {
142 Account: &Account{
143 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
144 },
145 ID: &[]byte{0, 1},
146 },
147 uint16(2): {
148 Account: &Account{
149 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
150 },
151 ID: &[]byte{0, 2},
152 },
153 },
154 },
155 },
156 Clients: map[uint16]*ClientConn{
157 uint16(1): {
158 Account: &Account{
159 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
160 },
161 ID: &[]byte{0, 1},
162 },
163 uint16(2): {
164 Account: &Account{
165 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
166 },
167 ID: &[]byte{0, 2},
168 },
169 },
170 },
171 },
172 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
173 },
174 want: []Transaction{
175 {
176 clientID: &[]byte{0, 1},
177 Flags: 0x00,
178 IsReply: 0x00,
179 Type: []byte{0, 0x76},
180 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
181 ErrorCode: []byte{0, 0, 0, 0},
182 Fields: []Field{
183 NewField(fieldChatID, []byte{0, 0, 0, 1}),
184 NewField(fieldUserID, []byte{0, 2}),
185 },
186 },
187 },
188 wantErr: false,
189 },
190 }
191 for _, tt := range tests {
192 rand.Seed(1)
193 t.Run(tt.name, func(t *testing.T) {
194 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
195 if (err != nil) != tt.wantErr {
196 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
197 return
198 }
199 if !assert.Equal(t, tt.want, got) {
200 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
201 }
202 })
203 }
204 }
205
206 func TestHandleGetUserNameList(t *testing.T) {
207 type args struct {
208 cc *ClientConn
209 t *Transaction
210 }
211 tests := []struct {
212 name string
213 args args
214 want []Transaction
215 wantErr bool
216 }{
217 {
218 name: "replies with userlist transaction",
219 args: args{
220 cc: &ClientConn{
221
222 ID: &[]byte{1, 1},
223 Server: &Server{
224 Clients: map[uint16]*ClientConn{
225 uint16(1): {
226 ID: &[]byte{0, 1},
227 Icon: &[]byte{0, 2},
228 Flags: &[]byte{0, 3},
229 UserName: []byte{0, 4},
230 },
231 uint16(2): {
232 ID: &[]byte{0, 2},
233 Icon: &[]byte{0, 2},
234 Flags: &[]byte{0, 3},
235 UserName: []byte{0, 4},
236 },
237 },
238 },
239 },
240 t: &Transaction{
241 ID: []byte{0, 0, 0, 1},
242 Type: []byte{0, 1},
243 },
244 },
245 want: []Transaction{
246 {
247 clientID: &[]byte{1, 1},
248 Flags: 0x00,
249 IsReply: 0x01,
250 Type: []byte{0, 1},
251 ID: []byte{0, 0, 0, 1},
252 ErrorCode: []byte{0, 0, 0, 0},
253 Fields: []Field{
254 NewField(
255 fieldUsernameWithInfo,
256 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
257 ),
258 NewField(
259 fieldUsernameWithInfo,
260 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
261 ),
262 },
263 },
264 },
265 wantErr: false,
266 },
267 }
268 for _, tt := range tests {
269 t.Run(tt.name, func(t *testing.T) {
270 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
271 if (err != nil) != tt.wantErr {
272 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
273 return
274 }
275 if !reflect.DeepEqual(got, tt.want) {
276 t.Errorf("HandleGetUserNameList() got = %v, want %v", got, tt.want)
277 }
278 })
279 }
280 }
281
282 func TestHandleChatSend(t *testing.T) {
283 type args struct {
284 cc *ClientConn
285 t *Transaction
286 }
287 tests := []struct {
288 name string
289 args args
290 want []Transaction
291 wantErr bool
292 }{
293 {
294 name: "sends chat msg transaction to all clients",
295 args: args{
296 cc: &ClientConn{
297 UserName: []byte{0x00, 0x01},
298 Server: &Server{
299 Clients: map[uint16]*ClientConn{
300 uint16(1): {
301 Account: &Account{
302 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
303 },
304 ID: &[]byte{0, 1},
305 },
306 uint16(2): {
307 Account: &Account{
308 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
309 },
310 ID: &[]byte{0, 2},
311 },
312 },
313 },
314 },
315 t: &Transaction{
316 Fields: []Field{
317 NewField(fieldData, []byte("hai")),
318 },
319 },
320 },
321 want: []Transaction{
322 {
323 clientID: &[]byte{0, 1},
324 Flags: 0x00,
325 IsReply: 0x00,
326 Type: []byte{0, 0x6a},
327 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
328 ErrorCode: []byte{0, 0, 0, 0},
329 Fields: []Field{
330 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
331 },
332 },
333 {
334 clientID: &[]byte{0, 2},
335 Flags: 0x00,
336 IsReply: 0x00,
337 Type: []byte{0, 0x6a},
338 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
339 ErrorCode: []byte{0, 0, 0, 0},
340 Fields: []Field{
341 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
342 },
343 },
344 },
345 wantErr: false,
346 },
347 {
348 name: "sends chat msg as emote if fieldChatOptions is set",
349 args: args{
350 cc: &ClientConn{
351 UserName: []byte("Testy McTest"),
352 Server: &Server{
353 Clients: map[uint16]*ClientConn{
354 uint16(1): {
355 Account: &Account{
356 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
357 },
358 ID: &[]byte{0, 1},
359 },
360 uint16(2): {
361 Account: &Account{
362 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
363 },
364 ID: &[]byte{0, 2},
365 },
366 },
367 },
368 },
369 t: &Transaction{
370 Fields: []Field{
371 NewField(fieldData, []byte("performed action")),
372 NewField(fieldChatOptions, []byte{0x00, 0x01}),
373 },
374 },
375 },
376 want: []Transaction{
377 {
378 clientID: &[]byte{0, 1},
379 Flags: 0x00,
380 IsReply: 0x00,
381 Type: []byte{0, 0x6a},
382 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
383 ErrorCode: []byte{0, 0, 0, 0},
384 Fields: []Field{
385 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
386 },
387 },
388 {
389 clientID: &[]byte{0, 2},
390 Flags: 0x00,
391 IsReply: 0x00,
392 Type: []byte{0, 0x6a},
393 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
394 ErrorCode: []byte{0, 0, 0, 0},
395 Fields: []Field{
396 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
397 },
398 },
399 },
400 wantErr: false,
401 },
402 {
403 name: "only sends chat msg to clients with accessReadChat permission",
404 args: args{
405 cc: &ClientConn{
406 UserName: []byte{0x00, 0x01},
407 Server: &Server{
408 Clients: map[uint16]*ClientConn{
409 uint16(1): {
410 Account: &Account{
411 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
412 },
413 ID: &[]byte{0, 1},
414 },
415 uint16(2): {
416 Account: &Account{
417 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
418 },
419 ID: &[]byte{0, 2},
420 },
421 },
422 },
423 },
424 t: &Transaction{
425 Fields: []Field{
426 NewField(fieldData, []byte("hai")),
427 },
428 },
429 },
430 want: []Transaction{
431 {
432 clientID: &[]byte{0, 1},
433 Flags: 0x00,
434 IsReply: 0x00,
435 Type: []byte{0, 0x6a},
436 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
437 ErrorCode: []byte{0, 0, 0, 0},
438 Fields: []Field{
439 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
440 },
441 },
442 },
443 wantErr: false,
444 },
445 }
446 for _, tt := range tests {
447 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
448 t.Run(tt.name, func(t *testing.T) {
449 got, err := HandleChatSend(tt.args.cc, tt.args.t)
450
451 if (err != nil) != tt.wantErr {
452 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
453 return
454 }
455 if !assert.Equal(t, tt.want, got) {
456 t.Errorf("HandleChatSend() got = %v, want %v", got, tt.want)
457 }
458 })
459 }
460 }
461
462 func TestHandleGetFileInfo(t *testing.T) {
463 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
464
465 type args struct {
466 cc *ClientConn
467 t *Transaction
468 }
469 tests := []struct {
470 name string
471 args args
472 wantRes []Transaction
473 wantErr bool
474 }{
475 {
476 name: "returns expected fields when a valid file is requested",
477 args: args{
478 cc: &ClientConn{
479 ID: &[]byte{0x00, 0x01},
480 Server: &Server{
481 Config: &Config{
482 FileRoot: func() string {
483 path, _ := os.Getwd()
484 return path + "/test/config/Files"
485 }(),
486 },
487 },
488 },
489 t: NewTransaction(
490 tranGetFileInfo, nil,
491 NewField(fieldFileName, []byte("testfile.txt")),
492 NewField(fieldFilePath, []byte{0x00, 0x00}),
493 ),
494 },
495 wantRes: []Transaction{
496 {
497 clientID: &[]byte{0, 1},
498 Flags: 0x00,
499 IsReply: 0x01,
500 Type: []byte{0, 0xce},
501 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
502 ErrorCode: []byte{0, 0, 0, 0},
503 Fields: []Field{
504 NewField(fieldFileName, []byte("testfile.txt")),
505 NewField(fieldFileTypeString, []byte("TEXT")),
506 NewField(fieldFileCreatorString, []byte("ttxt")),
507 NewField(fieldFileComment, []byte{}),
508 NewField(fieldFileType, []byte("TEXT")),
509 NewField(fieldFileCreateDate, make([]byte, 8)),
510 NewField(fieldFileModifyDate, make([]byte, 8)),
511 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
512 },
513 },
514 },
515 wantErr: false,
516 },
517 }
518 for _, tt := range tests {
519 t.Run(tt.name, func(t *testing.T) {
520 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
521
522 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
523 if (err != nil) != tt.wantErr {
524 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
525 return
526 }
527
528 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
529 // TODO: revisit how to test this by mocking the stat calls
530 gotRes[0].Fields[5].Data = make([]byte, 8)
531 gotRes[0].Fields[6].Data = make([]byte, 8)
532 if !assert.Equal(t, tt.wantRes, gotRes) {
533 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
534 }
535 })
536 }
537 }
538
539 func TestHandleNewFolder(t *testing.T) {
540 type args struct {
541 cc *ClientConn
542 t *Transaction
543 }
544 tests := []struct {
545 setup func()
546 name string
547 args args
548 wantRes []Transaction
549 wantErr bool
550 }{
551 {
552 name: "when path is nested",
553 args: args{
554 cc: &ClientConn{
555 ID: &[]byte{0, 1},
556 Server: &Server{
557 Config: &Config{
558 FileRoot: "/Files/",
559 },
560 },
561 },
562 t: NewTransaction(
563 tranNewFolder, &[]byte{0, 1},
564 NewField(fieldFileName, []byte("testFolder")),
565 NewField(fieldFilePath, []byte{
566 0x00, 0x01,
567 0x00, 0x00,
568 0x03,
569 0x61, 0x61, 0x61,
570 }),
571 ),
572 },
573 setup: func() {
574 mfs := MockFileStore{}
575 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
576 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
577 FS = mfs
578 },
579 wantRes: []Transaction{
580 {
581 clientID: &[]byte{0, 1},
582 Flags: 0x00,
583 IsReply: 0x01,
584 Type: []byte{0, 0xcd},
585 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
586 ErrorCode: []byte{0, 0, 0, 0},
587 },
588 },
589 wantErr: false,
590 },
591 {
592 name: "when path is not nested",
593 args: args{
594 cc: &ClientConn{
595 ID: &[]byte{0, 1},
596 Server: &Server{
597 Config: &Config{
598 FileRoot: "/Files",
599 },
600 },
601 },
602 t: NewTransaction(
603 tranNewFolder, &[]byte{0, 1},
604 NewField(fieldFileName, []byte("testFolder")),
605 ),
606 },
607 setup: func() {
608 mfs := MockFileStore{}
609 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
610 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
611 FS = mfs
612 },
613 wantRes: []Transaction{
614 {
615 clientID: &[]byte{0, 1},
616 Flags: 0x00,
617 IsReply: 0x01,
618 Type: []byte{0, 0xcd},
619 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
620 ErrorCode: []byte{0, 0, 0, 0},
621 },
622 },
623 wantErr: false,
624 },
625 {
626 name: "when UnmarshalBinary returns an err",
627 args: args{
628 cc: &ClientConn{
629 ID: &[]byte{0, 1},
630 Server: &Server{
631 Config: &Config{
632 FileRoot: "/Files/",
633 },
634 },
635 },
636 t: NewTransaction(
637 tranNewFolder, &[]byte{0, 1},
638 NewField(fieldFileName, []byte("testFolder")),
639 NewField(fieldFilePath, []byte{
640 0x00,
641 }),
642 ),
643 },
644 setup: func() {
645 mfs := MockFileStore{}
646 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
647 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
648 FS = mfs
649 },
650 wantRes: []Transaction{},
651 wantErr: true,
652 },
653 {
654 name: "fieldFileName does not allow directory traversal",
655 args: args{
656 cc: &ClientConn{
657 ID: &[]byte{0, 1},
658 Server: &Server{
659 Config: &Config{
660 FileRoot: "/Files/",
661 },
662 },
663 },
664 t: NewTransaction(
665 tranNewFolder, &[]byte{0, 1},
666 NewField(fieldFileName, []byte("../../testFolder")),
667 ),
668 },
669 setup: func() {
670 mfs := MockFileStore{}
671 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
672 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
673 FS = mfs
674 },
675 wantRes: []Transaction{
676 {
677 clientID: &[]byte{0, 1},
678 Flags: 0x00,
679 IsReply: 0x01,
680 Type: []byte{0, 0xcd},
681 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
682 ErrorCode: []byte{0, 0, 0, 0},
683 },
684 }, wantErr: false,
685 },
686 {
687 name: "fieldFilePath does not allow directory traversal",
688 args: args{
689 cc: &ClientConn{
690 ID: &[]byte{0, 1},
691 Server: &Server{
692 Config: &Config{
693 FileRoot: "/Files/",
694 },
695 },
696 },
697 t: NewTransaction(
698 tranNewFolder, &[]byte{0, 1},
699 NewField(fieldFileName, []byte("testFolder")),
700 NewField(fieldFilePath, []byte{
701 0x00, 0x02,
702 0x00, 0x00,
703 0x03,
704 0x2e, 0x2e, 0x2f,
705 0x00, 0x00,
706 0x03,
707 0x66, 0x6f, 0x6f,
708 }),
709 ),
710 },
711 setup: func() {
712 mfs := MockFileStore{}
713 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
714 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
715 FS = mfs
716 },
717 wantRes: []Transaction{
718 {
719 clientID: &[]byte{0, 1},
720 Flags: 0x00,
721 IsReply: 0x01,
722 Type: []byte{0, 0xcd},
723 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
724 ErrorCode: []byte{0, 0, 0, 0},
725 },
726 }, wantErr: false,
727 },
728 }
729 for _, tt := range tests {
730 t.Run(tt.name, func(t *testing.T) {
731 tt.setup()
732
733 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
734 if (err != nil) != tt.wantErr {
735 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
736 return
737 }
738 if !tranAssertEqual(t, tt.wantRes, gotRes) {
739 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
740 }
741 })
742 }
743 }
744
745 func TestHandleUploadFile(t *testing.T) {
746 type args struct {
747 cc *ClientConn
748 t *Transaction
749 }
750 tests := []struct {
751 name string
752 args args
753 wantRes []Transaction
754 wantErr bool
755 }{
756 {
757 name: "when request is valid",
758 args: args{
759 cc: &ClientConn{
760 Server: &Server{
761 FileTransfers: map[uint32]*FileTransfer{},
762 },
763 Account: &Account{
764 Access: func() *[]byte {
765 var bits accessBitmap
766 bits.Set(accessUploadFile)
767 access := bits[:]
768 return &access
769 }(),
770 },
771 },
772 t: NewTransaction(
773 tranUploadFile, &[]byte{0, 1},
774 NewField(fieldFileName, []byte("testFile")),
775 NewField(fieldFilePath, []byte{
776 0x00, 0x01,
777 0x00, 0x00,
778 0x03,
779 0x2e, 0x2e, 0x2f,
780 }),
781 ),
782 },
783 wantRes: []Transaction{
784 {
785 Flags: 0x00,
786 IsReply: 0x01,
787 Type: []byte{0, 0xcb},
788 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
789 ErrorCode: []byte{0, 0, 0, 0},
790 Fields: []Field{
791 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
792 },
793 },
794 },
795 wantErr: false,
796 },
797 {
798 name: "when user does not have required access",
799 args: args{
800 cc: &ClientConn{
801 Account: &Account{
802 Access: func() *[]byte {
803 var bits accessBitmap
804 access := bits[:]
805 return &access
806 }(),
807 },
808 Server: &Server{
809 FileTransfers: map[uint32]*FileTransfer{},
810 },
811 },
812 t: NewTransaction(
813 tranUploadFile, &[]byte{0, 1},
814 NewField(fieldFileName, []byte("testFile")),
815 NewField(fieldFilePath, []byte{
816 0x00, 0x01,
817 0x00, 0x00,
818 0x03,
819 0x2e, 0x2e, 0x2f,
820 }),
821 ),
822 },
823 wantRes: []Transaction{
824 {
825 Flags: 0x00,
826 IsReply: 0x01,
827 Type: []byte{0, 0x00},
828 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
829 ErrorCode: []byte{0, 0, 0, 1},
830 Fields: []Field{
831 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
832 },
833 },
834 },
835 wantErr: false,
836 },
837 }
838 for _, tt := range tests {
839 t.Run(tt.name, func(t *testing.T) {
840 rand.Seed(1)
841 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
842 if (err != nil) != tt.wantErr {
843 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
844 return
845 }
846 if !tranAssertEqual(t, tt.wantRes, gotRes) {
847 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)
848 }
849 })
850 }
851 }