]> git.r.bdr.sh - rbdr/mobius/blob - hotline/transaction_handlers_test.go
525bb8895efe51fc5a391e0367535ba4aefff4b5
[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, 0},
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, 0},
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 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
1060 if (err != nil) != tt.wantErr {
1061 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
1062 return
1063 }
1064
1065 if !tranAssertEqual(t, tt.wantRes, gotRes) {
1066 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
1067 }
1068 })
1069 }
1070 }
1071
1072 func TestHandleUploadFile(t *testing.T) {
1073 type args struct {
1074 cc *ClientConn
1075 t *Transaction
1076 }
1077 tests := []struct {
1078 name string
1079 args args
1080 wantRes []Transaction
1081 wantErr bool
1082 }{
1083 {
1084 name: "when request is valid and user has Upload Anywhere permission",
1085 args: args{
1086 cc: &ClientConn{
1087 Server: &Server{
1088 FS: &OSFileStore{},
1089 fileTransfers: map[[4]byte]*FileTransfer{},
1090 Config: &Config{
1091 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1092 }},
1093 transfers: map[int]map[[4]byte]*FileTransfer{
1094 FileUpload: {},
1095 },
1096 Account: &Account{
1097 Access: func() accessBitmap {
1098 var bits accessBitmap
1099 bits.Set(accessUploadFile)
1100 bits.Set(accessUploadAnywhere)
1101 return bits
1102 }(),
1103 },
1104 },
1105 t: NewTransaction(
1106 TranUploadFile, &[]byte{0, 1},
1107 NewField(FieldFileName, []byte("testFile")),
1108 NewField(FieldFilePath, []byte{
1109 0x00, 0x01,
1110 0x00, 0x00,
1111 0x03,
1112 0x2e, 0x2e, 0x2f,
1113 }),
1114 ),
1115 },
1116 wantRes: []Transaction{
1117 {
1118 Flags: 0x00,
1119 IsReply: 0x01,
1120 Type: []byte{0, 0},
1121 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1122 ErrorCode: []byte{0, 0, 0, 0},
1123 Fields: []Field{
1124 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
1125 },
1126 },
1127 },
1128 wantErr: false,
1129 },
1130 {
1131 name: "when user does not have required access",
1132 args: args{
1133 cc: &ClientConn{
1134 Account: &Account{
1135 Access: func() accessBitmap {
1136 var bits accessBitmap
1137 return bits
1138 }(),
1139 },
1140 },
1141 t: NewTransaction(
1142 TranUploadFile, &[]byte{0, 1},
1143 NewField(FieldFileName, []byte("testFile")),
1144 NewField(FieldFilePath, []byte{
1145 0x00, 0x01,
1146 0x00, 0x00,
1147 0x03,
1148 0x2e, 0x2e, 0x2f,
1149 }),
1150 ),
1151 },
1152 wantRes: []Transaction{
1153 {
1154 Flags: 0x00,
1155 IsReply: 0x01,
1156 Type: []byte{0, 0},
1157 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1158 ErrorCode: []byte{0, 0, 0, 1},
1159 Fields: []Field{
1160 NewField(FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
1161 },
1162 },
1163 },
1164 wantErr: false,
1165 },
1166 }
1167 for _, tt := range tests {
1168 t.Run(tt.name, func(t *testing.T) {
1169 rand.Seed(1)
1170 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
1171 if (err != nil) != tt.wantErr {
1172 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
1173 return
1174 }
1175
1176 tranAssertEqual(t, tt.wantRes, gotRes)
1177 })
1178 }
1179 }
1180
1181 func TestHandleMakeAlias(t *testing.T) {
1182 type args struct {
1183 cc *ClientConn
1184 t *Transaction
1185 }
1186 tests := []struct {
1187 name string
1188 args args
1189 wantRes []Transaction
1190 wantErr bool
1191 }{
1192 {
1193 name: "with valid input and required permissions",
1194 args: args{
1195 cc: &ClientConn{
1196 logger: NewTestLogger(),
1197 Account: &Account{
1198 Access: func() accessBitmap {
1199 var bits accessBitmap
1200 bits.Set(accessMakeAlias)
1201 return bits
1202 }(),
1203 },
1204 Server: &Server{
1205 Config: &Config{
1206 FileRoot: func() string {
1207 path, _ := os.Getwd()
1208 return path + "/test/config/Files"
1209 }(),
1210 },
1211 Logger: NewTestLogger(),
1212 FS: func() *MockFileStore {
1213 mfs := &MockFileStore{}
1214 path, _ := os.Getwd()
1215 mfs.On(
1216 "Symlink",
1217 path+"/test/config/Files/foo/testFile",
1218 path+"/test/config/Files/bar/testFile",
1219 ).Return(nil)
1220 return mfs
1221 }(),
1222 },
1223 },
1224 t: NewTransaction(
1225 TranMakeFileAlias, &[]byte{0, 1},
1226 NewField(FieldFileName, []byte("testFile")),
1227 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1228 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1229 ),
1230 },
1231 wantRes: []Transaction{
1232 {
1233 Flags: 0x00,
1234 IsReply: 0x01,
1235 Type: []byte{0, 0},
1236 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1237 ErrorCode: []byte{0, 0, 0, 0},
1238 Fields: []Field(nil),
1239 },
1240 },
1241 wantErr: false,
1242 },
1243 {
1244 name: "when symlink returns an error",
1245 args: args{
1246 cc: &ClientConn{
1247 logger: NewTestLogger(),
1248 Account: &Account{
1249 Access: func() accessBitmap {
1250 var bits accessBitmap
1251 bits.Set(accessMakeAlias)
1252 return bits
1253 }(),
1254 },
1255 Server: &Server{
1256 Config: &Config{
1257 FileRoot: func() string {
1258 path, _ := os.Getwd()
1259 return path + "/test/config/Files"
1260 }(),
1261 },
1262 Logger: NewTestLogger(),
1263 FS: func() *MockFileStore {
1264 mfs := &MockFileStore{}
1265 path, _ := os.Getwd()
1266 mfs.On(
1267 "Symlink",
1268 path+"/test/config/Files/foo/testFile",
1269 path+"/test/config/Files/bar/testFile",
1270 ).Return(errors.New("ohno"))
1271 return mfs
1272 }(),
1273 },
1274 },
1275 t: NewTransaction(
1276 TranMakeFileAlias, &[]byte{0, 1},
1277 NewField(FieldFileName, []byte("testFile")),
1278 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1279 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1280 ),
1281 },
1282 wantRes: []Transaction{
1283 {
1284 Flags: 0x00,
1285 IsReply: 0x01,
1286 Type: []byte{0, 0},
1287 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1288 ErrorCode: []byte{0, 0, 0, 1},
1289 Fields: []Field{
1290 NewField(FieldError, []byte("Error creating alias")),
1291 },
1292 },
1293 },
1294 wantErr: false,
1295 },
1296 {
1297 name: "when user does not have required permission",
1298 args: args{
1299 cc: &ClientConn{
1300 logger: NewTestLogger(),
1301 Account: &Account{
1302 Access: func() accessBitmap {
1303 var bits accessBitmap
1304 return bits
1305 }(),
1306 },
1307 Server: &Server{
1308 Config: &Config{
1309 FileRoot: func() string {
1310 path, _ := os.Getwd()
1311 return path + "/test/config/Files"
1312 }(),
1313 },
1314 },
1315 },
1316 t: NewTransaction(
1317 TranMakeFileAlias, &[]byte{0, 1},
1318 NewField(FieldFileName, []byte("testFile")),
1319 NewField(FieldFilePath, []byte{
1320 0x00, 0x01,
1321 0x00, 0x00,
1322 0x03,
1323 0x2e, 0x2e, 0x2e,
1324 }),
1325 NewField(FieldFileNewPath, []byte{
1326 0x00, 0x01,
1327 0x00, 0x00,
1328 0x03,
1329 0x2e, 0x2e, 0x2e,
1330 }),
1331 ),
1332 },
1333 wantRes: []Transaction{
1334 {
1335 Flags: 0x00,
1336 IsReply: 0x01,
1337 Type: []byte{0, 0},
1338 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1339 ErrorCode: []byte{0, 0, 0, 1},
1340 Fields: []Field{
1341 NewField(FieldError, []byte("You are not allowed to make aliases.")),
1342 },
1343 },
1344 },
1345 wantErr: false,
1346 },
1347 }
1348 for _, tt := range tests {
1349 t.Run(tt.name, func(t *testing.T) {
1350 gotRes, err := HandleMakeAlias(tt.args.cc, tt.args.t)
1351 if (err != nil) != tt.wantErr {
1352 t.Errorf("HandleMakeAlias(%v, %v)", tt.args.cc, tt.args.t)
1353 return
1354 }
1355
1356 tranAssertEqual(t, tt.wantRes, gotRes)
1357 })
1358 }
1359 }
1360
1361 func TestHandleGetUser(t *testing.T) {
1362 type args struct {
1363 cc *ClientConn
1364 t *Transaction
1365 }
1366 tests := []struct {
1367 name string
1368 args args
1369 wantRes []Transaction
1370 wantErr assert.ErrorAssertionFunc
1371 }{
1372 {
1373 name: "when account is valid",
1374 args: args{
1375 cc: &ClientConn{
1376 Account: &Account{
1377 Access: func() accessBitmap {
1378 var bits accessBitmap
1379 bits.Set(accessOpenUser)
1380 return bits
1381 }(),
1382 },
1383 Server: &Server{
1384 Accounts: map[string]*Account{
1385 "guest": {
1386 Login: "guest",
1387 Name: "Guest",
1388 Password: "password",
1389 Access: accessBitmap{},
1390 },
1391 },
1392 },
1393 },
1394 t: NewTransaction(
1395 TranGetUser, &[]byte{0, 1},
1396 NewField(FieldUserLogin, []byte("guest")),
1397 ),
1398 },
1399 wantRes: []Transaction{
1400 {
1401 Flags: 0x00,
1402 IsReply: 0x01,
1403 Type: []byte{0, 0},
1404 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1405 ErrorCode: []byte{0, 0, 0, 0},
1406 Fields: []Field{
1407 NewField(FieldUserName, []byte("Guest")),
1408 NewField(FieldUserLogin, negateString([]byte("guest"))),
1409 NewField(FieldUserPassword, []byte("password")),
1410 NewField(FieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
1411 },
1412 },
1413 },
1414 wantErr: assert.NoError,
1415 },
1416 {
1417 name: "when user does not have required permission",
1418 args: args{
1419 cc: &ClientConn{
1420 Account: &Account{
1421 Access: func() accessBitmap {
1422 var bits accessBitmap
1423 return bits
1424 }(),
1425 },
1426 Server: &Server{
1427 Accounts: map[string]*Account{},
1428 },
1429 },
1430 t: NewTransaction(
1431 TranGetUser, &[]byte{0, 1},
1432 NewField(FieldUserLogin, []byte("nonExistentUser")),
1433 ),
1434 },
1435 wantRes: []Transaction{
1436 {
1437 Flags: 0x00,
1438 IsReply: 0x01,
1439 Type: []byte{0, 0},
1440 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1441 ErrorCode: []byte{0, 0, 0, 1},
1442 Fields: []Field{
1443 NewField(FieldError, []byte("You are not allowed to view accounts.")),
1444 },
1445 },
1446 },
1447 wantErr: assert.NoError,
1448 },
1449 {
1450 name: "when account does not exist",
1451 args: args{
1452 cc: &ClientConn{
1453 Account: &Account{
1454 Access: func() accessBitmap {
1455 var bits accessBitmap
1456 bits.Set(accessOpenUser)
1457 return bits
1458 }(),
1459 },
1460 Server: &Server{
1461 Accounts: map[string]*Account{},
1462 },
1463 },
1464 t: NewTransaction(
1465 TranGetUser, &[]byte{0, 1},
1466 NewField(FieldUserLogin, []byte("nonExistentUser")),
1467 ),
1468 },
1469 wantRes: []Transaction{
1470 {
1471 Flags: 0x00,
1472 IsReply: 0x01,
1473 Type: []byte{0, 0},
1474 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1475 ErrorCode: []byte{0, 0, 0, 1},
1476 Fields: []Field{
1477 NewField(FieldError, []byte("Account does not exist.")),
1478 },
1479 },
1480 },
1481 wantErr: assert.NoError,
1482 },
1483 }
1484 for _, tt := range tests {
1485 t.Run(tt.name, func(t *testing.T) {
1486 gotRes, err := HandleGetUser(tt.args.cc, tt.args.t)
1487 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetUser(%v, %v)", tt.args.cc, tt.args.t)) {
1488 return
1489 }
1490
1491 tranAssertEqual(t, tt.wantRes, gotRes)
1492 })
1493 }
1494 }
1495
1496 func TestHandleDeleteUser(t *testing.T) {
1497 type args struct {
1498 cc *ClientConn
1499 t *Transaction
1500 }
1501 tests := []struct {
1502 name string
1503 args args
1504 wantRes []Transaction
1505 wantErr assert.ErrorAssertionFunc
1506 }{
1507 {
1508 name: "when user dataFile",
1509 args: args{
1510 cc: &ClientConn{
1511 Account: &Account{
1512 Access: func() accessBitmap {
1513 var bits accessBitmap
1514 bits.Set(accessDeleteUser)
1515 return bits
1516 }(),
1517 },
1518 Server: &Server{
1519 Accounts: map[string]*Account{
1520 "testuser": {
1521 Login: "testuser",
1522 Name: "Testy McTest",
1523 Password: "password",
1524 Access: accessBitmap{},
1525 },
1526 },
1527 FS: func() *MockFileStore {
1528 mfs := &MockFileStore{}
1529 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1530 return mfs
1531 }(),
1532 },
1533 },
1534 t: NewTransaction(
1535 TranDeleteUser, &[]byte{0, 1},
1536 NewField(FieldUserLogin, negateString([]byte("testuser"))),
1537 ),
1538 },
1539 wantRes: []Transaction{
1540 {
1541 Flags: 0x00,
1542 IsReply: 0x01,
1543 Type: []byte{0, 0},
1544 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1545 ErrorCode: []byte{0, 0, 0, 0},
1546 Fields: []Field(nil),
1547 },
1548 },
1549 wantErr: assert.NoError,
1550 },
1551 {
1552 name: "when user does not have required permission",
1553 args: args{
1554 cc: &ClientConn{
1555 Account: &Account{
1556 Access: func() accessBitmap {
1557 var bits accessBitmap
1558 return bits
1559 }(),
1560 },
1561 Server: &Server{
1562 Accounts: map[string]*Account{},
1563 },
1564 },
1565 t: NewTransaction(
1566 TranDeleteUser, &[]byte{0, 1},
1567 NewField(FieldUserLogin, negateString([]byte("testuser"))),
1568 ),
1569 },
1570 wantRes: []Transaction{
1571 {
1572 Flags: 0x00,
1573 IsReply: 0x01,
1574 Type: []byte{0, 0},
1575 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1576 ErrorCode: []byte{0, 0, 0, 1},
1577 Fields: []Field{
1578 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
1579 },
1580 },
1581 },
1582 wantErr: assert.NoError,
1583 },
1584 }
1585 for _, tt := range tests {
1586 t.Run(tt.name, func(t *testing.T) {
1587 gotRes, err := HandleDeleteUser(tt.args.cc, tt.args.t)
1588 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteUser(%v, %v)", tt.args.cc, tt.args.t)) {
1589 return
1590 }
1591
1592 tranAssertEqual(t, tt.wantRes, gotRes)
1593 })
1594 }
1595 }
1596
1597 func TestHandleGetMsgs(t *testing.T) {
1598 type args struct {
1599 cc *ClientConn
1600 t *Transaction
1601 }
1602 tests := []struct {
1603 name string
1604 args args
1605 wantRes []Transaction
1606 wantErr assert.ErrorAssertionFunc
1607 }{
1608 {
1609 name: "returns news data",
1610 args: args{
1611 cc: &ClientConn{
1612 Account: &Account{
1613 Access: func() accessBitmap {
1614 var bits accessBitmap
1615 bits.Set(accessNewsReadArt)
1616 return bits
1617 }(),
1618 },
1619 Server: &Server{
1620 FlatNews: []byte("TEST"),
1621 },
1622 },
1623 t: NewTransaction(
1624 TranGetMsgs, &[]byte{0, 1},
1625 ),
1626 },
1627 wantRes: []Transaction{
1628 {
1629 Flags: 0x00,
1630 IsReply: 0x01,
1631 Type: []byte{0, 0},
1632 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1633 ErrorCode: []byte{0, 0, 0, 0},
1634 Fields: []Field{
1635 NewField(FieldData, []byte("TEST")),
1636 },
1637 },
1638 },
1639 wantErr: assert.NoError,
1640 },
1641 {
1642 name: "when user does not have required permission",
1643 args: args{
1644 cc: &ClientConn{
1645 Account: &Account{
1646 Access: func() accessBitmap {
1647 var bits accessBitmap
1648 return bits
1649 }(),
1650 },
1651 Server: &Server{
1652 Accounts: map[string]*Account{},
1653 },
1654 },
1655 t: NewTransaction(
1656 TranGetMsgs, &[]byte{0, 1},
1657 ),
1658 },
1659 wantRes: []Transaction{
1660 {
1661 Flags: 0x00,
1662 IsReply: 0x01,
1663 Type: []byte{0, 0},
1664 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1665 ErrorCode: []byte{0, 0, 0, 1},
1666 Fields: []Field{
1667 NewField(FieldError, []byte("You are not allowed to read news.")),
1668 },
1669 },
1670 },
1671 wantErr: assert.NoError,
1672 },
1673 }
1674 for _, tt := range tests {
1675 t.Run(tt.name, func(t *testing.T) {
1676 gotRes, err := HandleGetMsgs(tt.args.cc, tt.args.t)
1677 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetMsgs(%v, %v)", tt.args.cc, tt.args.t)) {
1678 return
1679 }
1680
1681 tranAssertEqual(t, tt.wantRes, gotRes)
1682 })
1683 }
1684 }
1685
1686 func TestHandleNewUser(t *testing.T) {
1687 type args struct {
1688 cc *ClientConn
1689 t *Transaction
1690 }
1691 tests := []struct {
1692 name string
1693 args args
1694 wantRes []Transaction
1695 wantErr assert.ErrorAssertionFunc
1696 }{
1697 {
1698 name: "when user does not have required permission",
1699 args: args{
1700 cc: &ClientConn{
1701 Account: &Account{
1702 Access: func() accessBitmap {
1703 var bits accessBitmap
1704 return bits
1705 }(),
1706 },
1707 Server: &Server{
1708 Accounts: map[string]*Account{},
1709 },
1710 },
1711 t: NewTransaction(
1712 TranNewUser, &[]byte{0, 1},
1713 ),
1714 },
1715 wantRes: []Transaction{
1716 {
1717 Flags: 0x00,
1718 IsReply: 0x01,
1719 Type: []byte{0, 0},
1720 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1721 ErrorCode: []byte{0, 0, 0, 1},
1722 Fields: []Field{
1723 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
1724 },
1725 },
1726 },
1727 wantErr: assert.NoError,
1728 },
1729 {
1730 name: "when user attempts to create account with greater access",
1731 args: args{
1732 cc: &ClientConn{
1733 Account: &Account{
1734 Access: func() accessBitmap {
1735 var bits accessBitmap
1736 bits.Set(accessCreateUser)
1737 return bits
1738 }(),
1739 },
1740 Server: &Server{
1741 Accounts: map[string]*Account{},
1742 },
1743 },
1744 t: NewTransaction(
1745 TranNewUser, &[]byte{0, 1},
1746 NewField(FieldUserLogin, []byte("userB")),
1747 NewField(
1748 FieldUserAccess,
1749 func() []byte {
1750 var bits accessBitmap
1751 bits.Set(accessDisconUser)
1752 return bits[:]
1753 }(),
1754 ),
1755 ),
1756 },
1757 wantRes: []Transaction{
1758 {
1759 Flags: 0x00,
1760 IsReply: 0x01,
1761 Type: []byte{0, 0},
1762 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1763 ErrorCode: []byte{0, 0, 0, 1},
1764 Fields: []Field{
1765 NewField(FieldError, []byte("Cannot create account with more access than yourself.")),
1766 },
1767 },
1768 },
1769 wantErr: assert.NoError,
1770 },
1771 }
1772 for _, tt := range tests {
1773 t.Run(tt.name, func(t *testing.T) {
1774 gotRes, err := HandleNewUser(tt.args.cc, tt.args.t)
1775 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewUser(%v, %v)", tt.args.cc, tt.args.t)) {
1776 return
1777 }
1778
1779 tranAssertEqual(t, tt.wantRes, gotRes)
1780 })
1781 }
1782 }
1783
1784 func TestHandleListUsers(t *testing.T) {
1785 type args struct {
1786 cc *ClientConn
1787 t *Transaction
1788 }
1789 tests := []struct {
1790 name string
1791 args args
1792 wantRes []Transaction
1793 wantErr assert.ErrorAssertionFunc
1794 }{
1795 {
1796 name: "when user does not have required permission",
1797 args: args{
1798 cc: &ClientConn{
1799 Account: &Account{
1800 Access: func() accessBitmap {
1801 var bits accessBitmap
1802 return bits
1803 }(),
1804 },
1805 Server: &Server{
1806 Accounts: map[string]*Account{},
1807 },
1808 },
1809 t: NewTransaction(
1810 TranNewUser, &[]byte{0, 1},
1811 ),
1812 },
1813 wantRes: []Transaction{
1814 {
1815 Flags: 0x00,
1816 IsReply: 0x01,
1817 Type: []byte{0, 0},
1818 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1819 ErrorCode: []byte{0, 0, 0, 1},
1820 Fields: []Field{
1821 NewField(FieldError, []byte("You are not allowed to view accounts.")),
1822 },
1823 },
1824 },
1825 wantErr: assert.NoError,
1826 },
1827 {
1828 name: "when user has required permission",
1829 args: args{
1830 cc: &ClientConn{
1831 Account: &Account{
1832 Access: func() accessBitmap {
1833 var bits accessBitmap
1834 bits.Set(accessOpenUser)
1835 return bits
1836 }(),
1837 },
1838 Server: &Server{
1839 Accounts: map[string]*Account{
1840 "guest": {
1841 Name: "guest",
1842 Login: "guest",
1843 Password: "zz",
1844 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
1845 },
1846 },
1847 },
1848 },
1849 t: NewTransaction(
1850 TranGetClientInfoText, &[]byte{0, 1},
1851 NewField(FieldUserID, []byte{0, 1}),
1852 ),
1853 },
1854 wantRes: []Transaction{
1855 {
1856 Flags: 0x00,
1857 IsReply: 0x01,
1858 Type: []byte{0, 0},
1859 ID: []byte{0, 0, 0, 0},
1860 ErrorCode: []byte{0, 0, 0, 0},
1861 Fields: []Field{
1862 NewField(FieldData, []byte{
1863 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1864 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1865 0x00, 0x6a, 0x00, 0x01, 0x78,
1866 }),
1867 },
1868 },
1869 },
1870 wantErr: assert.NoError,
1871 },
1872 }
1873 for _, tt := range tests {
1874 t.Run(tt.name, func(t *testing.T) {
1875 gotRes, err := HandleListUsers(tt.args.cc, tt.args.t)
1876 if !tt.wantErr(t, err, fmt.Sprintf("HandleListUsers(%v, %v)", tt.args.cc, tt.args.t)) {
1877 return
1878 }
1879
1880 tranAssertEqual(t, tt.wantRes, gotRes)
1881 })
1882 }
1883 }
1884
1885 func TestHandleDownloadFile(t *testing.T) {
1886 type args struct {
1887 cc *ClientConn
1888 t *Transaction
1889 }
1890 tests := []struct {
1891 name string
1892 args args
1893 wantRes []Transaction
1894 wantErr assert.ErrorAssertionFunc
1895 }{
1896 {
1897 name: "when user does not have required permission",
1898 args: args{
1899 cc: &ClientConn{
1900 Account: &Account{
1901 Access: func() accessBitmap {
1902 var bits accessBitmap
1903 return bits
1904 }(),
1905 },
1906 Server: &Server{},
1907 },
1908 t: NewTransaction(TranDownloadFile, &[]byte{0, 1}),
1909 },
1910 wantRes: []Transaction{
1911 {
1912 Flags: 0x00,
1913 IsReply: 0x01,
1914 Type: []byte{0, 0},
1915 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1916 ErrorCode: []byte{0, 0, 0, 1},
1917 Fields: []Field{
1918 NewField(FieldError, []byte("You are not allowed to download files.")),
1919 },
1920 },
1921 },
1922 wantErr: assert.NoError,
1923 },
1924 {
1925 name: "with a valid file",
1926 args: args{
1927 cc: &ClientConn{
1928 transfers: map[int]map[[4]byte]*FileTransfer{
1929 FileDownload: {},
1930 },
1931 Account: &Account{
1932 Access: func() accessBitmap {
1933 var bits accessBitmap
1934 bits.Set(accessDownloadFile)
1935 return bits
1936 }(),
1937 },
1938 Server: &Server{
1939 FS: &OSFileStore{},
1940 fileTransfers: map[[4]byte]*FileTransfer{},
1941 Config: &Config{
1942 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1943 },
1944 Accounts: map[string]*Account{},
1945 },
1946 },
1947 t: NewTransaction(
1948 accessDownloadFile,
1949 &[]byte{0, 1},
1950 NewField(FieldFileName, []byte("testfile.txt")),
1951 NewField(FieldFilePath, []byte{0x0, 0x00}),
1952 ),
1953 },
1954 wantRes: []Transaction{
1955 {
1956 Flags: 0x00,
1957 IsReply: 0x01,
1958 Type: []byte{0, 0},
1959 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1960 ErrorCode: []byte{0, 0, 0, 0},
1961 Fields: []Field{
1962 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1963 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
1964 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1965 NewField(FieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1966 },
1967 },
1968 },
1969 wantErr: assert.NoError,
1970 },
1971 {
1972 name: "when client requests to resume 1k test file at offset 256",
1973 args: args{
1974 cc: &ClientConn{
1975 transfers: map[int]map[[4]byte]*FileTransfer{
1976 FileDownload: {},
1977 }, Account: &Account{
1978 Access: func() accessBitmap {
1979 var bits accessBitmap
1980 bits.Set(accessDownloadFile)
1981 return bits
1982 }(),
1983 },
1984 Server: &Server{
1985 FS: &OSFileStore{},
1986
1987 // FS: func() *MockFileStore {
1988 // path, _ := os.Getwd()
1989 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1990 // if err != nil {
1991 // panic(err)
1992 // }
1993 //
1994 // mfi := &MockFileInfo{}
1995 // mfi.On("Mode").Return(fs.FileMode(0))
1996 // mfs := &MockFileStore{}
1997 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1998 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1999 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
2000 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
2001 //
2002 // return mfs
2003 // }(),
2004 fileTransfers: map[[4]byte]*FileTransfer{},
2005 Config: &Config{
2006 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
2007 },
2008 Accounts: map[string]*Account{},
2009 },
2010 },
2011 t: NewTransaction(
2012 accessDownloadFile,
2013 &[]byte{0, 1},
2014 NewField(FieldFileName, []byte("testfile-1k")),
2015 NewField(FieldFilePath, []byte{0x00, 0x00}),
2016 NewField(
2017 FieldFileResumeData,
2018 func() []byte {
2019 frd := FileResumeData{
2020 Format: [4]byte{},
2021 Version: [2]byte{},
2022 RSVD: [34]byte{},
2023 ForkCount: [2]byte{0, 2},
2024 ForkInfoList: []ForkInfoList{
2025 {
2026 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
2027 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
2028 RSVDA: [4]byte{},
2029 RSVDB: [4]byte{},
2030 },
2031 {
2032 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
2033 DataSize: [4]byte{0, 0, 0, 0},
2034 RSVDA: [4]byte{},
2035 RSVDB: [4]byte{},
2036 },
2037 },
2038 }
2039 b, _ := frd.BinaryMarshal()
2040 return b
2041 }(),
2042 ),
2043 ),
2044 },
2045 wantRes: []Transaction{
2046 {
2047 Flags: 0x00,
2048 IsReply: 0x01,
2049 Type: []byte{0, 0},
2050 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2051 ErrorCode: []byte{0, 0, 0, 0},
2052 Fields: []Field{
2053 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
2054 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
2055 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
2056 NewField(FieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
2057 },
2058 },
2059 },
2060 wantErr: assert.NoError,
2061 },
2062 }
2063 for _, tt := range tests {
2064 t.Run(tt.name, func(t *testing.T) {
2065 gotRes, err := HandleDownloadFile(tt.args.cc, tt.args.t)
2066 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadFile(%v, %v)", tt.args.cc, tt.args.t)) {
2067 return
2068 }
2069
2070 tranAssertEqual(t, tt.wantRes, gotRes)
2071 })
2072 }
2073 }
2074
2075 func TestHandleUpdateUser(t *testing.T) {
2076 type args struct {
2077 cc *ClientConn
2078 t *Transaction
2079 }
2080 tests := []struct {
2081 name string
2082 args args
2083 wantRes []Transaction
2084 wantErr assert.ErrorAssertionFunc
2085 }{
2086 {
2087 name: "when action is create user without required permission",
2088 args: args{
2089 cc: &ClientConn{
2090 logger: NewTestLogger(),
2091 Server: &Server{
2092 Logger: NewTestLogger(),
2093 },
2094 Account: &Account{
2095 Access: func() accessBitmap {
2096 var bits accessBitmap
2097 return bits
2098 }(),
2099 },
2100 },
2101 t: NewTransaction(
2102 TranUpdateUser,
2103 &[]byte{0, 0},
2104 NewField(FieldData, []byte{
2105 0x00, 0x04, // field count
2106
2107 0x00, 0x69, // FieldUserLogin = 105
2108 0x00, 0x03,
2109 0x9d, 0x9d, 0x9d,
2110
2111 0x00, 0x6a, // FieldUserPassword = 106
2112 0x00, 0x03,
2113 0x9c, 0x9c, 0x9c,
2114
2115 0x00, 0x66, // FieldUserName = 102
2116 0x00, 0x03,
2117 0x61, 0x61, 0x61,
2118
2119 0x00, 0x6e, // FieldUserAccess = 110
2120 0x00, 0x08,
2121 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2122 }),
2123 ),
2124 },
2125 wantRes: []Transaction{
2126 {
2127 Flags: 0x00,
2128 IsReply: 0x01,
2129 Type: []byte{0, 0},
2130 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2131 ErrorCode: []byte{0, 0, 0, 1},
2132 Fields: []Field{
2133 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
2134 },
2135 },
2136 },
2137 wantErr: assert.NoError,
2138 },
2139 {
2140 name: "when action is modify user without required permission",
2141 args: args{
2142 cc: &ClientConn{
2143 logger: NewTestLogger(),
2144 Server: &Server{
2145 Logger: NewTestLogger(),
2146 Accounts: map[string]*Account{
2147 "bbb": {},
2148 },
2149 },
2150 Account: &Account{
2151 Access: func() accessBitmap {
2152 var bits accessBitmap
2153 return bits
2154 }(),
2155 },
2156 },
2157 t: NewTransaction(
2158 TranUpdateUser,
2159 &[]byte{0, 0},
2160 NewField(FieldData, []byte{
2161 0x00, 0x04, // field count
2162
2163 0x00, 0x69, // FieldUserLogin = 105
2164 0x00, 0x03,
2165 0x9d, 0x9d, 0x9d,
2166
2167 0x00, 0x6a, // FieldUserPassword = 106
2168 0x00, 0x03,
2169 0x9c, 0x9c, 0x9c,
2170
2171 0x00, 0x66, // FieldUserName = 102
2172 0x00, 0x03,
2173 0x61, 0x61, 0x61,
2174
2175 0x00, 0x6e, // FieldUserAccess = 110
2176 0x00, 0x08,
2177 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2178 }),
2179 ),
2180 },
2181 wantRes: []Transaction{
2182 {
2183 Flags: 0x00,
2184 IsReply: 0x01,
2185 Type: []byte{0, 0},
2186 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2187 ErrorCode: []byte{0, 0, 0, 1},
2188 Fields: []Field{
2189 NewField(FieldError, []byte("You are not allowed to modify accounts.")),
2190 },
2191 },
2192 },
2193 wantErr: assert.NoError,
2194 },
2195 {
2196 name: "when action is delete user without required permission",
2197 args: args{
2198 cc: &ClientConn{
2199 logger: NewTestLogger(),
2200 Server: &Server{
2201 Accounts: map[string]*Account{
2202 "bbb": {},
2203 },
2204 },
2205 Account: &Account{
2206 Access: func() accessBitmap {
2207 var bits accessBitmap
2208 return bits
2209 }(),
2210 },
2211 },
2212 t: NewTransaction(
2213 TranUpdateUser,
2214 &[]byte{0, 0},
2215 NewField(FieldData, []byte{
2216 0x00, 0x01,
2217 0x00, 0x65,
2218 0x00, 0x03,
2219 0x88, 0x9e, 0x8b,
2220 }),
2221 ),
2222 },
2223 wantRes: []Transaction{
2224 {
2225 Flags: 0x00,
2226 IsReply: 0x01,
2227 Type: []byte{0, 0},
2228 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2229 ErrorCode: []byte{0, 0, 0, 1},
2230 Fields: []Field{
2231 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
2232 },
2233 },
2234 },
2235 wantErr: assert.NoError,
2236 },
2237 }
2238 for _, tt := range tests {
2239 t.Run(tt.name, func(t *testing.T) {
2240 gotRes, err := HandleUpdateUser(tt.args.cc, tt.args.t)
2241 if !tt.wantErr(t, err, fmt.Sprintf("HandleUpdateUser(%v, %v)", tt.args.cc, tt.args.t)) {
2242 return
2243 }
2244
2245 tranAssertEqual(t, tt.wantRes, gotRes)
2246 })
2247 }
2248 }
2249
2250 func TestHandleDelNewsArt(t *testing.T) {
2251 type args struct {
2252 cc *ClientConn
2253 t *Transaction
2254 }
2255 tests := []struct {
2256 name string
2257 args args
2258 wantRes []Transaction
2259 wantErr assert.ErrorAssertionFunc
2260 }{
2261 {
2262 name: "without required permission",
2263 args: args{
2264 cc: &ClientConn{
2265 Account: &Account{
2266 Access: func() accessBitmap {
2267 var bits accessBitmap
2268 return bits
2269 }(),
2270 },
2271 },
2272 t: NewTransaction(
2273 TranDelNewsArt,
2274 &[]byte{0, 0},
2275 ),
2276 },
2277 wantRes: []Transaction{
2278 {
2279 Flags: 0x00,
2280 IsReply: 0x01,
2281 Type: []byte{0, 0},
2282 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2283 ErrorCode: []byte{0, 0, 0, 1},
2284 Fields: []Field{
2285 NewField(FieldError, []byte("You are not allowed to delete news articles.")),
2286 },
2287 },
2288 },
2289 wantErr: assert.NoError,
2290 },
2291 }
2292 for _, tt := range tests {
2293 t.Run(tt.name, func(t *testing.T) {
2294 gotRes, err := HandleDelNewsArt(tt.args.cc, tt.args.t)
2295 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsArt(%v, %v)", tt.args.cc, tt.args.t)) {
2296 return
2297 }
2298 tranAssertEqual(t, tt.wantRes, gotRes)
2299 })
2300 }
2301 }
2302
2303 func TestHandleDisconnectUser(t *testing.T) {
2304 type args struct {
2305 cc *ClientConn
2306 t *Transaction
2307 }
2308 tests := []struct {
2309 name string
2310 args args
2311 wantRes []Transaction
2312 wantErr assert.ErrorAssertionFunc
2313 }{
2314 {
2315 name: "without required permission",
2316 args: args{
2317 cc: &ClientConn{
2318 Account: &Account{
2319 Access: func() accessBitmap {
2320 var bits accessBitmap
2321 return bits
2322 }(),
2323 },
2324 },
2325 t: NewTransaction(
2326 TranDelNewsArt,
2327 &[]byte{0, 0},
2328 ),
2329 },
2330 wantRes: []Transaction{
2331 {
2332 Flags: 0x00,
2333 IsReply: 0x01,
2334 Type: []byte{0, 0},
2335 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2336 ErrorCode: []byte{0, 0, 0, 1},
2337 Fields: []Field{
2338 NewField(FieldError, []byte("You are not allowed to disconnect users.")),
2339 },
2340 },
2341 },
2342 wantErr: assert.NoError,
2343 },
2344 {
2345 name: "when target user has 'cannot be disconnected' priv",
2346 args: args{
2347 cc: &ClientConn{
2348 Server: &Server{
2349 Clients: map[uint16]*ClientConn{
2350 uint16(1): {
2351 Account: &Account{
2352 Login: "unnamed",
2353 Access: func() accessBitmap {
2354 var bits accessBitmap
2355 bits.Set(accessCannotBeDiscon)
2356 return bits
2357 }(),
2358 },
2359 },
2360 },
2361 },
2362 Account: &Account{
2363 Access: func() accessBitmap {
2364 var bits accessBitmap
2365 bits.Set(accessDisconUser)
2366 return bits
2367 }(),
2368 },
2369 },
2370 t: NewTransaction(
2371 TranDelNewsArt,
2372 &[]byte{0, 0},
2373 NewField(FieldUserID, []byte{0, 1}),
2374 ),
2375 },
2376 wantRes: []Transaction{
2377 {
2378 Flags: 0x00,
2379 IsReply: 0x01,
2380 Type: []byte{0, 0},
2381 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2382 ErrorCode: []byte{0, 0, 0, 1},
2383 Fields: []Field{
2384 NewField(FieldError, []byte("unnamed is not allowed to be disconnected.")),
2385 },
2386 },
2387 },
2388 wantErr: assert.NoError,
2389 },
2390 }
2391 for _, tt := range tests {
2392 t.Run(tt.name, func(t *testing.T) {
2393 gotRes, err := HandleDisconnectUser(tt.args.cc, tt.args.t)
2394 if !tt.wantErr(t, err, fmt.Sprintf("HandleDisconnectUser(%v, %v)", tt.args.cc, tt.args.t)) {
2395 return
2396 }
2397 tranAssertEqual(t, tt.wantRes, gotRes)
2398 })
2399 }
2400 }
2401
2402 func TestHandleSendInstantMsg(t *testing.T) {
2403 type args struct {
2404 cc *ClientConn
2405 t *Transaction
2406 }
2407 tests := []struct {
2408 name string
2409 args args
2410 wantRes []Transaction
2411 wantErr assert.ErrorAssertionFunc
2412 }{
2413 {
2414 name: "without required permission",
2415 args: args{
2416 cc: &ClientConn{
2417 Account: &Account{
2418 Access: func() accessBitmap {
2419 var bits accessBitmap
2420 return bits
2421 }(),
2422 },
2423 },
2424 t: NewTransaction(
2425 TranDelNewsArt,
2426 &[]byte{0, 0},
2427 ),
2428 },
2429 wantRes: []Transaction{
2430 {
2431 Flags: 0x00,
2432 IsReply: 0x01,
2433 Type: []byte{0, 0},
2434 ID: []byte{0, 0, 0, 0},
2435 ErrorCode: []byte{0, 0, 0, 1},
2436 Fields: []Field{
2437 NewField(FieldError, []byte("You are not allowed to send private messages.")),
2438 },
2439 },
2440 },
2441 wantErr: assert.Error,
2442 },
2443 {
2444 name: "when client 1 sends a message to client 2",
2445 args: args{
2446 cc: &ClientConn{
2447 Account: &Account{
2448 Access: func() accessBitmap {
2449 var bits accessBitmap
2450 bits.Set(accessSendPrivMsg)
2451 return bits
2452 }(),
2453 },
2454 ID: &[]byte{0, 1},
2455 UserName: []byte("User1"),
2456 Server: &Server{
2457 Clients: map[uint16]*ClientConn{
2458 uint16(2): {
2459 AutoReply: []byte(nil),
2460 Flags: []byte{0, 0},
2461 },
2462 },
2463 },
2464 },
2465 t: NewTransaction(
2466 TranSendInstantMsg,
2467 &[]byte{0, 1},
2468 NewField(FieldData, []byte("hai")),
2469 NewField(FieldUserID, []byte{0, 2}),
2470 ),
2471 },
2472 wantRes: []Transaction{
2473 *NewTransaction(
2474 TranServerMsg,
2475 &[]byte{0, 2},
2476 NewField(FieldData, []byte("hai")),
2477 NewField(FieldUserName, []byte("User1")),
2478 NewField(FieldUserID, []byte{0, 1}),
2479 NewField(FieldOptions, []byte{0, 1}),
2480 ),
2481 {
2482 clientID: &[]byte{0, 1},
2483 Flags: 0x00,
2484 IsReply: 0x01,
2485 Type: []byte{0, 0},
2486 ID: []byte{0, 0, 0, 0},
2487 ErrorCode: []byte{0, 0, 0, 0},
2488 Fields: []Field(nil),
2489 },
2490 },
2491 wantErr: assert.NoError,
2492 },
2493 {
2494 name: "when client 2 has autoreply enabled",
2495 args: args{
2496 cc: &ClientConn{
2497 Account: &Account{
2498 Access: func() accessBitmap {
2499 var bits accessBitmap
2500 bits.Set(accessSendPrivMsg)
2501 return bits
2502 }(),
2503 },
2504 ID: &[]byte{0, 1},
2505 UserName: []byte("User1"),
2506 Server: &Server{
2507 Clients: map[uint16]*ClientConn{
2508 uint16(2): {
2509 Flags: []byte{0, 0},
2510 ID: &[]byte{0, 2},
2511 UserName: []byte("User2"),
2512 AutoReply: []byte("autohai"),
2513 },
2514 },
2515 },
2516 },
2517 t: NewTransaction(
2518 TranSendInstantMsg,
2519 &[]byte{0, 1},
2520 NewField(FieldData, []byte("hai")),
2521 NewField(FieldUserID, []byte{0, 2}),
2522 ),
2523 },
2524 wantRes: []Transaction{
2525 *NewTransaction(
2526 TranServerMsg,
2527 &[]byte{0, 2},
2528 NewField(FieldData, []byte("hai")),
2529 NewField(FieldUserName, []byte("User1")),
2530 NewField(FieldUserID, []byte{0, 1}),
2531 NewField(FieldOptions, []byte{0, 1}),
2532 ),
2533 *NewTransaction(
2534 TranServerMsg,
2535 &[]byte{0, 1},
2536 NewField(FieldData, []byte("autohai")),
2537 NewField(FieldUserName, []byte("User2")),
2538 NewField(FieldUserID, []byte{0, 2}),
2539 NewField(FieldOptions, []byte{0, 1}),
2540 ),
2541 {
2542 clientID: &[]byte{0, 1},
2543 Flags: 0x00,
2544 IsReply: 0x01,
2545 Type: []byte{0, 0},
2546 ID: []byte{0, 0, 0, 0},
2547 ErrorCode: []byte{0, 0, 0, 0},
2548 Fields: []Field(nil),
2549 },
2550 },
2551 wantErr: assert.NoError,
2552 },
2553 {
2554 name: "when client 2 has refuse private messages enabled",
2555 args: args{
2556 cc: &ClientConn{
2557 Account: &Account{
2558 Access: func() accessBitmap {
2559 var bits accessBitmap
2560 bits.Set(accessSendPrivMsg)
2561 return bits
2562 }(),
2563 },
2564 ID: &[]byte{0, 1},
2565 UserName: []byte("User1"),
2566 Server: &Server{
2567 Clients: map[uint16]*ClientConn{
2568 uint16(2): {
2569 Flags: []byte{255, 255},
2570 ID: &[]byte{0, 2},
2571 UserName: []byte("User2"),
2572 },
2573 },
2574 },
2575 },
2576 t: NewTransaction(
2577 TranSendInstantMsg,
2578 &[]byte{0, 1},
2579 NewField(FieldData, []byte("hai")),
2580 NewField(FieldUserID, []byte{0, 2}),
2581 ),
2582 },
2583 wantRes: []Transaction{
2584 *NewTransaction(
2585 TranServerMsg,
2586 &[]byte{0, 1},
2587 NewField(FieldData, []byte("User2 does not accept private messages.")),
2588 NewField(FieldUserName, []byte("User2")),
2589 NewField(FieldUserID, []byte{0, 2}),
2590 NewField(FieldOptions, []byte{0, 2}),
2591 ),
2592 {
2593 clientID: &[]byte{0, 1},
2594 Flags: 0x00,
2595 IsReply: 0x01,
2596 Type: []byte{0, 0},
2597 ID: []byte{0, 0, 0, 0},
2598 ErrorCode: []byte{0, 0, 0, 0},
2599 Fields: []Field(nil),
2600 },
2601 },
2602 wantErr: assert.NoError,
2603 },
2604 }
2605 for _, tt := range tests {
2606 t.Run(tt.name, func(t *testing.T) {
2607 gotRes, err := HandleSendInstantMsg(tt.args.cc, tt.args.t)
2608 if !tt.wantErr(t, err, fmt.Sprintf("HandleSendInstantMsg(%v, %v)", tt.args.cc, tt.args.t)) {
2609 return
2610 }
2611
2612 tranAssertEqual(t, tt.wantRes, gotRes)
2613 })
2614 }
2615 }
2616
2617 func TestHandleDeleteFile(t *testing.T) {
2618 type args struct {
2619 cc *ClientConn
2620 t *Transaction
2621 }
2622 tests := []struct {
2623 name string
2624 args args
2625 wantRes []Transaction
2626 wantErr assert.ErrorAssertionFunc
2627 }{
2628 {
2629 name: "when user does not have required permission to delete a folder",
2630 args: args{
2631 cc: &ClientConn{
2632 Account: &Account{
2633 Access: func() accessBitmap {
2634 var bits accessBitmap
2635 return bits
2636 }(),
2637 },
2638 Server: &Server{
2639 Config: &Config{
2640 FileRoot: func() string {
2641 return "/fakeRoot/Files"
2642 }(),
2643 },
2644 FS: func() *MockFileStore {
2645 mfi := &MockFileInfo{}
2646 mfi.On("Mode").Return(fs.FileMode(0))
2647 mfi.On("Size").Return(int64(100))
2648 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2649 mfi.On("IsDir").Return(false)
2650 mfi.On("Name").Return("testfile")
2651
2652 mfs := &MockFileStore{}
2653 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2654 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2655 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2656
2657 return mfs
2658 }(),
2659 Accounts: map[string]*Account{},
2660 },
2661 },
2662 t: NewTransaction(
2663 TranDeleteFile, &[]byte{0, 1},
2664 NewField(FieldFileName, []byte("testfile")),
2665 NewField(FieldFilePath, []byte{
2666 0x00, 0x01,
2667 0x00, 0x00,
2668 0x03,
2669 0x61, 0x61, 0x61,
2670 }),
2671 ),
2672 },
2673 wantRes: []Transaction{
2674 {
2675 Flags: 0x00,
2676 IsReply: 0x01,
2677 Type: []byte{0, 0},
2678 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2679 ErrorCode: []byte{0, 0, 0, 1},
2680 Fields: []Field{
2681 NewField(FieldError, []byte("You are not allowed to delete files.")),
2682 },
2683 },
2684 },
2685 wantErr: assert.NoError,
2686 },
2687 {
2688 name: "deletes all associated metadata files",
2689 args: args{
2690 cc: &ClientConn{
2691 Account: &Account{
2692 Access: func() accessBitmap {
2693 var bits accessBitmap
2694 bits.Set(accessDeleteFile)
2695 return bits
2696 }(),
2697 },
2698 Server: &Server{
2699 Config: &Config{
2700 FileRoot: func() string {
2701 return "/fakeRoot/Files"
2702 }(),
2703 },
2704 FS: func() *MockFileStore {
2705 mfi := &MockFileInfo{}
2706 mfi.On("Mode").Return(fs.FileMode(0))
2707 mfi.On("Size").Return(int64(100))
2708 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2709 mfi.On("IsDir").Return(false)
2710 mfi.On("Name").Return("testfile")
2711
2712 mfs := &MockFileStore{}
2713 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2714 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2715 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2716
2717 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2718 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2719 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2720 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2721
2722 return mfs
2723 }(),
2724 Accounts: map[string]*Account{},
2725 },
2726 },
2727 t: NewTransaction(
2728 TranDeleteFile, &[]byte{0, 1},
2729 NewField(FieldFileName, []byte("testfile")),
2730 NewField(FieldFilePath, []byte{
2731 0x00, 0x01,
2732 0x00, 0x00,
2733 0x03,
2734 0x61, 0x61, 0x61,
2735 }),
2736 ),
2737 },
2738 wantRes: []Transaction{
2739 {
2740 Flags: 0x00,
2741 IsReply: 0x01,
2742 Type: []byte{0, 0},
2743 ID: []byte{0x0, 0x0, 0x0, 0x0},
2744 ErrorCode: []byte{0, 0, 0, 0},
2745 Fields: []Field(nil),
2746 },
2747 },
2748 wantErr: assert.NoError,
2749 },
2750 }
2751 for _, tt := range tests {
2752 t.Run(tt.name, func(t *testing.T) {
2753 gotRes, err := HandleDeleteFile(tt.args.cc, tt.args.t)
2754 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteFile(%v, %v)", tt.args.cc, tt.args.t)) {
2755 return
2756 }
2757
2758 tranAssertEqual(t, tt.wantRes, gotRes)
2759
2760 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2761 })
2762 }
2763 }
2764
2765 func TestHandleGetFileNameList(t *testing.T) {
2766 type args struct {
2767 cc *ClientConn
2768 t *Transaction
2769 }
2770 tests := []struct {
2771 name string
2772 args args
2773 wantRes []Transaction
2774 wantErr assert.ErrorAssertionFunc
2775 }{
2776 {
2777 name: "when FieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2778 args: args{
2779 cc: &ClientConn{
2780 Account: &Account{
2781 Access: func() accessBitmap {
2782 var bits accessBitmap
2783 return bits
2784 }(),
2785 },
2786 Server: &Server{
2787
2788 Config: &Config{
2789 FileRoot: func() string {
2790 path, _ := os.Getwd()
2791 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2792 }(),
2793 },
2794 },
2795 },
2796 t: NewTransaction(
2797 TranGetFileNameList, &[]byte{0, 1},
2798 NewField(FieldFilePath, []byte{
2799 0x00, 0x01,
2800 0x00, 0x00,
2801 0x08,
2802 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2803 }),
2804 ),
2805 },
2806 wantRes: []Transaction{
2807 {
2808 Flags: 0x00,
2809 IsReply: 0x01,
2810 Type: []byte{0, 0},
2811 ID: []byte{0, 0, 0, 0},
2812 ErrorCode: []byte{0, 0, 0, 1},
2813 Fields: []Field{
2814 NewField(FieldError, []byte("You are not allowed to view drop boxes.")),
2815 },
2816 },
2817 },
2818 wantErr: assert.NoError,
2819 },
2820 {
2821 name: "with file root",
2822 args: args{
2823 cc: &ClientConn{
2824 Server: &Server{
2825 Config: &Config{
2826 FileRoot: func() string {
2827 path, _ := os.Getwd()
2828 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2829 }(),
2830 },
2831 },
2832 },
2833 t: NewTransaction(
2834 TranGetFileNameList, &[]byte{0, 1},
2835 NewField(FieldFilePath, []byte{
2836 0x00, 0x00,
2837 0x00, 0x00,
2838 }),
2839 ),
2840 },
2841 wantRes: []Transaction{
2842 {
2843 Flags: 0x00,
2844 IsReply: 0x01,
2845 Type: []byte{0, 0},
2846 ID: []byte{0, 0, 0, 0},
2847 ErrorCode: []byte{0, 0, 0, 0},
2848 Fields: []Field{
2849 NewField(
2850 FieldFileNameWithInfo,
2851 func() []byte {
2852 fnwi := FileNameWithInfo{
2853 fileNameWithInfoHeader: fileNameWithInfoHeader{
2854 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2855 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2856 FileSize: [4]byte{0, 0, 0x04, 0},
2857 RSVD: [4]byte{},
2858 NameScript: [2]byte{},
2859 NameSize: [2]byte{0, 0x0b},
2860 },
2861 name: []byte("testfile-1k"),
2862 }
2863 b, _ := fnwi.MarshalBinary()
2864 return b
2865 }(),
2866 ),
2867 },
2868 },
2869 },
2870 wantErr: assert.NoError,
2871 },
2872 }
2873 for _, tt := range tests {
2874 t.Run(tt.name, func(t *testing.T) {
2875 gotRes, err := HandleGetFileNameList(tt.args.cc, tt.args.t)
2876 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetFileNameList(%v, %v)", tt.args.cc, tt.args.t)) {
2877 return
2878 }
2879
2880 tranAssertEqual(t, tt.wantRes, gotRes)
2881 })
2882 }
2883 }
2884
2885 func TestHandleGetClientInfoText(t *testing.T) {
2886 type args struct {
2887 cc *ClientConn
2888 t *Transaction
2889 }
2890 tests := []struct {
2891 name string
2892 args args
2893 wantRes []Transaction
2894 wantErr assert.ErrorAssertionFunc
2895 }{
2896 {
2897 name: "when user does not have required permission",
2898 args: args{
2899 cc: &ClientConn{
2900 Account: &Account{
2901 Access: func() accessBitmap {
2902 var bits accessBitmap
2903 return bits
2904 }(),
2905 },
2906 Server: &Server{
2907 Accounts: map[string]*Account{},
2908 },
2909 },
2910 t: NewTransaction(
2911 TranGetClientInfoText, &[]byte{0, 1},
2912 NewField(FieldUserID, []byte{0, 1}),
2913 ),
2914 },
2915 wantRes: []Transaction{
2916 {
2917 Flags: 0x00,
2918 IsReply: 0x01,
2919 Type: []byte{0, 0},
2920 ID: []byte{0, 0, 0, 0},
2921 ErrorCode: []byte{0, 0, 0, 1},
2922 Fields: []Field{
2923 NewField(FieldError, []byte("You are not allowed to get client info.")),
2924 },
2925 },
2926 },
2927 wantErr: assert.NoError,
2928 },
2929 {
2930 name: "with a valid user",
2931 args: args{
2932 cc: &ClientConn{
2933 UserName: []byte("Testy McTest"),
2934 RemoteAddr: "1.2.3.4:12345",
2935 Account: &Account{
2936 Access: func() accessBitmap {
2937 var bits accessBitmap
2938 bits.Set(accessGetClientInfo)
2939 return bits
2940 }(),
2941 Name: "test",
2942 Login: "test",
2943 },
2944 Server: &Server{
2945 Accounts: map[string]*Account{},
2946 Clients: map[uint16]*ClientConn{
2947 uint16(1): {
2948 UserName: []byte("Testy McTest"),
2949 RemoteAddr: "1.2.3.4:12345",
2950 Account: &Account{
2951 Access: func() accessBitmap {
2952 var bits accessBitmap
2953 bits.Set(accessGetClientInfo)
2954 return bits
2955 }(),
2956 Name: "test",
2957 Login: "test",
2958 },
2959 },
2960 },
2961 },
2962 transfers: map[int]map[[4]byte]*FileTransfer{
2963 FileDownload: {},
2964 FileUpload: {},
2965 FolderDownload: {},
2966 FolderUpload: {},
2967 },
2968 },
2969 t: NewTransaction(
2970 TranGetClientInfoText, &[]byte{0, 1},
2971 NewField(FieldUserID, []byte{0, 1}),
2972 ),
2973 },
2974 wantRes: []Transaction{
2975 {
2976 Flags: 0x00,
2977 IsReply: 0x01,
2978 Type: []byte{0, 0},
2979 ID: []byte{0, 0, 0, 0},
2980 ErrorCode: []byte{0, 0, 0, 0},
2981 Fields: []Field{
2982 NewField(FieldData, []byte(
2983 strings.ReplaceAll(`Nickname: Testy McTest
2984 Name: test
2985 Account: test
2986 Address: 1.2.3.4:12345
2987
2988 -------- File Downloads ---------
2989
2990 None.
2991
2992 ------- Folder Downloads --------
2993
2994 None.
2995
2996 --------- File Uploads ----------
2997
2998 None.
2999
3000 -------- Folder Uploads ---------
3001
3002 None.
3003
3004 ------- Waiting Downloads -------
3005
3006 None.
3007
3008 `, "\n", "\r")),
3009 ),
3010 NewField(FieldUserName, []byte("Testy McTest")),
3011 },
3012 },
3013 },
3014 wantErr: assert.NoError,
3015 },
3016 }
3017 for _, tt := range tests {
3018 t.Run(tt.name, func(t *testing.T) {
3019 gotRes, err := HandleGetClientInfoText(tt.args.cc, tt.args.t)
3020 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetClientInfoText(%v, %v)", tt.args.cc, tt.args.t)) {
3021 return
3022 }
3023 tranAssertEqual(t, tt.wantRes, gotRes)
3024 })
3025 }
3026 }
3027
3028 func TestHandleTranAgreed(t *testing.T) {
3029 type args struct {
3030 cc *ClientConn
3031 t *Transaction
3032 }
3033 tests := []struct {
3034 name string
3035 args args
3036 wantRes []Transaction
3037 wantErr assert.ErrorAssertionFunc
3038 }{
3039 {
3040 name: "normal request flow",
3041 args: args{
3042 cc: &ClientConn{
3043 Account: &Account{
3044 Access: func() accessBitmap {
3045 var bits accessBitmap
3046 bits.Set(accessDisconUser)
3047 bits.Set(accessAnyName)
3048 return bits
3049 }()},
3050 Icon: []byte{0, 1},
3051 Flags: []byte{0, 1},
3052 Version: []byte{0, 1},
3053 ID: &[]byte{0, 1},
3054 logger: NewTestLogger(),
3055 Server: &Server{
3056 Config: &Config{
3057 BannerFile: "banner.jpg",
3058 },
3059 },
3060 },
3061 t: NewTransaction(
3062 TranAgreed, nil,
3063 NewField(FieldUserName, []byte("username")),
3064 NewField(FieldUserIconID, []byte{0, 1}),
3065 NewField(FieldOptions, []byte{0, 0}),
3066 ),
3067 },
3068 wantRes: []Transaction{
3069 {
3070 clientID: &[]byte{0, 1},
3071 Flags: 0x00,
3072 IsReply: 0x00,
3073 Type: []byte{0, 0x7a},
3074 ID: []byte{0, 0, 0, 0},
3075 ErrorCode: []byte{0, 0, 0, 0},
3076 Fields: []Field{
3077 NewField(FieldBannerType, []byte("JPEG")),
3078 },
3079 },
3080 {
3081 clientID: &[]byte{0, 1},
3082 Flags: 0x00,
3083 IsReply: 0x01,
3084 Type: []byte{0, 0},
3085 ID: []byte{0, 0, 0, 0},
3086 ErrorCode: []byte{0, 0, 0, 0},
3087 Fields: []Field{},
3088 },
3089 },
3090 wantErr: assert.NoError,
3091 },
3092 }
3093 for _, tt := range tests {
3094 t.Run(tt.name, func(t *testing.T) {
3095 gotRes, err := HandleTranAgreed(tt.args.cc, tt.args.t)
3096 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranAgreed(%v, %v)", tt.args.cc, tt.args.t)) {
3097 return
3098 }
3099 tranAssertEqual(t, tt.wantRes, gotRes)
3100 })
3101 }
3102 }
3103
3104 func TestHandleSetClientUserInfo(t *testing.T) {
3105 type args struct {
3106 cc *ClientConn
3107 t *Transaction
3108 }
3109 tests := []struct {
3110 name string
3111 args args
3112 wantRes []Transaction
3113 wantErr assert.ErrorAssertionFunc
3114 }{
3115 {
3116 name: "when client does not have accessAnyName",
3117 args: args{
3118 cc: &ClientConn{
3119 Account: &Account{
3120 Access: func() accessBitmap {
3121 var bits accessBitmap
3122 return bits
3123 }(),
3124 },
3125 ID: &[]byte{0, 1},
3126 UserName: []byte("Guest"),
3127 Flags: []byte{0, 1},
3128 Server: &Server{
3129 Clients: map[uint16]*ClientConn{
3130 uint16(1): {
3131 ID: &[]byte{0, 1},
3132 },
3133 },
3134 },
3135 },
3136 t: NewTransaction(
3137 TranSetClientUserInfo, nil,
3138 NewField(FieldUserIconID, []byte{0, 1}),
3139 NewField(FieldUserName, []byte("NOPE")),
3140 ),
3141 },
3142 wantRes: []Transaction{
3143 {
3144 clientID: &[]byte{0, 1},
3145 Flags: 0x00,
3146 IsReply: 0x00,
3147 Type: []byte{0x01, 0x2d},
3148 ID: []byte{0, 0, 0, 0},
3149 ErrorCode: []byte{0, 0, 0, 0},
3150 Fields: []Field{
3151 NewField(FieldUserID, []byte{0, 1}),
3152 NewField(FieldUserIconID, []byte{0, 1}),
3153 NewField(FieldUserFlags, []byte{0, 1}),
3154 NewField(FieldUserName, []byte("Guest"))},
3155 },
3156 },
3157 wantErr: assert.NoError,
3158 },
3159 }
3160 for _, tt := range tests {
3161 t.Run(tt.name, func(t *testing.T) {
3162 gotRes, err := HandleSetClientUserInfo(tt.args.cc, tt.args.t)
3163 if !tt.wantErr(t, err, fmt.Sprintf("HandleSetClientUserInfo(%v, %v)", tt.args.cc, tt.args.t)) {
3164 return
3165 }
3166
3167 tranAssertEqual(t, tt.wantRes, gotRes)
3168 })
3169 }
3170 }
3171
3172 func TestHandleDelNewsItem(t *testing.T) {
3173 type args struct {
3174 cc *ClientConn
3175 t *Transaction
3176 }
3177 tests := []struct {
3178 name string
3179 args args
3180 wantRes []Transaction
3181 wantErr assert.ErrorAssertionFunc
3182 }{
3183 {
3184 name: "when user does not have permission to delete a news category",
3185 args: args{
3186 cc: &ClientConn{
3187 Account: &Account{
3188 Access: accessBitmap{},
3189 },
3190 ID: &[]byte{0, 1},
3191 Server: &Server{
3192 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3193 "test": {
3194 Type: []byte{0, 3},
3195 Count: nil,
3196 NameSize: 0,
3197 Name: "zz",
3198 },
3199 }},
3200 },
3201 },
3202 t: NewTransaction(
3203 TranDelNewsItem, nil,
3204 NewField(FieldNewsPath,
3205 []byte{
3206 0, 1,
3207 0, 0,
3208 4,
3209 0x74, 0x65, 0x73, 0x74,
3210 },
3211 ),
3212 ),
3213 },
3214 wantRes: []Transaction{
3215 {
3216 clientID: &[]byte{0, 1},
3217 Flags: 0x00,
3218 IsReply: 0x01,
3219 Type: []byte{0, 0},
3220 ID: []byte{0, 0, 0, 0},
3221 ErrorCode: []byte{0, 0, 0, 1},
3222 Fields: []Field{
3223 NewField(FieldError, []byte("You are not allowed to delete news categories.")),
3224 },
3225 },
3226 },
3227 wantErr: assert.NoError,
3228 },
3229 {
3230 name: "when user does not have permission to delete a news folder",
3231 args: args{
3232 cc: &ClientConn{
3233 Account: &Account{
3234 Access: accessBitmap{},
3235 },
3236 ID: &[]byte{0, 1},
3237 Server: &Server{
3238 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3239 "testcat": {
3240 Type: []byte{0, 2},
3241 Count: nil,
3242 NameSize: 0,
3243 Name: "test",
3244 },
3245 }},
3246 },
3247 },
3248 t: NewTransaction(
3249 TranDelNewsItem, nil,
3250 NewField(FieldNewsPath,
3251 []byte{
3252 0, 1,
3253 0, 0,
3254 4,
3255 0x74, 0x65, 0x73, 0x74,
3256 },
3257 ),
3258 ),
3259 },
3260 wantRes: []Transaction{
3261 {
3262 clientID: &[]byte{0, 1},
3263 Flags: 0x00,
3264 IsReply: 0x01,
3265 Type: []byte{0, 0},
3266 ID: []byte{0, 0, 0, 0},
3267 ErrorCode: []byte{0, 0, 0, 1},
3268 Fields: []Field{
3269 NewField(FieldError, []byte("You are not allowed to delete news folders.")),
3270 },
3271 },
3272 },
3273 wantErr: assert.NoError,
3274 },
3275 {
3276 name: "when user deletes a news folder",
3277 args: args{
3278 cc: &ClientConn{
3279 Account: &Account{
3280 Access: func() accessBitmap {
3281 var bits accessBitmap
3282 bits.Set(accessNewsDeleteFldr)
3283 return bits
3284 }(),
3285 },
3286 ID: &[]byte{0, 1},
3287 Server: &Server{
3288 ConfigDir: "/fakeConfigRoot",
3289 FS: func() *MockFileStore {
3290 mfs := &MockFileStore{}
3291 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3292 return mfs
3293 }(),
3294 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3295 "testcat": {
3296 Type: []byte{0, 2},
3297 Count: nil,
3298 NameSize: 0,
3299 Name: "test",
3300 },
3301 }},
3302 },
3303 },
3304 t: NewTransaction(
3305 TranDelNewsItem, nil,
3306 NewField(FieldNewsPath,
3307 []byte{
3308 0, 1,
3309 0, 0,
3310 4,
3311 0x74, 0x65, 0x73, 0x74,
3312 },
3313 ),
3314 ),
3315 },
3316 wantRes: []Transaction{
3317 {
3318 clientID: &[]byte{0, 1},
3319 Flags: 0x00,
3320 IsReply: 0x01,
3321 Type: []byte{0, 0},
3322 ID: []byte{0, 0, 0, 0},
3323 ErrorCode: []byte{0, 0, 0, 0},
3324 Fields: []Field{},
3325 },
3326 },
3327 wantErr: assert.NoError,
3328 },
3329 }
3330 for _, tt := range tests {
3331 t.Run(tt.name, func(t *testing.T) {
3332 gotRes, err := HandleDelNewsItem(tt.args.cc, tt.args.t)
3333 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsItem(%v, %v)", tt.args.cc, tt.args.t)) {
3334 return
3335 }
3336 tranAssertEqual(t, tt.wantRes, gotRes)
3337 })
3338 }
3339 }
3340
3341 func TestHandleDownloadBanner(t *testing.T) {
3342 type args struct {
3343 cc *ClientConn
3344 t *Transaction
3345 }
3346 tests := []struct {
3347 name string
3348 args args
3349 wantRes []Transaction
3350 wantErr assert.ErrorAssertionFunc
3351 }{
3352 {
3353 name: "returns expected response",
3354 args: args{
3355 cc: &ClientConn{
3356 ID: &[]byte{0, 1},
3357 transfers: map[int]map[[4]byte]*FileTransfer{
3358 bannerDownload: {},
3359 },
3360 Server: &Server{
3361 ConfigDir: "/config",
3362 Config: &Config{
3363 BannerFile: "banner.jpg",
3364 },
3365 fileTransfers: map[[4]byte]*FileTransfer{},
3366 FS: func() *MockFileStore {
3367 mfi := &MockFileInfo{}
3368 mfi.On("Size").Return(int64(100))
3369
3370 mfs := &MockFileStore{}
3371 mfs.On("Stat", "/config/banner.jpg").Return(mfi, nil)
3372 return mfs
3373 }(),
3374 },
3375 },
3376 t: NewTransaction(TranDownloadBanner, nil),
3377 },
3378 wantRes: []Transaction{
3379 {
3380 clientID: &[]byte{0, 1},
3381 Flags: 0x00,
3382 IsReply: 0x01,
3383 Type: []byte{0, 0},
3384 ID: []byte{0, 0, 0, 0},
3385 ErrorCode: []byte{0, 0, 0, 0},
3386 Fields: []Field{
3387 NewField(FieldRefNum, []byte{1, 2, 3, 4}),
3388 NewField(FieldTransferSize, []byte{0, 0, 0, 0x64}),
3389 },
3390 },
3391 },
3392 wantErr: assert.NoError,
3393 },
3394 }
3395 for _, tt := range tests {
3396 t.Run(tt.name, func(t *testing.T) {
3397 gotRes, err := HandleDownloadBanner(tt.args.cc, tt.args.t)
3398 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadBanner(%v, %v)", tt.args.cc, tt.args.t)) {
3399 return
3400 }
3401
3402 tranAssertEqual(t, tt.wantRes, gotRes)
3403 })
3404 }
3405 }
3406
3407 func TestHandleTranOldPostNews(t *testing.T) {
3408 type args struct {
3409 cc *ClientConn
3410 t *Transaction
3411 }
3412 tests := []struct {
3413 name string
3414 args args
3415 wantRes []Transaction
3416 wantErr assert.ErrorAssertionFunc
3417 }{
3418 {
3419 name: "when user does not have required permission",
3420 args: args{
3421 cc: &ClientConn{
3422 Account: &Account{
3423 Access: func() accessBitmap {
3424 var bits accessBitmap
3425 return bits
3426 }(),
3427 },
3428 },
3429 t: NewTransaction(
3430 TranOldPostNews, &[]byte{0, 1},
3431 NewField(FieldData, []byte("hai")),
3432 ),
3433 },
3434 wantRes: []Transaction{
3435 {
3436 Flags: 0x00,
3437 IsReply: 0x01,
3438 Type: []byte{0, 0},
3439 ID: []byte{0, 0, 0, 0},
3440 ErrorCode: []byte{0, 0, 0, 1},
3441 Fields: []Field{
3442 NewField(FieldError, []byte("You are not allowed to post news.")),
3443 },
3444 },
3445 },
3446 wantErr: assert.NoError,
3447 },
3448 {
3449 name: "when user posts news update",
3450 args: args{
3451 cc: &ClientConn{
3452 Account: &Account{
3453 Access: func() accessBitmap {
3454 var bits accessBitmap
3455 bits.Set(accessNewsPostArt)
3456 return bits
3457 }(),
3458 },
3459 Server: &Server{
3460 FS: func() *MockFileStore {
3461 mfs := &MockFileStore{}
3462 mfs.On("WriteFile", "/fakeConfigRoot/MessageBoard.txt", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3463 return mfs
3464 }(),
3465 ConfigDir: "/fakeConfigRoot",
3466 Config: &Config{},
3467 },
3468 },
3469 t: NewTransaction(
3470 TranOldPostNews, &[]byte{0, 1},
3471 NewField(FieldData, []byte("hai")),
3472 ),
3473 },
3474 wantRes: []Transaction{
3475 {
3476 Flags: 0x00,
3477 IsReply: 0x01,
3478 Type: []byte{0, 0},
3479 ID: []byte{0, 0, 0, 0},
3480 ErrorCode: []byte{0, 0, 0, 0},
3481 },
3482 },
3483 wantErr: assert.NoError,
3484 },
3485 }
3486 for _, tt := range tests {
3487 t.Run(tt.name, func(t *testing.T) {
3488 gotRes, err := HandleTranOldPostNews(tt.args.cc, tt.args.t)
3489 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranOldPostNews(%v, %v)", tt.args.cc, tt.args.t)) {
3490 return
3491 }
3492
3493 tranAssertEqual(t, tt.wantRes, gotRes)
3494 })
3495 }
3496 }
3497
3498 func TestHandleInviteNewChat(t *testing.T) {
3499 type args struct {
3500 cc *ClientConn
3501 t *Transaction
3502 }
3503 tests := []struct {
3504 name string
3505 args args
3506 wantRes []Transaction
3507 wantErr assert.ErrorAssertionFunc
3508 }{
3509 {
3510 name: "when user does not have required permission",
3511 args: args{
3512 cc: &ClientConn{
3513 Account: &Account{
3514 Access: func() accessBitmap {
3515 var bits accessBitmap
3516 return bits
3517 }(),
3518 },
3519 },
3520 t: NewTransaction(TranInviteNewChat, &[]byte{0, 1}),
3521 },
3522 wantRes: []Transaction{
3523 {
3524 Flags: 0x00,
3525 IsReply: 0x01,
3526 Type: []byte{0, 0},
3527 ID: []byte{0, 0, 0, 0},
3528 ErrorCode: []byte{0, 0, 0, 1},
3529 Fields: []Field{
3530 NewField(FieldError, []byte("You are not allowed to request private chat.")),
3531 },
3532 },
3533 },
3534 wantErr: assert.NoError,
3535 },
3536 {
3537 name: "when userA invites userB to new private chat",
3538 args: args{
3539 cc: &ClientConn{
3540 ID: &[]byte{0, 1},
3541 Account: &Account{
3542 Access: func() accessBitmap {
3543 var bits accessBitmap
3544 bits.Set(accessOpenChat)
3545 return bits
3546 }(),
3547 },
3548 UserName: []byte("UserA"),
3549 Icon: []byte{0, 1},
3550 Flags: []byte{0, 0},
3551 Server: &Server{
3552 Clients: map[uint16]*ClientConn{
3553 uint16(2): {
3554 ID: &[]byte{0, 2},
3555 UserName: []byte("UserB"),
3556 Flags: []byte{0, 0},
3557 },
3558 },
3559 PrivateChats: make(map[uint32]*PrivateChat),
3560 },
3561 },
3562 t: NewTransaction(
3563 TranInviteNewChat, &[]byte{0, 1},
3564 NewField(FieldUserID, []byte{0, 2}),
3565 ),
3566 },
3567 wantRes: []Transaction{
3568 {
3569 clientID: &[]byte{0, 2},
3570 Flags: 0x00,
3571 IsReply: 0x00,
3572 Type: []byte{0, 0x71},
3573 ID: []byte{0, 0, 0, 0},
3574 ErrorCode: []byte{0, 0, 0, 0},
3575 Fields: []Field{
3576 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3577 NewField(FieldUserName, []byte("UserA")),
3578 NewField(FieldUserID, []byte{0, 1}),
3579 },
3580 },
3581
3582 {
3583 clientID: &[]byte{0, 1},
3584 Flags: 0x00,
3585 IsReply: 0x01,
3586 Type: []byte{0, 0},
3587 ID: []byte{0, 0, 0, 0},
3588 ErrorCode: []byte{0, 0, 0, 0},
3589 Fields: []Field{
3590 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3591 NewField(FieldUserName, []byte("UserA")),
3592 NewField(FieldUserID, []byte{0, 1}),
3593 NewField(FieldUserIconID, []byte{0, 1}),
3594 NewField(FieldUserFlags, []byte{0, 0}),
3595 },
3596 },
3597 },
3598 wantErr: assert.NoError,
3599 },
3600 {
3601 name: "when userA invites userB to new private chat, but UserB has refuse private chat enabled",
3602 args: args{
3603 cc: &ClientConn{
3604 ID: &[]byte{0, 1},
3605 Account: &Account{
3606 Access: func() accessBitmap {
3607 var bits accessBitmap
3608 bits.Set(accessOpenChat)
3609 return bits
3610 }(),
3611 },
3612 UserName: []byte("UserA"),
3613 Icon: []byte{0, 1},
3614 Flags: []byte{0, 0},
3615 Server: &Server{
3616 Clients: map[uint16]*ClientConn{
3617 uint16(2): {
3618 ID: &[]byte{0, 2},
3619 UserName: []byte("UserB"),
3620 Flags: []byte{255, 255},
3621 },
3622 },
3623 PrivateChats: make(map[uint32]*PrivateChat),
3624 },
3625 },
3626 t: NewTransaction(
3627 TranInviteNewChat, &[]byte{0, 1},
3628 NewField(FieldUserID, []byte{0, 2}),
3629 ),
3630 },
3631 wantRes: []Transaction{
3632 {
3633 clientID: &[]byte{0, 1},
3634 Flags: 0x00,
3635 IsReply: 0x00,
3636 Type: []byte{0, 0x68},
3637 ID: []byte{0, 0, 0, 0},
3638 ErrorCode: []byte{0, 0, 0, 0},
3639 Fields: []Field{
3640 NewField(FieldData, []byte("UserB does not accept private chats.")),
3641 NewField(FieldUserName, []byte("UserB")),
3642 NewField(FieldUserID, []byte{0, 2}),
3643 NewField(FieldOptions, []byte{0, 2}),
3644 },
3645 },
3646 {
3647 clientID: &[]byte{0, 1},
3648 Flags: 0x00,
3649 IsReply: 0x01,
3650 Type: []byte{0, 0},
3651 ID: []byte{0, 0, 0, 0},
3652 ErrorCode: []byte{0, 0, 0, 0},
3653 Fields: []Field{
3654 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3655 NewField(FieldUserName, []byte("UserA")),
3656 NewField(FieldUserID, []byte{0, 1}),
3657 NewField(FieldUserIconID, []byte{0, 1}),
3658 NewField(FieldUserFlags, []byte{0, 0}),
3659 },
3660 },
3661 },
3662 wantErr: assert.NoError,
3663 },
3664 }
3665 for _, tt := range tests {
3666 t.Run(tt.name, func(t *testing.T) {
3667 rand.Seed(1)
3668 gotRes, err := HandleInviteNewChat(tt.args.cc, tt.args.t)
3669 if !tt.wantErr(t, err, fmt.Sprintf("HandleInviteNewChat(%v, %v)", tt.args.cc, tt.args.t)) {
3670 return
3671 }
3672 tranAssertEqual(t, tt.wantRes, gotRes)
3673 })
3674 }
3675 }
3676
3677 func TestHandleGetNewsArtData(t *testing.T) {
3678 type args struct {
3679 cc *ClientConn
3680 t *Transaction
3681 }
3682 tests := []struct {
3683 name string
3684 args args
3685 wantRes []Transaction
3686 wantErr assert.ErrorAssertionFunc
3687 }{
3688 {
3689 name: "when user does not have required permission",
3690 args: args{
3691 cc: &ClientConn{
3692 Account: &Account{
3693 Access: func() accessBitmap {
3694 var bits accessBitmap
3695 return bits
3696 }(),
3697 },
3698 Server: &Server{
3699 Accounts: map[string]*Account{},
3700 },
3701 },
3702 t: NewTransaction(
3703 TranGetNewsArtData, &[]byte{0, 1},
3704 ),
3705 },
3706 wantRes: []Transaction{
3707 {
3708 Flags: 0x00,
3709 IsReply: 0x01,
3710 Type: []byte{0, 0},
3711 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
3712 ErrorCode: []byte{0, 0, 0, 1},
3713 Fields: []Field{
3714 NewField(FieldError, []byte("You are not allowed to read news.")),
3715 },
3716 },
3717 },
3718 wantErr: assert.NoError,
3719 },
3720 }
3721 for _, tt := range tests {
3722 t.Run(tt.name, func(t *testing.T) {
3723 gotRes, err := HandleGetNewsArtData(tt.args.cc, tt.args.t)
3724 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetNewsArtData(%v, %v)", tt.args.cc, tt.args.t)) {
3725 return
3726 }
3727 tranAssertEqual(t, tt.wantRes, gotRes)
3728 })
3729 }
3730 }
3731
3732 func TestHandleGetNewsArtNameList(t *testing.T) {
3733 type args struct {
3734 cc *ClientConn
3735 t *Transaction
3736 }
3737 tests := []struct {
3738 name string
3739 args args
3740 wantRes []Transaction
3741 wantErr assert.ErrorAssertionFunc
3742 }{
3743 {
3744 name: "when user does not have required permission",
3745 args: args{
3746 cc: &ClientConn{
3747 Account: &Account{
3748 Access: func() accessBitmap {
3749 var bits accessBitmap
3750 return bits
3751 }(),
3752 },
3753 Server: &Server{
3754 Accounts: map[string]*Account{},
3755 },
3756 },
3757 t: NewTransaction(
3758 TranGetNewsArtNameList, &[]byte{0, 1},
3759 ),
3760 },
3761 wantRes: []Transaction{
3762 {
3763 Flags: 0x00,
3764 IsReply: 0x01,
3765 Type: []byte{0, 0},
3766 ErrorCode: []byte{0, 0, 0, 1},
3767 Fields: []Field{
3768 NewField(FieldError, []byte("You are not allowed to read news.")),
3769 },
3770 },
3771 },
3772 wantErr: assert.NoError,
3773 },
3774 }
3775 for _, tt := range tests {
3776 t.Run(tt.name, func(t *testing.T) {
3777 gotRes, err := HandleGetNewsArtNameList(tt.args.cc, tt.args.t)
3778 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetNewsArtNameList(%v, %v)", tt.args.cc, tt.args.t)) {
3779 return
3780 }
3781 tranAssertEqual(t, tt.wantRes, gotRes)
3782 })
3783 }
3784 }
3785
3786 func TestHandleNewNewsFldr(t *testing.T) {
3787 type args struct {
3788 cc *ClientConn
3789 t *Transaction
3790 }
3791 tests := []struct {
3792 name string
3793 args args
3794 wantRes []Transaction
3795 wantErr assert.ErrorAssertionFunc
3796 }{
3797 {
3798 name: "when user does not have required permission",
3799 args: args{
3800 cc: &ClientConn{
3801 Account: &Account{
3802 Access: func() accessBitmap {
3803 var bits accessBitmap
3804 return bits
3805 }(),
3806 },
3807 Server: &Server{
3808 Accounts: map[string]*Account{},
3809 },
3810 },
3811 t: NewTransaction(
3812 TranGetNewsArtNameList, &[]byte{0, 1},
3813 ),
3814 },
3815 wantRes: []Transaction{
3816 {
3817 Flags: 0x00,
3818 IsReply: 0x01,
3819 Type: []byte{0, 0},
3820 ErrorCode: []byte{0, 0, 0, 1},
3821 Fields: []Field{
3822 NewField(FieldError, []byte("You are not allowed to create news folders.")),
3823 },
3824 },
3825 },
3826 wantErr: assert.NoError,
3827 },
3828 {
3829 name: "with a valid request",
3830 args: args{
3831 cc: &ClientConn{
3832 Account: &Account{
3833 Access: func() accessBitmap {
3834 var bits accessBitmap
3835 bits.Set(accessNewsCreateFldr)
3836 return bits
3837 }(),
3838 },
3839 logger: NewTestLogger(),
3840 ID: &[]byte{0, 1},
3841 Server: &Server{
3842 ConfigDir: "/fakeConfigRoot",
3843 FS: func() *MockFileStore {
3844 mfs := &MockFileStore{}
3845 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil)
3846 return mfs
3847 }(),
3848 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3849 "test": {
3850 Type: []byte{0, 2},
3851 Count: nil,
3852 NameSize: 0,
3853 Name: "test",
3854 SubCats: make(map[string]NewsCategoryListData15),
3855 },
3856 }},
3857 },
3858 },
3859 t: NewTransaction(
3860 TranGetNewsArtNameList, &[]byte{0, 1},
3861 NewField(FieldFileName, []byte("testFolder")),
3862 NewField(FieldNewsPath,
3863 []byte{
3864 0, 1,
3865 0, 0,
3866 4,
3867 0x74, 0x65, 0x73, 0x74,
3868 },
3869 ),
3870 ),
3871 },
3872 wantRes: []Transaction{
3873 {
3874 clientID: &[]byte{0, 1},
3875 Flags: 0x00,
3876 IsReply: 0x01,
3877 Type: []byte{0, 0},
3878 ID: []byte{0, 0, 0, 0},
3879 ErrorCode: []byte{0, 0, 0, 0},
3880 Fields: []Field{},
3881 },
3882 },
3883 wantErr: assert.NoError,
3884 },
3885 //{
3886 // name: "when there is an error writing the threaded news file",
3887 // args: args{
3888 // cc: &ClientConn{
3889 // Account: &Account{
3890 // Access: func() accessBitmap {
3891 // var bits accessBitmap
3892 // bits.Set(accessNewsCreateFldr)
3893 // return bits
3894 // }(),
3895 // },
3896 // logger: NewTestLogger(),
3897 // ID: &[]byte{0, 1},
3898 // Server: &Server{
3899 // ConfigDir: "/fakeConfigRoot",
3900 // FS: func() *MockFileStore {
3901 // mfs := &MockFileStore{}
3902 // mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(os.ErrNotExist)
3903 // return mfs
3904 // }(),
3905 // ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3906 // "test": {
3907 // Type: []byte{0, 2},
3908 // Count: nil,
3909 // NameSize: 0,
3910 // Name: "test",
3911 // SubCats: make(map[string]NewsCategoryListData15),
3912 // },
3913 // }},
3914 // },
3915 // },
3916 // t: NewTransaction(
3917 // TranGetNewsArtNameList, &[]byte{0, 1},
3918 // NewField(FieldFileName, []byte("testFolder")),
3919 // NewField(FieldNewsPath,
3920 // []byte{
3921 // 0, 1,
3922 // 0, 0,
3923 // 4,
3924 // 0x74, 0x65, 0x73, 0x74,
3925 // },
3926 // ),
3927 // ),
3928 // },
3929 // wantRes: []Transaction{
3930 // {
3931 // clientID: &[]byte{0, 1},
3932 // Flags: 0x00,
3933 // IsReply: 0x01,
3934 // Type: []byte{0, 0},
3935 // ErrorCode: []byte{0, 0, 0, 1},
3936 // Fields: []Field{
3937 // NewField(FieldError, []byte("Error creating news folder.")),
3938 // },
3939 // },
3940 // },
3941 // wantErr: assert.Error,
3942 // },
3943 }
3944 for _, tt := range tests {
3945 t.Run(tt.name, func(t *testing.T) {
3946 gotRes, err := HandleNewNewsFldr(tt.args.cc, tt.args.t)
3947 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewNewsFldr(%v, %v)", tt.args.cc, tt.args.t)) {
3948 return
3949 }
3950 tranAssertEqual(t, tt.wantRes, gotRes)
3951 })
3952 }
3953 }