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