]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
Add partial support for file create/modify timestamps
[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 },
232 },
233 },
234 t: &Transaction{
235 ID: []byte{0, 0, 0, 1},
236 Type: []byte{0, 1},
237 },
238 },
239 want: []Transaction{
240 {
241 clientID: &[]byte{1, 1},
242 Flags: 0x00,
243 IsReply: 0x01,
244 Type: []byte{0, 1},
245 ID: []byte{0, 0, 0, 1},
246 ErrorCode: []byte{0, 0, 0, 0},
247 Fields: []Field{
248 NewField(
249 fieldUsernameWithInfo,
250 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
251 ),
252 },
253 },
254 },
255 wantErr: false,
256 },
257 }
258 for _, tt := range tests {
259 t.Run(tt.name, func(t *testing.T) {
260 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
261 if (err != nil) != tt.wantErr {
262 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
263 return
264 }
265 if !reflect.DeepEqual(got, tt.want) {
266 t.Errorf("HandleGetUserNameList() got = %v, want %v", got, tt.want)
267 }
268 })
269 }
270 }
271
272 func TestHandleChatSend(t *testing.T) {
273 type args struct {
274 cc *ClientConn
275 t *Transaction
276 }
277 tests := []struct {
278 name string
279 args args
280 want []Transaction
281 wantErr bool
282 }{
283 {
284 name: "sends chat msg transaction to all clients",
285 args: args{
286 cc: &ClientConn{
287 UserName: []byte{0x00, 0x01},
288 Server: &Server{
289 Clients: map[uint16]*ClientConn{
290 uint16(1): {
291 Account: &Account{
292 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
293 },
294 ID: &[]byte{0, 1},
295 },
296 uint16(2): {
297 Account: &Account{
298 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
299 },
300 ID: &[]byte{0, 2},
301 },
302 },
303 },
304 },
305 t: &Transaction{
306 Fields: []Field{
307 NewField(fieldData, []byte("hai")),
308 },
309 },
310 },
311 want: []Transaction{
312 {
313 clientID: &[]byte{0, 1},
314 Flags: 0x00,
315 IsReply: 0x00,
316 Type: []byte{0, 0x6a},
317 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
318 ErrorCode: []byte{0, 0, 0, 0},
319 Fields: []Field{
320 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
321 },
322 },
323 {
324 clientID: &[]byte{0, 2},
325 Flags: 0x00,
326 IsReply: 0x00,
327 Type: []byte{0, 0x6a},
328 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
329 ErrorCode: []byte{0, 0, 0, 0},
330 Fields: []Field{
331 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
332 },
333 },
334 },
335 wantErr: false,
336 },
337 {
338 name: "sends chat msg as emote if fieldChatOptions is set",
339 args: args{
340 cc: &ClientConn{
341 UserName: []byte("Testy McTest"),
342 Server: &Server{
343 Clients: map[uint16]*ClientConn{
344 uint16(1): {
345 Account: &Account{
346 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
347 },
348 ID: &[]byte{0, 1},
349 },
350 uint16(2): {
351 Account: &Account{
352 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
353 },
354 ID: &[]byte{0, 2},
355 },
356 },
357 },
358 },
359 t: &Transaction{
360 Fields: []Field{
361 NewField(fieldData, []byte("performed action")),
362 NewField(fieldChatOptions, []byte{0x00, 0x01}),
363 },
364 },
365 },
366 want: []Transaction{
367 {
368 clientID: &[]byte{0, 1},
369 Flags: 0x00,
370 IsReply: 0x00,
371 Type: []byte{0, 0x6a},
372 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
373 ErrorCode: []byte{0, 0, 0, 0},
374 Fields: []Field{
375 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
376 },
377 },
378 {
379 clientID: &[]byte{0, 2},
380 Flags: 0x00,
381 IsReply: 0x00,
382 Type: []byte{0, 0x6a},
383 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
384 ErrorCode: []byte{0, 0, 0, 0},
385 Fields: []Field{
386 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
387 },
388 },
389 },
390 wantErr: false,
391 },
392 {
393 name: "only sends chat msg to clients with accessReadChat permission",
394 args: args{
395 cc: &ClientConn{
396 UserName: []byte{0x00, 0x01},
397 Server: &Server{
398 Clients: map[uint16]*ClientConn{
399 uint16(1): {
400 Account: &Account{
401 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
402 },
403 ID: &[]byte{0, 1},
404 },
405 uint16(2): {
406 Account: &Account{
407 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
408 },
409 ID: &[]byte{0, 2},
410 },
411 },
412 },
413 },
414 t: &Transaction{
415 Fields: []Field{
416 NewField(fieldData, []byte("hai")),
417 },
418 },
419 },
420 want: []Transaction{
421 {
422 clientID: &[]byte{0, 1},
423 Flags: 0x00,
424 IsReply: 0x00,
425 Type: []byte{0, 0x6a},
426 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
427 ErrorCode: []byte{0, 0, 0, 0},
428 Fields: []Field{
429 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
430 },
431 },
432 },
433 wantErr: false,
434 },
435 }
436 for _, tt := range tests {
437 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
438 t.Run(tt.name, func(t *testing.T) {
439 got, err := HandleChatSend(tt.args.cc, tt.args.t)
440
441 if (err != nil) != tt.wantErr {
442 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
443 return
444 }
445 if !assert.Equal(t, tt.want, got) {
446 t.Errorf("HandleChatSend() got = %v, want %v", got, tt.want)
447 }
448 })
449 }
450 }
451
452 func TestHandleGetFileInfo(t *testing.T) {
453 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
454
455 type args struct {
456 cc *ClientConn
457 t *Transaction
458 }
459 tests := []struct {
460 name string
461 args args
462 wantRes []Transaction
463 wantErr bool
464 }{
465 {
466 name: "returns expected fields when a valid file is requested",
467 args: args{
468 cc: &ClientConn{
469 ID: &[]byte{0x00, 0x01},
470 Server: &Server{
471 Config: &Config{
472 FileRoot: func() string {
473 path, _ := os.Getwd()
474 return path + "/test/config/Files"
475 }(),
476 },
477 },
478 },
479 t: NewTransaction(
480 tranGetFileInfo, nil,
481 NewField(fieldFileName, []byte("testfile.txt")),
482 NewField(fieldFilePath, []byte{0x00, 0x00}),
483 ),
484 },
485 wantRes: []Transaction{
486 {
487 clientID: &[]byte{0, 1},
488 Flags: 0x00,
489 IsReply: 0x01,
490 Type: []byte{0, 0xce},
491 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
492 ErrorCode: []byte{0, 0, 0, 0},
493 Fields: []Field{
494 NewField(fieldFileName, []byte("testfile.txt")),
495 NewField(fieldFileTypeString, []byte("TEXT")),
496 NewField(fieldFileCreatorString, []byte("ttxt")),
497 NewField(fieldFileComment, []byte("TODO")),
498 NewField(fieldFileType, []byte("TEXT")),
499 NewField(fieldFileCreateDate, make([]byte, 8)),
500 NewField(fieldFileModifyDate, make([]byte, 8)),
501 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
502 },
503 },
504 },
505 wantErr: false,
506 },
507 }
508 for _, tt := range tests {
509 t.Run(tt.name, func(t *testing.T) {
510 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
511
512 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
513 if (err != nil) != tt.wantErr {
514 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
515 return
516 }
517
518 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
519 // TODO: revisit how to test this by mocking the stat calls
520 gotRes[0].Fields[5].Data = make([]byte, 8)
521 gotRes[0].Fields[6].Data = make([]byte, 8)
522 if !assert.Equal(t, tt.wantRes, gotRes) {
523 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
524 }
525 })
526 }
527 }
528
529 func TestHandleNewFolder(t *testing.T) {
530 type args struct {
531 cc *ClientConn
532 t *Transaction
533 }
534 tests := []struct {
535 setup func()
536 name string
537 args args
538 wantRes []Transaction
539 wantErr bool
540 }{
541 {
542 name: "when path is nested",
543 args: args{
544 cc: &ClientConn{
545 ID: &[]byte{0, 1},
546 Server: &Server{
547 Config: &Config{
548 FileRoot: "/Files/",
549 },
550 },
551 },
552 t: NewTransaction(
553 tranNewFolder, &[]byte{0, 1},
554 NewField(fieldFileName, []byte("testFolder")),
555 NewField(fieldFilePath, []byte{
556 0x00, 0x01,
557 0x00, 0x00,
558 0x03,
559 0x61, 0x61, 0x61,
560 }),
561 ),
562 },
563 setup: func() {
564 mfs := MockFileStore{}
565 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
566 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
567 FS = mfs
568 },
569 wantRes: []Transaction{
570 {
571 clientID: &[]byte{0, 1},
572 Flags: 0x00,
573 IsReply: 0x01,
574 Type: []byte{0, 0xcd},
575 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
576 ErrorCode: []byte{0, 0, 0, 0},
577 },
578 },
579 wantErr: false,
580 },
581 {
582 name: "when path is not nested",
583 args: args{
584 cc: &ClientConn{
585 ID: &[]byte{0, 1},
586 Server: &Server{
587 Config: &Config{
588 FileRoot: "/Files",
589 },
590 },
591 },
592 t: NewTransaction(
593 tranNewFolder, &[]byte{0, 1},
594 NewField(fieldFileName, []byte("testFolder")),
595 ),
596 },
597 setup: func() {
598 mfs := MockFileStore{}
599 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
600 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
601 FS = mfs
602 },
603 wantRes: []Transaction{
604 {
605 clientID: &[]byte{0, 1},
606 Flags: 0x00,
607 IsReply: 0x01,
608 Type: []byte{0, 0xcd},
609 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
610 ErrorCode: []byte{0, 0, 0, 0},
611 },
612 },
613 wantErr: false,
614 },
615 {
616 name: "when UnmarshalBinary returns an err",
617 args: args{
618 cc: &ClientConn{
619 ID: &[]byte{0, 1},
620 Server: &Server{
621 Config: &Config{
622 FileRoot: "/Files/",
623 },
624 },
625 },
626 t: NewTransaction(
627 tranNewFolder, &[]byte{0, 1},
628 NewField(fieldFileName, []byte("testFolder")),
629 NewField(fieldFilePath, []byte{
630 0x00,
631 }),
632 ),
633 },
634 setup: func() {
635 mfs := MockFileStore{}
636 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
637 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
638 FS = mfs
639 },
640 wantRes: []Transaction{},
641 wantErr: true,
642 },
643 {
644 name: "fieldFileName does not allow directory traversal",
645 args: args{
646 cc: &ClientConn{
647 ID: &[]byte{0, 1},
648 Server: &Server{
649 Config: &Config{
650 FileRoot: "/Files/",
651 },
652 },
653 },
654 t: NewTransaction(
655 tranNewFolder, &[]byte{0, 1},
656 NewField(fieldFileName, []byte("../../testFolder")),
657 ),
658 },
659 setup: func() {
660 mfs := MockFileStore{}
661 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
662 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
663 FS = mfs
664 },
665 wantRes: []Transaction{
666 {
667 clientID: &[]byte{0, 1},
668 Flags: 0x00,
669 IsReply: 0x01,
670 Type: []byte{0, 0xcd},
671 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
672 ErrorCode: []byte{0, 0, 0, 0},
673 },
674 }, wantErr: false,
675 },
676 {
677 name: "fieldFilePath does not allow directory traversal",
678 args: args{
679 cc: &ClientConn{
680 ID: &[]byte{0, 1},
681 Server: &Server{
682 Config: &Config{
683 FileRoot: "/Files/",
684 },
685 },
686 },
687 t: NewTransaction(
688 tranNewFolder, &[]byte{0, 1},
689 NewField(fieldFileName, []byte("testFolder")),
690 NewField(fieldFilePath, []byte{
691 0x00, 0x02,
692 0x00, 0x00,
693 0x03,
694 0x2e, 0x2e, 0x2f,
695 0x00, 0x00,
696 0x03,
697 0x66, 0x6f, 0x6f,
698 }),
699 ),
700 },
701 setup: func() {
702 mfs := MockFileStore{}
703 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
704 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
705 FS = mfs
706 },
707 wantRes: []Transaction{
708 {
709 clientID: &[]byte{0, 1},
710 Flags: 0x00,
711 IsReply: 0x01,
712 Type: []byte{0, 0xcd},
713 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
714 ErrorCode: []byte{0, 0, 0, 0},
715 },
716 }, wantErr: false,
717 },
718 }
719 for _, tt := range tests {
720 t.Run(tt.name, func(t *testing.T) {
721 tt.setup()
722
723 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
724 if (err != nil) != tt.wantErr {
725 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
726 return
727 }
728 if !tranAssertEqual(t, tt.wantRes, gotRes) {
729 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
730 }
731 })
732 }
733 }
734
735 func TestHandleUploadFile(t *testing.T) {
736 type args struct {
737 cc *ClientConn
738 t *Transaction
739 }
740 tests := []struct {
741 name string
742 args args
743 wantRes []Transaction
744 wantErr bool
745 }{
746 {
747 name: "when request is valid",
748 args: args{
749 cc: &ClientConn{
750 Server: &Server{
751 FileTransfers: map[uint32]*FileTransfer{},
752 },
753 Account: &Account{
754 Access: func() *[]byte {
755 var bits accessBitmap
756 bits.Set(accessUploadFile)
757 access := bits[:]
758 return &access
759 }(),
760 },
761 },
762 t: NewTransaction(
763 tranUploadFile, &[]byte{0, 1},
764 NewField(fieldFileName, []byte("testFile")),
765 NewField(fieldFilePath, []byte{
766 0x00, 0x01,
767 0x00, 0x00,
768 0x03,
769 0x2e, 0x2e, 0x2f,
770 }),
771 ),
772 },
773 wantRes: []Transaction{
774 {
775 Flags: 0x00,
776 IsReply: 0x01,
777 Type: []byte{0, 0xcb},
778 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
779 ErrorCode: []byte{0, 0, 0, 0},
780 Fields: []Field{
781 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
782 },
783 },
784 },
785 wantErr: false,
786 },
787 {
788 name: "when user does not have required access",
789 args: args{
790 cc: &ClientConn{
791 Account: &Account{
792 Access: func() *[]byte {
793 var bits accessBitmap
794 access := bits[:]
795 return &access
796 }(),
797 },
798 Server: &Server{
799 FileTransfers: map[uint32]*FileTransfer{},
800 },
801 },
802 t: NewTransaction(
803 tranUploadFile, &[]byte{0, 1},
804 NewField(fieldFileName, []byte("testFile")),
805 NewField(fieldFilePath, []byte{
806 0x00, 0x01,
807 0x00, 0x00,
808 0x03,
809 0x2e, 0x2e, 0x2f,
810 }),
811 ),
812 },
813 wantRes: []Transaction{
814 {
815 Flags: 0x00,
816 IsReply: 0x01,
817 Type: []byte{0, 0x00},
818 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
819 ErrorCode: []byte{0, 0, 0, 1},
820 Fields: []Field{
821 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
822 },
823 },
824 },
825 wantErr: false,
826 },
827 }
828 for _, tt := range tests {
829 t.Run(tt.name, func(t *testing.T) {
830 rand.Seed(1)
831 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
832 if (err != nil) != tt.wantErr {
833 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
834 return
835 }
836 if !tranAssertEqual(t, tt.wantRes, gotRes) {
837 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)
838 }
839 })
840 }
841 }