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