]> git.r.bdr.sh - rbdr/mobius/blame - hotline/transaction_handlers_test.go
Use strings.ReplaceAll method
[rbdr/mobius] / hotline / transaction_handlers_test.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
decc2fbf 4 "errors"
9ebf276d 5 "fmt"
6988a057 6 "github.com/stretchr/testify/assert"
8eb43f95 7 "github.com/stretchr/testify/mock"
00d1ef67 8 "io/fs"
6988a057 9 "math/rand"
00d1ef67 10 "os"
f22acf38 11 "path/filepath"
decc2fbf 12 "strings"
6988a057 13 "testing"
7cd900d6 14 "time"
6988a057
JH
15)
16
17func 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{
72dd37f1 32 UserName: []byte{0x00, 0x01},
6988a057
JH
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{
187d6dc5 40 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
41 },
42 ID: &[]byte{0, 1},
43 },
44 uint16(2): {
45 Account: &Account{
187d6dc5 46 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
47 },
48 ID: &[]byte{0, 2},
49 },
50 },
51 },
52 },
53 Clients: map[uint16]*ClientConn{
54 uint16(1): {
55 Account: &Account{
187d6dc5 56 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
57 },
58 ID: &[]byte{0, 1},
59 },
60 uint16(2): {
61 Account: &Account{
187d6dc5 62 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
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{
d005ef04
JH
76 NewField(FieldChatID, []byte{0, 0, 0, 1}),
77 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
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{
d005ef04
JH
90 NewField(FieldChatID, []byte{0, 0, 0, 1}),
91 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
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{
d005ef04
JH
102 NewField(FieldChatID, []byte{0, 0, 0, 1}),
103 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
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
126func 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{
187d6dc5 148 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
149 },
150 ID: &[]byte{0, 1},
151 },
152 uint16(2): {
153 Account: &Account{
187d6dc5 154 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
155 },
156 ID: &[]byte{0, 2},
157 },
158 },
159 },
160 },
161 Clients: map[uint16]*ClientConn{
162 uint16(1): {
163 Account: &Account{
187d6dc5 164 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
165 },
166 ID: &[]byte{0, 1},
167 },
168 uint16(2): {
169 Account: &Account{
187d6dc5 170 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
171 },
172 ID: &[]byte{0, 2},
173 },
174 },
175 },
176 },
d005ef04 177 t: NewTransaction(TranDeleteUser, nil, NewField(FieldChatID, []byte{0, 0, 0, 1})),
6988a057
JH
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{
d005ef04
JH
188 NewField(FieldChatID, []byte{0, 0, 0, 1}),
189 NewField(FieldUserID, []byte{0, 2}),
6988a057
JH
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
6988a057
JH
211func 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},
a7216f67
JH
232 Icon: []byte{0, 2},
233 Flags: []byte{0, 3},
72dd37f1 234 UserName: []byte{0, 4},
6988a057 235 },
c7e932c0
JH
236 uint16(2): {
237 ID: &[]byte{0, 2},
a7216f67
JH
238 Icon: []byte{0, 2},
239 Flags: []byte{0, 3},
c7e932c0 240 UserName: []byte{0, 4},
bd1ce113 241 },
6988a057
JH
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,
945b9813 255 Type: []byte{0, 0},
6988a057
JH
256 ID: []byte{0, 0, 0, 1},
257 ErrorCode: []byte{0, 0, 0, 0},
258 Fields: []Field{
259 NewField(
d005ef04 260 FieldUsernameWithInfo,
6988a057
JH
261 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
262 ),
c7e932c0 263 NewField(
d005ef04 264 FieldUsernameWithInfo,
c7e932c0
JH
265 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
266 ),
6988a057
JH
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 }
bd1ce113 280 assert.Equal(t, tt.want, got)
6988a057
JH
281 })
282 }
283}
284
285func 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{
9ebf276d 300 Account: &Account{
187d6dc5 301 Access: func() accessBitmap {
9ebf276d
JH
302 var bits accessBitmap
303 bits.Set(accessSendChat)
187d6dc5 304 return bits
9ebf276d
JH
305 }(),
306 },
72dd37f1 307 UserName: []byte{0x00, 0x01},
6988a057
JH
308 Server: &Server{
309 Clients: map[uint16]*ClientConn{
310 uint16(1): {
311 Account: &Account{
187d6dc5 312 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
313 },
314 ID: &[]byte{0, 1},
315 },
316 uint16(2): {
317 Account: &Account{
187d6dc5 318 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057
JH
319 },
320 ID: &[]byte{0, 2},
321 },
322 },
323 },
324 },
325 t: &Transaction{
326 Fields: []Field{
d005ef04 327 NewField(FieldData, []byte("hai")),
6988a057
JH
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{
d005ef04 340 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
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{
d005ef04 351 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
352 },
353 },
354 },
355 wantErr: false,
356 },
361928c9
JH
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{
d005ef04
JH
388 NewField(FieldData, []byte("hai")),
389 NewField(FieldChatID, []byte{0, 0, 0, 0}),
361928c9
JH
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{
d005ef04 402 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
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{
d005ef04 413 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
414 },
415 },
416 },
417 wantErr: false,
418 },
9ebf276d
JH
419 {
420 name: "when user does not have required permission",
421 args: args{
422 cc: &ClientConn{
423 Account: &Account{
187d6dc5 424 Access: func() accessBitmap {
9ebf276d 425 var bits accessBitmap
187d6dc5 426 return bits
9ebf276d
JH
427 }(),
428 },
429 Server: &Server{
430 Accounts: map[string]*Account{},
431 },
432 },
433 t: NewTransaction(
d005ef04
JH
434 TranChatSend, &[]byte{0, 1},
435 NewField(FieldData, []byte("hai")),
9ebf276d
JH
436 ),
437 },
438 want: []Transaction{
439 {
440 Flags: 0x00,
441 IsReply: 0x01,
860861f2 442 Type: []byte{0, 0},
9ebf276d
JH
443 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
444 ErrorCode: []byte{0, 0, 0, 1},
445 Fields: []Field{
d005ef04 446 NewField(FieldError, []byte("You are not allowed to participate in chat.")),
9ebf276d
JH
447 },
448 },
449 },
450 wantErr: false,
451 },
72dd37f1 452 {
d005ef04 453 name: "sends chat msg as emote if FieldChatOptions is set to 1",
72dd37f1
JH
454 args: args{
455 cc: &ClientConn{
9ebf276d 456 Account: &Account{
187d6dc5 457 Access: func() accessBitmap {
9ebf276d
JH
458 var bits accessBitmap
459 bits.Set(accessSendChat)
187d6dc5 460 return bits
9ebf276d
JH
461 }(),
462 },
72dd37f1
JH
463 UserName: []byte("Testy McTest"),
464 Server: &Server{
465 Clients: map[uint16]*ClientConn{
466 uint16(1): {
467 Account: &Account{
187d6dc5 468 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72dd37f1
JH
469 },
470 ID: &[]byte{0, 1},
471 },
472 uint16(2): {
473 Account: &Account{
187d6dc5 474 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72dd37f1
JH
475 },
476 ID: &[]byte{0, 2},
477 },
478 },
479 },
480 },
481 t: &Transaction{
482 Fields: []Field{
d005ef04
JH
483 NewField(FieldData, []byte("performed action")),
484 NewField(FieldChatOptions, []byte{0x00, 0x01}),
72dd37f1
JH
485 },
486 },
487 },
488 want: []Transaction{
489 {
490 clientID: &[]byte{0, 1},
491 Flags: 0x00,
492 IsReply: 0x00,
493 Type: []byte{0, 0x6a},
481631f6 494 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
72dd37f1
JH
495 ErrorCode: []byte{0, 0, 0, 0},
496 Fields: []Field{
d005ef04 497 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
498 },
499 },
500 {
501 clientID: &[]byte{0, 2},
502 Flags: 0x00,
503 IsReply: 0x00,
504 Type: []byte{0, 0x6a},
481631f6 505 ID: []byte{0xf0, 0xc5, 0x34, 0x1e},
72dd37f1
JH
506 ErrorCode: []byte{0, 0, 0, 0},
507 Fields: []Field{
d005ef04 508 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
509 },
510 },
511 },
512 wantErr: false,
513 },
2e43fd4e 514 {
d005ef04 515 name: "does not send chat msg as emote if FieldChatOptions is set to 0",
2e43fd4e
JH
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{
d005ef04
JH
545 NewField(FieldData, []byte("hello")),
546 NewField(FieldChatOptions, []byte{0x00, 0x00}),
2e43fd4e
JH
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{
d005ef04 559 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
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{
d005ef04 570 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
571 },
572 },
573 },
574 wantErr: false,
575 },
6988a057
JH
576 {
577 name: "only sends chat msg to clients with accessReadChat permission",
578 args: args{
579 cc: &ClientConn{
9ebf276d 580 Account: &Account{
187d6dc5 581 Access: func() accessBitmap {
9ebf276d
JH
582 var bits accessBitmap
583 bits.Set(accessSendChat)
187d6dc5 584 return bits
9ebf276d
JH
585 }(),
586 },
72dd37f1 587 UserName: []byte{0x00, 0x01},
6988a057
JH
588 Server: &Server{
589 Clients: map[uint16]*ClientConn{
590 uint16(1): {
591 Account: &Account{
187d6dc5
JH
592 Access: func() accessBitmap {
593 var bits accessBitmap
594 bits.Set(accessReadChat)
595 return bits
596 }()},
6988a057
JH
597 ID: &[]byte{0, 1},
598 },
599 uint16(2): {
600 Account: &Account{
187d6dc5 601 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
6988a057
JH
602 },
603 ID: &[]byte{0, 2},
604 },
605 },
606 },
607 },
608 t: &Transaction{
609 Fields: []Field{
d005ef04 610 NewField(FieldData, []byte("hai")),
6988a057
JH
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{
d005ef04 623 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
624 },
625 },
626 },
627 wantErr: false,
628 },
481631f6
JH
629 {
630 name: "only sends private chat msg to members of private chat",
631 args: args{
632 cc: &ClientConn{
633 Account: &Account{
187d6dc5 634 Access: func() accessBitmap {
481631f6
JH
635 var bits accessBitmap
636 bits.Set(accessSendChat)
187d6dc5 637 return bits
481631f6
JH
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{
187d6dc5 657 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
481631f6
JH
658 },
659 ID: &[]byte{0, 1},
660 },
661 uint16(2): {
662 Account: &Account{
187d6dc5 663 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
481631f6
JH
664 },
665 ID: &[]byte{0, 2},
666 },
667 uint16(3): {
668 Account: &Account{
187d6dc5 669 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
481631f6
JH
670 },
671 ID: &[]byte{0, 3},
672 },
673 },
674 },
675 },
676 t: &Transaction{
677 Fields: []Field{
d005ef04
JH
678 NewField(FieldData, []byte("hai")),
679 NewField(FieldChatID, []byte{0, 0, 0, 1}),
481631f6
JH
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{
d005ef04
JH
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}),
481631f6
JH
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{
d005ef04
JH
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}),
481631f6
JH
706 },
707 },
708 },
709 wantErr: false,
710 },
6988a057
JH
711 }
712 for _, tt := range tests {
6988a057
JH
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 }
9ebf276d 720 tranAssertEqual(t, tt.want, got)
6988a057
JH
721 })
722 }
723}
72dd37f1
JH
724
725func 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{
7cd900d6 744 FS: &OSFileStore{},
72dd37f1 745 Config: &Config{
29f329ae
JH
746 FileRoot: func() string {
747 path, _ := os.Getwd()
f22acf38 748 return filepath.Join(path, "/test/config/Files")
29f329ae 749 }(),
72dd37f1
JH
750 },
751 },
752 },
753 t: NewTransaction(
d005ef04
JH
754 TranGetFileInfo, nil,
755 NewField(FieldFileName, []byte("testfile.txt")),
756 NewField(FieldFilePath, []byte{0x00, 0x00}),
72dd37f1
JH
757 ),
758 },
759 wantRes: []Transaction{
760 {
761 clientID: &[]byte{0, 1},
762 Flags: 0x00,
763 IsReply: 0x01,
945b9813 764 Type: []byte{0, 0},
72dd37f1
JH
765 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
766 ErrorCode: []byte{0, 0, 0, 0},
767 Fields: []Field{
d005ef04
JH
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}),
72dd37f1
JH
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 }
29f329ae 791
7cd900d6 792 // Clear the fileWrapper timestamp fields to work around problems running the tests in multiple timezones
29f329ae
JH
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)
00d1ef67 796 if !assert.Equal(t, tt.wantRes, gotRes) {
72dd37f1
JH
797 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
798 }
799 })
800 }
801}
00d1ef67
JH
802
803func TestHandleNewFolder(t *testing.T) {
804 type args struct {
805 cc *ClientConn
806 t *Transaction
807 }
808 tests := []struct {
00d1ef67
JH
809 name string
810 args args
811 wantRes []Transaction
812 wantErr bool
813 }{
d4c152a4 814 {
b196a50a 815 name: "without required permission",
d4c152a4
JH
816 args: args{
817 cc: &ClientConn{
818 Account: &Account{
187d6dc5 819 Access: func() accessBitmap {
d4c152a4 820 var bits accessBitmap
187d6dc5 821 return bits
d4c152a4
JH
822 }(),
823 },
824 },
825 t: NewTransaction(
826 accessCreateFolder,
827 &[]byte{0, 0},
828 ),
829 },
830 wantRes: []Transaction{
831 {
832 Flags: 0x00,
833 IsReply: 0x01,
860861f2 834 Type: []byte{0, 0},
d4c152a4
JH
835 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
836 ErrorCode: []byte{0, 0, 0, 1},
837 Fields: []Field{
d005ef04 838 NewField(FieldError, []byte("You are not allowed to create folders.")),
d4c152a4
JH
839 },
840 },
841 },
842 wantErr: false,
843 },
00d1ef67
JH
844 {
845 name: "when path is nested",
846 args: args{
847 cc: &ClientConn{
d4c152a4 848 Account: &Account{
187d6dc5 849 Access: func() accessBitmap {
d4c152a4
JH
850 var bits accessBitmap
851 bits.Set(accessCreateFolder)
187d6dc5 852 return bits
d4c152a4
JH
853 }(),
854 },
00d1ef67
JH
855 ID: &[]byte{0, 1},
856 Server: &Server{
857 Config: &Config{
858 FileRoot: "/Files/",
859 },
b196a50a
JH
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 }(),
00d1ef67
JH
866 },
867 },
868 t: NewTransaction(
d005ef04
JH
869 TranNewFolder, &[]byte{0, 1},
870 NewField(FieldFileName, []byte("testFolder")),
871 NewField(FieldFilePath, []byte{
00d1ef67
JH
872 0x00, 0x01,
873 0x00, 0x00,
874 0x03,
875 0x61, 0x61, 0x61,
876 }),
877 ),
878 },
00d1ef67
JH
879 wantRes: []Transaction{
880 {
881 clientID: &[]byte{0, 1},
882 Flags: 0x00,
883 IsReply: 0x01,
945b9813 884 Type: []byte{0, 0},
00d1ef67
JH
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{
d4c152a4 895 Account: &Account{
187d6dc5 896 Access: func() accessBitmap {
d4c152a4
JH
897 var bits accessBitmap
898 bits.Set(accessCreateFolder)
187d6dc5 899 return bits
d4c152a4
JH
900 }(),
901 },
00d1ef67
JH
902 ID: &[]byte{0, 1},
903 Server: &Server{
904 Config: &Config{
905 FileRoot: "/Files",
906 },
b196a50a
JH
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 }(),
00d1ef67
JH
913 },
914 },
915 t: NewTransaction(
d005ef04
JH
916 TranNewFolder, &[]byte{0, 1},
917 NewField(FieldFileName, []byte("testFolder")),
00d1ef67
JH
918 ),
919 },
00d1ef67
JH
920 wantRes: []Transaction{
921 {
922 clientID: &[]byte{0, 1},
923 Flags: 0x00,
924 IsReply: 0x01,
945b9813 925 Type: []byte{0, 0},
00d1ef67
JH
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 {
8fc43f8e 933 name: "when Write returns an err",
00d1ef67
JH
934 args: args{
935 cc: &ClientConn{
d4c152a4 936 Account: &Account{
187d6dc5 937 Access: func() accessBitmap {
d4c152a4
JH
938 var bits accessBitmap
939 bits.Set(accessCreateFolder)
187d6dc5 940 return bits
d4c152a4
JH
941 }(),
942 },
00d1ef67
JH
943 ID: &[]byte{0, 1},
944 Server: &Server{
945 Config: &Config{
946 FileRoot: "/Files/",
947 },
b196a50a
JH
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 }(),
00d1ef67
JH
954 },
955 },
956 t: NewTransaction(
d005ef04
JH
957 TranNewFolder, &[]byte{0, 1},
958 NewField(FieldFileName, []byte("testFolder")),
959 NewField(FieldFilePath, []byte{
00d1ef67
JH
960 0x00,
961 }),
962 ),
963 },
00d1ef67
JH
964 wantRes: []Transaction{},
965 wantErr: true,
966 },
967 {
d005ef04 968 name: "FieldFileName does not allow directory traversal",
00d1ef67
JH
969 args: args{
970 cc: &ClientConn{
d4c152a4 971 Account: &Account{
187d6dc5 972 Access: func() accessBitmap {
d4c152a4
JH
973 var bits accessBitmap
974 bits.Set(accessCreateFolder)
187d6dc5 975 return bits
d4c152a4
JH
976 }(),
977 },
00d1ef67
JH
978 ID: &[]byte{0, 1},
979 Server: &Server{
980 Config: &Config{
981 FileRoot: "/Files/",
982 },
b196a50a
JH
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 }(),
00d1ef67
JH
989 },
990 },
991 t: NewTransaction(
d005ef04
JH
992 TranNewFolder, &[]byte{0, 1},
993 NewField(FieldFileName, []byte("../../testFolder")),
00d1ef67
JH
994 ),
995 },
00d1ef67
JH
996 wantRes: []Transaction{
997 {
998 clientID: &[]byte{0, 1},
999 Flags: 0x00,
1000 IsReply: 0x01,
945b9813 1001 Type: []byte{0, 0},
00d1ef67
JH
1002 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
1003 ErrorCode: []byte{0, 0, 0, 0},
1004 },
92a7e455 1005 }, wantErr: false,
00d1ef67
JH
1006 },
1007 {
d005ef04 1008 name: "FieldFilePath does not allow directory traversal",
00d1ef67
JH
1009 args: args{
1010 cc: &ClientConn{
d4c152a4 1011 Account: &Account{
187d6dc5 1012 Access: func() accessBitmap {
d4c152a4
JH
1013 var bits accessBitmap
1014 bits.Set(accessCreateFolder)
187d6dc5 1015 return bits
d4c152a4
JH
1016 }(),
1017 },
00d1ef67
JH
1018 ID: &[]byte{0, 1},
1019 Server: &Server{
1020 Config: &Config{
1021 FileRoot: "/Files/",
1022 },
b196a50a
JH
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 }(),
00d1ef67
JH
1029 },
1030 },
1031 t: NewTransaction(
d005ef04
JH
1032 TranNewFolder, &[]byte{0, 1},
1033 NewField(FieldFileName, []byte("testFolder")),
1034 NewField(FieldFilePath, []byte{
00d1ef67
JH
1035 0x00, 0x02,
1036 0x00, 0x00,
1037 0x03,
1038 0x2e, 0x2e, 0x2f,
1039 0x00, 0x00,
1040 0x03,
1041 0x66, 0x6f, 0x6f,
1042 }),
1043 ),
1044 },
00d1ef67
JH
1045 wantRes: []Transaction{
1046 {
1047 clientID: &[]byte{0, 1},
1048 Flags: 0x00,
1049 IsReply: 0x01,
945b9813 1050 Type: []byte{0, 0},
00d1ef67
JH
1051 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
1052 ErrorCode: []byte{0, 0, 0, 0},
1053 },
92a7e455 1054 }, wantErr: false,
00d1ef67
JH
1055 },
1056 }
1057 for _, tt := range tests {
1058 t.Run(tt.name, func(t *testing.T) {
00d1ef67
JH
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 }
d4c152a4 1064
00d1ef67
JH
1065 if !tranAssertEqual(t, tt.wantRes, gotRes) {
1066 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
1067 }
1068 })
1069 }
1070}
1071
92a7e455
JH
1072func 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 {
7e2e07da 1084 name: "when request is valid and user has Upload Anywhere permission",
92a7e455
JH
1085 args: args{
1086 cc: &ClientConn{
1087 Server: &Server{
df1ade54
JH
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: {},
92a7e455
JH
1095 },
1096 Account: &Account{
187d6dc5 1097 Access: func() accessBitmap {
92a7e455
JH
1098 var bits accessBitmap
1099 bits.Set(accessUploadFile)
7e2e07da 1100 bits.Set(accessUploadAnywhere)
187d6dc5 1101 return bits
92a7e455
JH
1102 }(),
1103 },
1104 },
1105 t: NewTransaction(
d005ef04
JH
1106 TranUploadFile, &[]byte{0, 1},
1107 NewField(FieldFileName, []byte("testFile")),
1108 NewField(FieldFilePath, []byte{
92a7e455
JH
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,
945b9813 1120 Type: []byte{0, 0},
92a7e455
JH
1121 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1122 ErrorCode: []byte{0, 0, 0, 0},
1123 Fields: []Field{
d005ef04 1124 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
92a7e455
JH
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{
187d6dc5 1135 Access: func() accessBitmap {
92a7e455 1136 var bits accessBitmap
187d6dc5 1137 return bits
92a7e455
JH
1138 }(),
1139 },
92a7e455
JH
1140 },
1141 t: NewTransaction(
d005ef04
JH
1142 TranUploadFile, &[]byte{0, 1},
1143 NewField(FieldFileName, []byte("testFile")),
1144 NewField(FieldFilePath, []byte{
92a7e455
JH
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,
860861f2 1156 Type: []byte{0, 0},
92a7e455
JH
1157 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1158 ErrorCode: []byte{0, 0, 0, 1},
1159 Fields: []Field{
d005ef04 1160 NewField(FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
92a7e455
JH
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 }
aebc4d36
JH
1175
1176 tranAssertEqual(t, tt.wantRes, gotRes)
92a7e455
JH
1177 })
1178 }
1179}
decc2fbf
JH
1180
1181func TestHandleMakeAlias(t *testing.T) {
1182 type args struct {
1183 cc *ClientConn
1184 t *Transaction
1185 }
1186 tests := []struct {
1187 name string
decc2fbf
JH
1188 args args
1189 wantRes []Transaction
1190 wantErr bool
1191 }{
1192 {
1193 name: "with valid input and required permissions",
decc2fbf
JH
1194 args: args{
1195 cc: &ClientConn{
02b446d8 1196 logger: NewTestLogger(),
decc2fbf 1197 Account: &Account{
187d6dc5 1198 Access: func() accessBitmap {
decc2fbf
JH
1199 var bits accessBitmap
1200 bits.Set(accessMakeAlias)
187d6dc5 1201 return bits
decc2fbf
JH
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(),
b196a50a
JH
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 }(),
decc2fbf
JH
1222 },
1223 },
1224 t: NewTransaction(
d005ef04
JH
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"}, "/"))),
decc2fbf
JH
1229 ),
1230 },
1231 wantRes: []Transaction{
1232 {
1233 Flags: 0x00,
1234 IsReply: 0x01,
945b9813 1235 Type: []byte{0, 0},
decc2fbf
JH
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",
decc2fbf
JH
1245 args: args{
1246 cc: &ClientConn{
02b446d8 1247 logger: NewTestLogger(),
decc2fbf 1248 Account: &Account{
187d6dc5 1249 Access: func() accessBitmap {
decc2fbf
JH
1250 var bits accessBitmap
1251 bits.Set(accessMakeAlias)
187d6dc5 1252 return bits
decc2fbf
JH
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(),
b196a50a
JH
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 }(),
decc2fbf
JH
1273 },
1274 },
1275 t: NewTransaction(
d005ef04
JH
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"}, "/"))),
decc2fbf
JH
1280 ),
1281 },
1282 wantRes: []Transaction{
1283 {
1284 Flags: 0x00,
1285 IsReply: 0x01,
860861f2 1286 Type: []byte{0, 0},
decc2fbf
JH
1287 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1288 ErrorCode: []byte{0, 0, 0, 1},
1289 Fields: []Field{
d005ef04 1290 NewField(FieldError, []byte("Error creating alias")),
decc2fbf
JH
1291 },
1292 },
1293 },
1294 wantErr: false,
1295 },
1296 {
b196a50a 1297 name: "when user does not have required permission",
decc2fbf
JH
1298 args: args{
1299 cc: &ClientConn{
02b446d8 1300 logger: NewTestLogger(),
decc2fbf 1301 Account: &Account{
187d6dc5 1302 Access: func() accessBitmap {
decc2fbf 1303 var bits accessBitmap
187d6dc5 1304 return bits
decc2fbf
JH
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(
d005ef04
JH
1317 TranMakeFileAlias, &[]byte{0, 1},
1318 NewField(FieldFileName, []byte("testFile")),
1319 NewField(FieldFilePath, []byte{
decc2fbf
JH
1320 0x00, 0x01,
1321 0x00, 0x00,
1322 0x03,
1323 0x2e, 0x2e, 0x2e,
1324 }),
d005ef04 1325 NewField(FieldFileNewPath, []byte{
decc2fbf
JH
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,
860861f2 1337 Type: []byte{0, 0},
decc2fbf
JH
1338 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1339 ErrorCode: []byte{0, 0, 0, 1},
1340 Fields: []Field{
d005ef04 1341 NewField(FieldError, []byte("You are not allowed to make aliases.")),
decc2fbf
JH
1342 },
1343 },
1344 },
1345 wantErr: false,
1346 },
1347 }
1348 for _, tt := range tests {
1349 t.Run(tt.name, func(t *testing.T) {
decc2fbf
JH
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}
9ebf276d
JH
1360
1361func 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{
187d6dc5 1377 Access: func() accessBitmap {
9ebf276d
JH
1378 var bits accessBitmap
1379 bits.Set(accessOpenUser)
187d6dc5 1380 return bits
9ebf276d
JH
1381 }(),
1382 },
1383 Server: &Server{
1384 Accounts: map[string]*Account{
1385 "guest": {
1386 Login: "guest",
1387 Name: "Guest",
1388 Password: "password",
187d6dc5 1389 Access: accessBitmap{},
9ebf276d
JH
1390 },
1391 },
1392 },
1393 },
1394 t: NewTransaction(
d005ef04
JH
1395 TranGetUser, &[]byte{0, 1},
1396 NewField(FieldUserLogin, []byte("guest")),
9ebf276d
JH
1397 ),
1398 },
1399 wantRes: []Transaction{
1400 {
1401 Flags: 0x00,
1402 IsReply: 0x01,
945b9813 1403 Type: []byte{0, 0},
9ebf276d
JH
1404 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1405 ErrorCode: []byte{0, 0, 0, 0},
1406 Fields: []Field{
d005ef04
JH
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}),
9ebf276d
JH
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{
187d6dc5 1421 Access: func() accessBitmap {
9ebf276d 1422 var bits accessBitmap
187d6dc5 1423 return bits
9ebf276d
JH
1424 }(),
1425 },
1426 Server: &Server{
1427 Accounts: map[string]*Account{},
1428 },
1429 },
1430 t: NewTransaction(
d005ef04
JH
1431 TranGetUser, &[]byte{0, 1},
1432 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1433 ),
1434 },
1435 wantRes: []Transaction{
1436 {
1437 Flags: 0x00,
1438 IsReply: 0x01,
860861f2 1439 Type: []byte{0, 0},
9ebf276d
JH
1440 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1441 ErrorCode: []byte{0, 0, 0, 1},
1442 Fields: []Field{
d005ef04 1443 NewField(FieldError, []byte("You are not allowed to view accounts.")),
9ebf276d
JH
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{
187d6dc5 1454 Access: func() accessBitmap {
9ebf276d
JH
1455 var bits accessBitmap
1456 bits.Set(accessOpenUser)
187d6dc5 1457 return bits
9ebf276d
JH
1458 }(),
1459 },
1460 Server: &Server{
1461 Accounts: map[string]*Account{},
1462 },
1463 },
1464 t: NewTransaction(
d005ef04
JH
1465 TranGetUser, &[]byte{0, 1},
1466 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1467 ),
1468 },
1469 wantRes: []Transaction{
1470 {
1471 Flags: 0x00,
1472 IsReply: 0x01,
860861f2 1473 Type: []byte{0, 0},
9ebf276d
JH
1474 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1475 ErrorCode: []byte{0, 0, 0, 1},
1476 Fields: []Field{
d005ef04 1477 NewField(FieldError, []byte("Account does not exist.")),
9ebf276d
JH
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
1496func TestHandleDeleteUser(t *testing.T) {
1497 type args struct {
1498 cc *ClientConn
1499 t *Transaction
1500 }
1501 tests := []struct {
1502 name string
9ebf276d
JH
1503 args args
1504 wantRes []Transaction
1505 wantErr assert.ErrorAssertionFunc
1506 }{
1507 {
7cd900d6 1508 name: "when user dataFile",
9ebf276d
JH
1509 args: args{
1510 cc: &ClientConn{
1511 Account: &Account{
187d6dc5 1512 Access: func() accessBitmap {
9ebf276d
JH
1513 var bits accessBitmap
1514 bits.Set(accessDeleteUser)
187d6dc5 1515 return bits
9ebf276d
JH
1516 }(),
1517 },
1518 Server: &Server{
1519 Accounts: map[string]*Account{
1520 "testuser": {
1521 Login: "testuser",
1522 Name: "Testy McTest",
1523 Password: "password",
187d6dc5 1524 Access: accessBitmap{},
9ebf276d
JH
1525 },
1526 },
b196a50a
JH
1527 FS: func() *MockFileStore {
1528 mfs := &MockFileStore{}
1529 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1530 return mfs
1531 }(),
9ebf276d
JH
1532 },
1533 },
1534 t: NewTransaction(
d005ef04
JH
1535 TranDeleteUser, &[]byte{0, 1},
1536 NewField(FieldUserLogin, negateString([]byte("testuser"))),
9ebf276d
JH
1537 ),
1538 },
1539 wantRes: []Transaction{
1540 {
1541 Flags: 0x00,
1542 IsReply: 0x01,
945b9813 1543 Type: []byte{0, 0},
9ebf276d
JH
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 {
b196a50a 1552 name: "when user does not have required permission",
9ebf276d
JH
1553 args: args{
1554 cc: &ClientConn{
1555 Account: &Account{
187d6dc5 1556 Access: func() accessBitmap {
9ebf276d 1557 var bits accessBitmap
187d6dc5 1558 return bits
9ebf276d
JH
1559 }(),
1560 },
1561 Server: &Server{
1562 Accounts: map[string]*Account{},
1563 },
1564 },
1565 t: NewTransaction(
d005ef04
JH
1566 TranDeleteUser, &[]byte{0, 1},
1567 NewField(FieldUserLogin, negateString([]byte("testuser"))),
9ebf276d
JH
1568 ),
1569 },
1570 wantRes: []Transaction{
1571 {
1572 Flags: 0x00,
1573 IsReply: 0x01,
860861f2 1574 Type: []byte{0, 0},
9ebf276d
JH
1575 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1576 ErrorCode: []byte{0, 0, 0, 1},
1577 Fields: []Field{
d005ef04 1578 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
9ebf276d
JH
1579 },
1580 },
1581 },
1582 wantErr: assert.NoError,
1583 },
1584 }
1585 for _, tt := range tests {
1586 t.Run(tt.name, func(t *testing.T) {
9ebf276d
JH
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}
481631f6
JH
1596
1597func 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{
187d6dc5 1613 Access: func() accessBitmap {
481631f6
JH
1614 var bits accessBitmap
1615 bits.Set(accessNewsReadArt)
187d6dc5 1616 return bits
481631f6
JH
1617 }(),
1618 },
1619 Server: &Server{
1620 FlatNews: []byte("TEST"),
1621 },
1622 },
1623 t: NewTransaction(
d005ef04 1624 TranGetMsgs, &[]byte{0, 1},
481631f6
JH
1625 ),
1626 },
1627 wantRes: []Transaction{
1628 {
1629 Flags: 0x00,
1630 IsReply: 0x01,
945b9813 1631 Type: []byte{0, 0},
481631f6
JH
1632 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1633 ErrorCode: []byte{0, 0, 0, 0},
1634 Fields: []Field{
d005ef04 1635 NewField(FieldData, []byte("TEST")),
481631f6
JH
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{
187d6dc5 1646 Access: func() accessBitmap {
481631f6 1647 var bits accessBitmap
187d6dc5 1648 return bits
481631f6
JH
1649 }(),
1650 },
1651 Server: &Server{
1652 Accounts: map[string]*Account{},
1653 },
1654 },
1655 t: NewTransaction(
d005ef04 1656 TranGetMsgs, &[]byte{0, 1},
481631f6
JH
1657 ),
1658 },
1659 wantRes: []Transaction{
1660 {
1661 Flags: 0x00,
1662 IsReply: 0x01,
860861f2 1663 Type: []byte{0, 0},
481631f6
JH
1664 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1665 ErrorCode: []byte{0, 0, 0, 1},
1666 Fields: []Field{
d005ef04 1667 NewField(FieldError, []byte("You are not allowed to read news.")),
481631f6
JH
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
1686func 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{
187d6dc5 1702 Access: func() accessBitmap {
481631f6 1703 var bits accessBitmap
187d6dc5 1704 return bits
481631f6
JH
1705 }(),
1706 },
1707 Server: &Server{
1708 Accounts: map[string]*Account{},
1709 },
1710 },
1711 t: NewTransaction(
d005ef04 1712 TranNewUser, &[]byte{0, 1},
481631f6
JH
1713 ),
1714 },
1715 wantRes: []Transaction{
1716 {
1717 Flags: 0x00,
1718 IsReply: 0x01,
860861f2 1719 Type: []byte{0, 0},
481631f6
JH
1720 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1721 ErrorCode: []byte{0, 0, 0, 1},
1722 Fields: []Field{
d005ef04 1723 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
481631f6
JH
1724 },
1725 },
1726 },
1727 wantErr: assert.NoError,
1728 },
ecb1fcd9
JH
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(
d005ef04
JH
1745 TranNewUser, &[]byte{0, 1},
1746 NewField(FieldUserLogin, []byte("userB")),
ecb1fcd9 1747 NewField(
d005ef04 1748 FieldUserAccess,
ecb1fcd9
JH
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,
860861f2 1761 Type: []byte{0, 0},
ecb1fcd9
JH
1762 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1763 ErrorCode: []byte{0, 0, 0, 1},
1764 Fields: []Field{
d005ef04 1765 NewField(FieldError, []byte("Cannot create account with more access than yourself.")),
ecb1fcd9
JH
1766 },
1767 },
1768 },
1769 wantErr: assert.NoError,
1770 },
481631f6
JH
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
1784func 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{
187d6dc5 1800 Access: func() accessBitmap {
481631f6 1801 var bits accessBitmap
187d6dc5 1802 return bits
481631f6
JH
1803 }(),
1804 },
1805 Server: &Server{
1806 Accounts: map[string]*Account{},
1807 },
1808 },
1809 t: NewTransaction(
d005ef04 1810 TranNewUser, &[]byte{0, 1},
481631f6
JH
1811 ),
1812 },
1813 wantRes: []Transaction{
1814 {
1815 Flags: 0x00,
1816 IsReply: 0x01,
860861f2 1817 Type: []byte{0, 0},
481631f6
JH
1818 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1819 ErrorCode: []byte{0, 0, 0, 1},
1820 Fields: []Field{
d005ef04 1821 NewField(FieldError, []byte("You are not allowed to view accounts.")),
481631f6
JH
1822 },
1823 },
1824 },
1825 wantErr: assert.NoError,
1826 },
60ec6281
JH
1827 {
1828 name: "when user has required permission",
1829 args: args{
1830 cc: &ClientConn{
1831 Account: &Account{
187d6dc5 1832 Access: func() accessBitmap {
60ec6281
JH
1833 var bits accessBitmap
1834 bits.Set(accessOpenUser)
187d6dc5 1835 return bits
60ec6281
JH
1836 }(),
1837 },
1838 Server: &Server{
1839 Accounts: map[string]*Account{
1840 "guest": {
1841 Name: "guest",
1842 Login: "guest",
1843 Password: "zz",
187d6dc5 1844 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
60ec6281
JH
1845 },
1846 },
1847 },
1848 },
1849 t: NewTransaction(
d005ef04
JH
1850 TranGetClientInfoText, &[]byte{0, 1},
1851 NewField(FieldUserID, []byte{0, 1}),
60ec6281
JH
1852 ),
1853 },
1854 wantRes: []Transaction{
1855 {
1856 Flags: 0x00,
1857 IsReply: 0x01,
945b9813 1858 Type: []byte{0, 0},
60ec6281
JH
1859 ID: []byte{0, 0, 0, 0},
1860 ErrorCode: []byte{0, 0, 0, 0},
1861 Fields: []Field{
d005ef04 1862 NewField(FieldData, []byte{
60ec6281
JH
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 },
481631f6
JH
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
1885func 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{
187d6dc5 1901 Access: func() accessBitmap {
481631f6 1902 var bits accessBitmap
187d6dc5 1903 return bits
481631f6
JH
1904 }(),
1905 },
1906 Server: &Server{},
1907 },
d005ef04 1908 t: NewTransaction(TranDownloadFile, &[]byte{0, 1}),
481631f6
JH
1909 },
1910 wantRes: []Transaction{
1911 {
1912 Flags: 0x00,
1913 IsReply: 0x01,
860861f2 1914 Type: []byte{0, 0},
481631f6
JH
1915 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1916 ErrorCode: []byte{0, 0, 0, 1},
1917 Fields: []Field{
d005ef04 1918 NewField(FieldError, []byte("You are not allowed to download files.")),
481631f6
JH
1919 },
1920 },
1921 },
1922 wantErr: assert.NoError,
1923 },
1924 {
1925 name: "with a valid file",
1926 args: args{
1927 cc: &ClientConn{
df1ade54
JH
1928 transfers: map[int]map[[4]byte]*FileTransfer{
1929 FileDownload: {},
1930 },
481631f6 1931 Account: &Account{
187d6dc5 1932 Access: func() accessBitmap {
481631f6
JH
1933 var bits accessBitmap
1934 bits.Set(accessDownloadFile)
187d6dc5 1935 return bits
481631f6
JH
1936 }(),
1937 },
1938 Server: &Server{
7cd900d6 1939 FS: &OSFileStore{},
df1ade54 1940 fileTransfers: map[[4]byte]*FileTransfer{},
481631f6
JH
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},
d005ef04
JH
1950 NewField(FieldFileName, []byte("testfile.txt")),
1951 NewField(FieldFilePath, []byte{0x0, 0x00}),
481631f6
JH
1952 ),
1953 },
1954 wantRes: []Transaction{
1955 {
1956 Flags: 0x00,
1957 IsReply: 0x01,
945b9813 1958 Type: []byte{0, 0},
481631f6
JH
1959 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1960 ErrorCode: []byte{0, 0, 0, 0},
1961 Fields: []Field{
d005ef04
JH
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}),
481631f6
JH
1966 },
1967 },
1968 },
1969 wantErr: assert.NoError,
1970 },
7cd900d6
JH
1971 {
1972 name: "when client requests to resume 1k test file at offset 256",
1973 args: args{
1974 cc: &ClientConn{
df1ade54
JH
1975 transfers: map[int]map[[4]byte]*FileTransfer{
1976 FileDownload: {},
1977 }, Account: &Account{
187d6dc5 1978 Access: func() accessBitmap {
7cd900d6
JH
1979 var bits accessBitmap
1980 bits.Set(accessDownloadFile)
187d6dc5 1981 return bits
7cd900d6
JH
1982 }(),
1983 },
1984 Server: &Server{
1985 FS: &OSFileStore{},
df1ade54 1986
7cd900d6
JH
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 // }(),
df1ade54 2004 fileTransfers: map[[4]byte]*FileTransfer{},
7cd900d6
JH
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},
d005ef04
JH
2014 NewField(FieldFileName, []byte("testfile-1k")),
2015 NewField(FieldFilePath, []byte{0x00, 0x00}),
7cd900d6 2016 NewField(
d005ef04 2017 FieldFileResumeData,
7cd900d6
JH
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,
945b9813 2049 Type: []byte{0, 0},
7cd900d6
JH
2050 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2051 ErrorCode: []byte{0, 0, 0, 0},
2052 Fields: []Field{
d005ef04
JH
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}),
7cd900d6
JH
2057 },
2058 },
2059 },
2060 wantErr: assert.NoError,
2061 },
481631f6
JH
2062 }
2063 for _, tt := range tests {
2064 t.Run(tt.name, func(t *testing.T) {
481631f6
JH
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}
d2810ae9
JH
2074
2075func 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{
02b446d8 2090 logger: NewTestLogger(),
d2810ae9
JH
2091 Server: &Server{
2092 Logger: NewTestLogger(),
2093 },
2094 Account: &Account{
187d6dc5 2095 Access: func() accessBitmap {
d2810ae9 2096 var bits accessBitmap
187d6dc5 2097 return bits
d2810ae9
JH
2098 }(),
2099 },
2100 },
2101 t: NewTransaction(
d005ef04 2102 TranUpdateUser,
d2810ae9 2103 &[]byte{0, 0},
d005ef04 2104 NewField(FieldData, []byte{
d2810ae9
JH
2105 0x00, 0x04, // field count
2106
d005ef04 2107 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
2108 0x00, 0x03,
2109 0x9d, 0x9d, 0x9d,
2110
d005ef04 2111 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
2112 0x00, 0x03,
2113 0x9c, 0x9c, 0x9c,
2114
d005ef04 2115 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
2116 0x00, 0x03,
2117 0x61, 0x61, 0x61,
2118
d005ef04 2119 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
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,
860861f2 2129 Type: []byte{0, 0},
d2810ae9
JH
2130 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2131 ErrorCode: []byte{0, 0, 0, 1},
2132 Fields: []Field{
d005ef04 2133 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
d2810ae9
JH
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{
02b446d8 2143 logger: NewTestLogger(),
d2810ae9
JH
2144 Server: &Server{
2145 Logger: NewTestLogger(),
2146 Accounts: map[string]*Account{
2147 "bbb": {},
2148 },
2149 },
2150 Account: &Account{
187d6dc5 2151 Access: func() accessBitmap {
d2810ae9 2152 var bits accessBitmap
187d6dc5 2153 return bits
d2810ae9
JH
2154 }(),
2155 },
2156 },
2157 t: NewTransaction(
d005ef04 2158 TranUpdateUser,
d2810ae9 2159 &[]byte{0, 0},
d005ef04 2160 NewField(FieldData, []byte{
d2810ae9
JH
2161 0x00, 0x04, // field count
2162
d005ef04 2163 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
2164 0x00, 0x03,
2165 0x9d, 0x9d, 0x9d,
2166
d005ef04 2167 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
2168 0x00, 0x03,
2169 0x9c, 0x9c, 0x9c,
2170
d005ef04 2171 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
2172 0x00, 0x03,
2173 0x61, 0x61, 0x61,
2174
d005ef04 2175 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
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,
860861f2 2185 Type: []byte{0, 0},
d2810ae9
JH
2186 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2187 ErrorCode: []byte{0, 0, 0, 1},
2188 Fields: []Field{
d005ef04 2189 NewField(FieldError, []byte("You are not allowed to modify accounts.")),
d2810ae9
JH
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{
02b446d8 2199 logger: NewTestLogger(),
d2810ae9 2200 Server: &Server{
d2810ae9
JH
2201 Accounts: map[string]*Account{
2202 "bbb": {},
2203 },
2204 },
2205 Account: &Account{
187d6dc5 2206 Access: func() accessBitmap {
d2810ae9 2207 var bits accessBitmap
187d6dc5 2208 return bits
d2810ae9
JH
2209 }(),
2210 },
2211 },
2212 t: NewTransaction(
d005ef04 2213 TranUpdateUser,
d2810ae9 2214 &[]byte{0, 0},
d005ef04 2215 NewField(FieldData, []byte{
d2810ae9
JH
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,
860861f2 2227 Type: []byte{0, 0},
d2810ae9
JH
2228 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2229 ErrorCode: []byte{0, 0, 0, 1},
2230 Fields: []Field{
d005ef04 2231 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
d2810ae9
JH
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}
d4c152a4
JH
2249
2250func 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{
187d6dc5 2266 Access: func() accessBitmap {
d4c152a4 2267 var bits accessBitmap
187d6dc5 2268 return bits
d4c152a4
JH
2269 }(),
2270 },
2271 },
2272 t: NewTransaction(
d005ef04 2273 TranDelNewsArt,
d4c152a4
JH
2274 &[]byte{0, 0},
2275 ),
2276 },
2277 wantRes: []Transaction{
2278 {
2279 Flags: 0x00,
2280 IsReply: 0x01,
860861f2 2281 Type: []byte{0, 0},
d4c152a4
JH
2282 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2283 ErrorCode: []byte{0, 0, 0, 1},
2284 Fields: []Field{
d005ef04 2285 NewField(FieldError, []byte("You are not allowed to delete news articles.")),
d4c152a4
JH
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
2303func 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{
187d6dc5 2319 Access: func() accessBitmap {
d4c152a4 2320 var bits accessBitmap
187d6dc5 2321 return bits
d4c152a4
JH
2322 }(),
2323 },
2324 },
2325 t: NewTransaction(
d005ef04 2326 TranDelNewsArt,
d4c152a4
JH
2327 &[]byte{0, 0},
2328 ),
2329 },
2330 wantRes: []Transaction{
2331 {
2332 Flags: 0x00,
2333 IsReply: 0x01,
860861f2 2334 Type: []byte{0, 0},
d4c152a4
JH
2335 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2336 ErrorCode: []byte{0, 0, 0, 1},
2337 Fields: []Field{
d005ef04 2338 NewField(FieldError, []byte("You are not allowed to disconnect users.")),
d4c152a4
JH
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",
187d6dc5 2353 Access: func() accessBitmap {
d4c152a4
JH
2354 var bits accessBitmap
2355 bits.Set(accessCannotBeDiscon)
187d6dc5 2356 return bits
d4c152a4
JH
2357 }(),
2358 },
2359 },
2360 },
2361 },
2362 Account: &Account{
187d6dc5 2363 Access: func() accessBitmap {
d4c152a4
JH
2364 var bits accessBitmap
2365 bits.Set(accessDisconUser)
187d6dc5 2366 return bits
d4c152a4
JH
2367 }(),
2368 },
2369 },
2370 t: NewTransaction(
d005ef04 2371 TranDelNewsArt,
d4c152a4 2372 &[]byte{0, 0},
d005ef04 2373 NewField(FieldUserID, []byte{0, 1}),
d4c152a4
JH
2374 ),
2375 },
2376 wantRes: []Transaction{
2377 {
2378 Flags: 0x00,
2379 IsReply: 0x01,
860861f2 2380 Type: []byte{0, 0},
d4c152a4
JH
2381 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2382 ErrorCode: []byte{0, 0, 0, 1},
2383 Fields: []Field{
d005ef04 2384 NewField(FieldError, []byte("unnamed is not allowed to be disconnected.")),
d4c152a4
JH
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}
aeec1015
JH
2401
2402func 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 }{
69c2fb50
JH
2413 {
2414 name: "without required permission",
2415 args: args{
2416 cc: &ClientConn{
2417 Account: &Account{
187d6dc5 2418 Access: func() accessBitmap {
69c2fb50 2419 var bits accessBitmap
187d6dc5 2420 return bits
69c2fb50
JH
2421 }(),
2422 },
2423 },
2424 t: NewTransaction(
d005ef04 2425 TranDelNewsArt,
69c2fb50
JH
2426 &[]byte{0, 0},
2427 ),
2428 },
2429 wantRes: []Transaction{
2430 {
2431 Flags: 0x00,
2432 IsReply: 0x01,
860861f2 2433 Type: []byte{0, 0},
69c2fb50
JH
2434 ID: []byte{0, 0, 0, 0},
2435 ErrorCode: []byte{0, 0, 0, 1},
2436 Fields: []Field{
d005ef04 2437 NewField(FieldError, []byte("You are not allowed to send private messages.")),
69c2fb50
JH
2438 },
2439 },
2440 },
2441 wantErr: assert.NoError,
2442 },
aeec1015
JH
2443 {
2444 name: "when client 1 sends a message to client 2",
2445 args: args{
2446 cc: &ClientConn{
69c2fb50 2447 Account: &Account{
187d6dc5 2448 Access: func() accessBitmap {
69c2fb50
JH
2449 var bits accessBitmap
2450 bits.Set(accessSendPrivMsg)
187d6dc5 2451 return bits
69c2fb50
JH
2452 }(),
2453 },
aeec1015
JH
2454 ID: &[]byte{0, 1},
2455 UserName: []byte("User1"),
2456 Server: &Server{
2457 Clients: map[uint16]*ClientConn{
2458 uint16(2): {
2459 AutoReply: []byte(nil),
38f710ec 2460 Flags: []byte{0, 0},
aeec1015
JH
2461 },
2462 },
2463 },
2464 },
2465 t: NewTransaction(
d005ef04 2466 TranSendInstantMsg,
aeec1015 2467 &[]byte{0, 1},
d005ef04
JH
2468 NewField(FieldData, []byte("hai")),
2469 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2470 ),
2471 },
2472 wantRes: []Transaction{
2473 *NewTransaction(
d005ef04 2474 TranServerMsg,
aeec1015 2475 &[]byte{0, 2},
d005ef04
JH
2476 NewField(FieldData, []byte("hai")),
2477 NewField(FieldUserName, []byte("User1")),
2478 NewField(FieldUserID, []byte{0, 1}),
2479 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2480 ),
2481 {
2482 clientID: &[]byte{0, 1},
2483 Flags: 0x00,
2484 IsReply: 0x01,
945b9813 2485 Type: []byte{0, 0},
aeec1015
JH
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{
69c2fb50 2497 Account: &Account{
187d6dc5 2498 Access: func() accessBitmap {
69c2fb50
JH
2499 var bits accessBitmap
2500 bits.Set(accessSendPrivMsg)
187d6dc5 2501 return bits
69c2fb50
JH
2502 }(),
2503 },
aeec1015
JH
2504 ID: &[]byte{0, 1},
2505 UserName: []byte("User1"),
2506 Server: &Server{
2507 Clients: map[uint16]*ClientConn{
2508 uint16(2): {
38f710ec 2509 Flags: []byte{0, 0},
aeec1015
JH
2510 ID: &[]byte{0, 2},
2511 UserName: []byte("User2"),
2512 AutoReply: []byte("autohai"),
2513 },
2514 },
2515 },
2516 },
2517 t: NewTransaction(
d005ef04 2518 TranSendInstantMsg,
aeec1015 2519 &[]byte{0, 1},
d005ef04
JH
2520 NewField(FieldData, []byte("hai")),
2521 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2522 ),
2523 },
2524 wantRes: []Transaction{
2525 *NewTransaction(
d005ef04 2526 TranServerMsg,
aeec1015 2527 &[]byte{0, 2},
d005ef04
JH
2528 NewField(FieldData, []byte("hai")),
2529 NewField(FieldUserName, []byte("User1")),
2530 NewField(FieldUserID, []byte{0, 1}),
2531 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2532 ),
2533 *NewTransaction(
d005ef04 2534 TranServerMsg,
aeec1015 2535 &[]byte{0, 1},
d005ef04
JH
2536 NewField(FieldData, []byte("autohai")),
2537 NewField(FieldUserName, []byte("User2")),
2538 NewField(FieldUserID, []byte{0, 2}),
2539 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2540 ),
2541 {
2542 clientID: &[]byte{0, 1},
2543 Flags: 0x00,
2544 IsReply: 0x01,
945b9813 2545 Type: []byte{0, 0},
aeec1015
JH
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 },
38f710ec
JH
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(
d005ef04 2577 TranSendInstantMsg,
38f710ec 2578 &[]byte{0, 1},
d005ef04
JH
2579 NewField(FieldData, []byte("hai")),
2580 NewField(FieldUserID, []byte{0, 2}),
38f710ec
JH
2581 ),
2582 },
2583 wantRes: []Transaction{
2584 *NewTransaction(
d005ef04 2585 TranServerMsg,
38f710ec 2586 &[]byte{0, 1},
d005ef04
JH
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}),
38f710ec
JH
2591 ),
2592 {
2593 clientID: &[]byte{0, 1},
2594 Flags: 0x00,
2595 IsReply: 0x01,
945b9813 2596 Type: []byte{0, 0},
38f710ec
JH
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 },
aeec1015
JH
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}
7cd900d6
JH
2616
2617func 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{
187d6dc5 2633 Access: func() accessBitmap {
7cd900d6 2634 var bits accessBitmap
187d6dc5 2635 return bits
7cd900d6
JH
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(
d005ef04
JH
2663 TranDeleteFile, &[]byte{0, 1},
2664 NewField(FieldFileName, []byte("testfile")),
2665 NewField(FieldFilePath, []byte{
7cd900d6
JH
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,
860861f2 2677 Type: []byte{0, 0},
7cd900d6
JH
2678 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2679 ErrorCode: []byte{0, 0, 0, 1},
2680 Fields: []Field{
d005ef04 2681 NewField(FieldError, []byte("You are not allowed to delete files.")),
7cd900d6
JH
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{
187d6dc5 2692 Access: func() accessBitmap {
7cd900d6
JH
2693 var bits accessBitmap
2694 bits.Set(accessDeleteFile)
187d6dc5 2695 return bits
7cd900d6
JH
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(
d005ef04
JH
2728 TranDeleteFile, &[]byte{0, 1},
2729 NewField(FieldFileName, []byte("testfile")),
2730 NewField(FieldFilePath, []byte{
7cd900d6
JH
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,
945b9813 2742 Type: []byte{0, 0},
7cd900d6
JH
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}
2e08be58
JH
2764
2765func 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 {
d005ef04 2777 name: "when FieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2e08be58
JH
2778 args: args{
2779 cc: &ClientConn{
2780 Account: &Account{
187d6dc5 2781 Access: func() accessBitmap {
2e08be58 2782 var bits accessBitmap
187d6dc5 2783 return bits
2e08be58
JH
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(
d005ef04
JH
2797 TranGetFileNameList, &[]byte{0, 1},
2798 NewField(FieldFilePath, []byte{
2e08be58
JH
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,
860861f2 2810 Type: []byte{0, 0},
2e08be58
JH
2811 ID: []byte{0, 0, 0, 0},
2812 ErrorCode: []byte{0, 0, 0, 1},
2813 Fields: []Field{
d005ef04 2814 NewField(FieldError, []byte("You are not allowed to view drop boxes.")),
2e08be58
JH
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(
d005ef04
JH
2834 TranGetFileNameList, &[]byte{0, 1},
2835 NewField(FieldFilePath, []byte{
2e08be58
JH
2836 0x00, 0x00,
2837 0x00, 0x00,
2838 }),
2839 ),
2840 },
2841 wantRes: []Transaction{
2842 {
2843 Flags: 0x00,
2844 IsReply: 0x01,
945b9813 2845 Type: []byte{0, 0},
2e08be58
JH
2846 ID: []byte{0, 0, 0, 0},
2847 ErrorCode: []byte{0, 0, 0, 0},
2848 Fields: []Field{
2849 NewField(
d005ef04 2850 FieldFileNameWithInfo,
2e08be58
JH
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}
df1ade54
JH
2884
2885func 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{
187d6dc5 2901 Access: func() accessBitmap {
df1ade54 2902 var bits accessBitmap
187d6dc5 2903 return bits
df1ade54
JH
2904 }(),
2905 },
2906 Server: &Server{
2907 Accounts: map[string]*Account{},
2908 },
2909 },
2910 t: NewTransaction(
d005ef04
JH
2911 TranGetClientInfoText, &[]byte{0, 1},
2912 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2913 ),
2914 },
2915 wantRes: []Transaction{
2916 {
2917 Flags: 0x00,
2918 IsReply: 0x01,
860861f2 2919 Type: []byte{0, 0},
df1ade54
JH
2920 ID: []byte{0, 0, 0, 0},
2921 ErrorCode: []byte{0, 0, 0, 1},
2922 Fields: []Field{
d005ef04 2923 NewField(FieldError, []byte("You are not allowed to get client info.")),
df1ade54
JH
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{
187d6dc5 2936 Access: func() accessBitmap {
df1ade54
JH
2937 var bits accessBitmap
2938 bits.Set(accessGetClientInfo)
187d6dc5 2939 return bits
df1ade54
JH
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{
187d6dc5 2951 Access: func() accessBitmap {
df1ade54
JH
2952 var bits accessBitmap
2953 bits.Set(accessGetClientInfo)
187d6dc5 2954 return bits
df1ade54
JH
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(
d005ef04
JH
2970 TranGetClientInfoText, &[]byte{0, 1},
2971 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2972 ),
2973 },
2974 wantRes: []Transaction{
2975 {
2976 Flags: 0x00,
2977 IsReply: 0x01,
945b9813 2978 Type: []byte{0, 0},
df1ade54
JH
2979 ID: []byte{0, 0, 0, 0},
2980 ErrorCode: []byte{0, 0, 0, 0},
2981 Fields: []Field{
d005ef04 2982 NewField(FieldData, []byte(
c8bfd606 2983 strings.ReplaceAll(`Nickname: Testy McTest
df1ade54
JH
2984Name: test
2985Account: test
2986Address: 1.2.3.4:12345
2987
2988-------- File Downloads ---------
2989
2990None.
2991
2992------- Folder Downloads --------
2993
2994None.
2995
2996--------- File Uploads ----------
2997
2998None.
2999
3000-------- Folder Uploads ---------
3001
3002None.
3003
3004------- Waiting Downloads -------
3005
3006None.
3007
c8bfd606 3008`, "\n", "\r")),
df1ade54 3009 ),
d005ef04 3010 NewField(FieldUserName, []byte("Testy McTest")),
df1ade54
JH
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}
ea5d8c51
JH
3027
3028func 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{
187d6dc5 3044 Access: func() accessBitmap {
ea5d8c51
JH
3045 var bits accessBitmap
3046 bits.Set(accessDisconUser)
3047 bits.Set(accessAnyName)
187d6dc5 3048 return bits
ea5d8c51 3049 }()},
a7216f67
JH
3050 Icon: []byte{0, 1},
3051 Flags: []byte{0, 1},
3052 Version: []byte{0, 1},
ea5d8c51
JH
3053 ID: &[]byte{0, 1},
3054 logger: NewTestLogger(),
3055 Server: &Server{
3056 Config: &Config{
3057 BannerFile: "banner.jpg",
3058 },
3059 },
3060 },
3061 t: NewTransaction(
d005ef04
JH
3062 TranAgreed, nil,
3063 NewField(FieldUserName, []byte("username")),
3064 NewField(FieldUserIconID, []byte{0, 1}),
3065 NewField(FieldOptions, []byte{0, 0}),
ea5d8c51
JH
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{
d005ef04 3077 NewField(FieldBannerType, []byte("JPEG")),
ea5d8c51
JH
3078 },
3079 },
3080 {
3081 clientID: &[]byte{0, 1},
3082 Flags: 0x00,
3083 IsReply: 0x01,
945b9813 3084 Type: []byte{0, 0},
ea5d8c51
JH
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}
264b7c27
JH
3103
3104func 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{
187d6dc5 3120 Access: func() accessBitmap {
264b7c27 3121 var bits accessBitmap
187d6dc5 3122 return bits
264b7c27
JH
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(
d005ef04
JH
3137 TranSetClientUserInfo, nil,
3138 NewField(FieldUserIconID, []byte{0, 1}),
3139 NewField(FieldUserName, []byte("NOPE")),
264b7c27
JH
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{
d005ef04
JH
3151 NewField(FieldUserID, []byte{0, 1}),
3152 NewField(FieldUserIconID, []byte{0, 1}),
3153 NewField(FieldUserFlags, []byte{0, 1}),
3154 NewField(FieldUserName, []byte("Guest"))},
264b7c27
JH
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}
8eb43f95
JH
3171
3172func 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(
d005ef04
JH
3203 TranDelNewsItem, nil,
3204 NewField(FieldNewsPath,
8eb43f95
JH
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,
860861f2 3219 Type: []byte{0, 0},
8eb43f95
JH
3220 ID: []byte{0, 0, 0, 0},
3221 ErrorCode: []byte{0, 0, 0, 1},
3222 Fields: []Field{
d005ef04 3223 NewField(FieldError, []byte("You are not allowed to delete news categories.")),
8eb43f95
JH
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(
d005ef04
JH
3249 TranDelNewsItem, nil,
3250 NewField(FieldNewsPath,
8eb43f95
JH
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,
860861f2 3265 Type: []byte{0, 0},
8eb43f95
JH
3266 ID: []byte{0, 0, 0, 0},
3267 ErrorCode: []byte{0, 0, 0, 1},
3268 Fields: []Field{
d005ef04 3269 NewField(FieldError, []byte("You are not allowed to delete news folders.")),
8eb43f95
JH
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(
d005ef04
JH
3305 TranDelNewsItem, nil,
3306 NewField(FieldNewsPath,
8eb43f95
JH
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,
945b9813 3321 Type: []byte{0, 0},
8eb43f95
JH
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}
969e6481
JH
3340
3341func 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 },
d005ef04 3376 t: NewTransaction(TranDownloadBanner, nil),
969e6481
JH
3377 },
3378 wantRes: []Transaction{
3379 {
3380 clientID: &[]byte{0, 1},
3381 Flags: 0x00,
3382 IsReply: 0x01,
945b9813 3383 Type: []byte{0, 0},
969e6481
JH
3384 ID: []byte{0, 0, 0, 0},
3385 ErrorCode: []byte{0, 0, 0, 0},
3386 Fields: []Field{
d005ef04
JH
3387 NewField(FieldRefNum, []byte{1, 2, 3, 4}),
3388 NewField(FieldTransferSize, []byte{0, 0, 0, 0x64}),
969e6481
JH
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}
8a1512f9
JH
3406
3407func 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(
d005ef04
JH
3430 TranOldPostNews, &[]byte{0, 1},
3431 NewField(FieldData, []byte("hai")),
8a1512f9
JH
3432 ),
3433 },
3434 wantRes: []Transaction{
3435 {
3436 Flags: 0x00,
3437 IsReply: 0x01,
860861f2 3438 Type: []byte{0, 0},
8a1512f9
JH
3439 ID: []byte{0, 0, 0, 0},
3440 ErrorCode: []byte{0, 0, 0, 1},
3441 Fields: []Field{
d005ef04 3442 NewField(FieldError, []byte("You are not allowed to post news.")),
8a1512f9
JH
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(
d005ef04
JH
3470 TranOldPostNews, &[]byte{0, 1},
3471 NewField(FieldData, []byte("hai")),
8a1512f9
JH
3472 ),
3473 },
3474 wantRes: []Transaction{
3475 {
3476 Flags: 0x00,
3477 IsReply: 0x01,
945b9813 3478 Type: []byte{0, 0},
8a1512f9
JH
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}
c1c44744
JH
3497
3498func 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 },
d005ef04 3520 t: NewTransaction(TranInviteNewChat, &[]byte{0, 1}),
c1c44744
JH
3521 },
3522 wantRes: []Transaction{
3523 {
3524 Flags: 0x00,
3525 IsReply: 0x01,
860861f2 3526 Type: []byte{0, 0},
c1c44744
JH
3527 ID: []byte{0, 0, 0, 0},
3528 ErrorCode: []byte{0, 0, 0, 1},
3529 Fields: []Field{
d005ef04 3530 NewField(FieldError, []byte("You are not allowed to request private chat.")),
c1c44744
JH
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(
d005ef04
JH
3563 TranInviteNewChat, &[]byte{0, 1},
3564 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
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{
d005ef04
JH
3576 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3577 NewField(FieldUserName, []byte("UserA")),
3578 NewField(FieldUserID, []byte{0, 1}),
c1c44744
JH
3579 },
3580 },
3581
3582 {
3583 clientID: &[]byte{0, 1},
3584 Flags: 0x00,
3585 IsReply: 0x01,
945b9813 3586 Type: []byte{0, 0},
c1c44744
JH
3587 ID: []byte{0, 0, 0, 0},
3588 ErrorCode: []byte{0, 0, 0, 0},
3589 Fields: []Field{
d005ef04
JH
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}),
c1c44744
JH
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(
d005ef04
JH
3627 TranInviteNewChat, &[]byte{0, 1},
3628 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
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{
d005ef04
JH
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}),
c1c44744
JH
3644 },
3645 },
3646 {
3647 clientID: &[]byte{0, 1},
3648 Flags: 0x00,
3649 IsReply: 0x01,
945b9813 3650 Type: []byte{0, 0},
c1c44744
JH
3651 ID: []byte{0, 0, 0, 0},
3652 ErrorCode: []byte{0, 0, 0, 0},
3653 Fields: []Field{
d005ef04
JH
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}),
c1c44744
JH
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}
33265393
JH
3676
3677func 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(
d005ef04 3703 TranGetNewsArtData, &[]byte{0, 1},
33265393
JH
3704 ),
3705 },
3706 wantRes: []Transaction{
3707 {
3708 Flags: 0x00,
3709 IsReply: 0x01,
860861f2 3710 Type: []byte{0, 0},
33265393
JH
3711 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
3712 ErrorCode: []byte{0, 0, 0, 1},
3713 Fields: []Field{
d005ef04 3714 NewField(FieldError, []byte("You are not allowed to read news.")),
33265393
JH
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}
860861f2
JH
3731
3732func 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(
d005ef04 3758 TranGetNewsArtNameList, &[]byte{0, 1},
860861f2
JH
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{
d005ef04 3768 NewField(FieldError, []byte("You are not allowed to read news.")),
860861f2
JH
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)
860861f2
JH
3782 })
3783 }
3784}
3785
3786func 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(
d005ef04 3812 TranGetNewsArtNameList, &[]byte{0, 1},
860861f2
JH
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{
d005ef04 3822 NewField(FieldError, []byte("You are not allowed to create news folders.")),
860861f2
JH
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(
d005ef04
JH
3860 TranGetNewsArtNameList, &[]byte{0, 1},
3861 NewField(FieldFileName, []byte("testFolder")),
3862 NewField(FieldNewsPath,
860861f2
JH
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(
d005ef04
JH
3917 // TranGetNewsArtNameList, &[]byte{0, 1},
3918 // NewField(FieldFileName, []byte("testFolder")),
3919 // NewField(FieldNewsPath,
860861f2
JH
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{
d005ef04 3937 // NewField(FieldError, []byte("Error creating news folder.")),
860861f2
JH
3938 // },
3939 // },
3940 // },
3941 // wantErr: assert.Error,
aeb97482 3942 // },
860861f2
JH
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}