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