1 package rulesengine
2
3 import (
4 "context"
5 "fmt"
6 "testing"
7
8 "github.com/stretchr/testify/assert"
9 )
10
11 var commandNames = []Command{
12 {Name: "a"},
13 {Name: "b"},
14 {Name: "c"},
15 }
16
17 var privilegeNames = []Privilege{
18 {Name: "a"},
19 {Name: "b"},
20 {Name: "c"},
21 }
22
23 func TestSplitPostDefaultRulesToRuleSegment(t *testing.T) {
24 t.Parallel()
25
26 tests := map[string]struct {
27 rules WriteRules
28 exp []RuleSegment
29 }{
30 "One Rule": {
31 rules: WriteRules{
32 {
33 Command: commandNames[0].Name,
34 Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name},
35 },
36 },
37 exp: []RuleSegment{
38 {Command: commandNames[0], Privilege: privilegeNames[0]},
39 {Command: commandNames[0], Privilege: privilegeNames[1]},
40 },
41 },
42 "Multiple Rules": {
43 rules: WriteRules{
44 {
45 Command: commandNames[0].Name,
46 Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name},
47 },
48 {
49 Command: commandNames[1].Name,
50 Privileges: []string{privilegeNames[1].Name, privilegeNames[2].Name},
51 },
52 {
53 Command: commandNames[2].Name,
54 Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name, privilegeNames[2].Name},
55 },
56 },
57 exp: []RuleSegment{
58 {Command: commandNames[0], Privilege: privilegeNames[0]},
59 {Command: commandNames[0], Privilege: privilegeNames[1]},
60 {Command: commandNames[1], Privilege: privilegeNames[1]},
61 {Command: commandNames[1], Privilege: privilegeNames[2]},
62 {Command: commandNames[2], Privilege: privilegeNames[0]},
63 {Command: commandNames[2], Privilege: privilegeNames[1]},
64 {Command: commandNames[2], Privilege: privilegeNames[2]},
65 },
66 },
67 }
68
69 for name, tc := range tests {
70 tc := tc
71 t.Run(name, func(t *testing.T) {
72 t.Parallel()
73
74 segments := splitPostDefaultRulesToRuleSegment(tc.rules)
75 assert.Equal(t, tc.exp, segments)
76 })
77 }
78 }
79
80 func TestAssembleRules(t *testing.T) {
81 tests := map[string]struct {
82 ruleSegments []RuleSegment
83 expectedRes []Rule
84 }{
85 "2 privs 2 commands": {
86 ruleSegments: []RuleSegment{
87 {
88 Command: Command{
89 Name: "com1",
90 ID: "comID1"},
91 Privilege: Privilege{
92 Name: "priv1",
93 ID: "privID1",
94 },
95 },
96 {
97 Command: Command{
98 Name: "com1",
99 ID: "comID1"},
100 Privilege: Privilege{
101 Name: "priv2",
102 ID: "privID2",
103 },
104 },
105 {
106 Command: Command{
107 Name: "com2",
108 ID: "comID2"},
109 Privilege: Privilege{
110 Name: "priv3",
111 ID: "privID3",
112 },
113 },
114 },
115 expectedRes: []Rule{
116 {
117 Command: Command{Name: "com1", ID: "comID1"},
118 Privileges: []Privilege{{Name: "priv1", ID: "privID1"}, {Name: "priv2", ID: "privID2"}},
119 },
120 {
121 Command: Command{Name: "com2", ID: "comID2"},
122 Privileges: []Privilege{{Name: "priv3", ID: "privID3"}},
123 },
124 },
125 },
126 "Banner ignored": {
127 ruleSegments: []RuleSegment{
128 {
129 Banner: Banner{BannerName: "bannername", BannerID: "bannerID"},
130 Command: Command{
131 Name: "com1",
132 ID: "comID1"},
133 Privilege: Privilege{
134 Name: "priv1",
135 ID: "privID1",
136 },
137 },
138 },
139 expectedRes: []Rule{
140 {
141 Command: Command{Name: "com1", ID: "comID1"},
142 Privileges: []Privilege{{Name: "priv1", ID: "privID1"}},
143 }},
144 },
145 }
146 for name, tc := range tests {
147 t.Run(name, func(t *testing.T) {
148 assert.EqualValues(t, tc.expectedRes, assembleRules(tc.ruleSegments))
149 })
150 }
151 }
152
153 type mockDefaultRulesDS struct {
154 addDefaultRulesFunc func(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error)
155 readDefaultRulesFunc func(ctx context.Context) ([]RuleSegment, error)
156 Dataset
157 }
158
159 func (m *mockDefaultRulesDS) AddDefaultRules(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) {
160 if m.addDefaultRulesFunc != nil {
161 return m.addDefaultRulesFunc(ctx, ruleSegments)
162 }
163 return AddRuleResult{}, fmt.Errorf("AddDefaultRules not implemented")
164 }
165
166 func (m *mockDefaultRulesDS) ReadAllDefaultRules(ctx context.Context) ([]RuleSegment, error) {
167 if m.readDefaultRulesFunc != nil {
168 return m.readDefaultRulesFunc(ctx)
169 }
170 return nil, fmt.Errorf("ReadDefaultRules not implemented")
171 }
172
173 func newMockDefaultRulesDS(addDefaultRulesFunc func(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error),
174 readDefaultRulesFunc func(ctx context.Context) ([]RuleSegment, error)) *mockDefaultRulesDS {
175 return &mockDefaultRulesDS{
176 addDefaultRulesFunc: addDefaultRulesFunc,
177 readDefaultRulesFunc: readDefaultRulesFunc,
178 }
179 }
180
181 type helper interface {
182 Helper()
183 }
184
185 func ErrorEqualMsg(message string) assert.ErrorAssertionFunc {
186 return func(t assert.TestingT, err error, i ...interface{}) bool {
187 if tt, ok := t.(helper); ok {
188 tt.Helper()
189 }
190
191 return assert.EqualError(t, err, message, i...)
192 }
193 }
194
195 func TestAddDefaultRulesForPrivileges(t *testing.T) {
196 t.Parallel()
197 tests := map[string]struct {
198 data []RuleSet
199 expectedRules []RuleSegment
200 assertErr assert.ErrorAssertionFunc
201 }{
202 "Single Privilege, Single Command": {
203 data: []RuleSet{
204 {
205 Privilege: "privilege1",
206 Commands: []string{"command1"},
207 },
208 },
209 expectedRules: []RuleSegment{
210 {
211 Command: Command{Name: "command1"},
212 Privilege: Privilege{Name: "privilege1"},
213 },
214 },
215 assertErr: assert.NoError,
216 },
217 "Single Privilege, Multiple Commands": {
218 data: []RuleSet{
219 {
220 Privilege: "privilege1",
221 Commands: []string{"command1", "command2"},
222 },
223 },
224 expectedRules: []RuleSegment{
225 {
226 Command: Command{Name: "command1"},
227 Privilege: Privilege{Name: "privilege1"},
228 },
229 {
230 Command: Command{Name: "command2"},
231 Privilege: Privilege{Name: "privilege1"},
232 },
233 },
234 assertErr: assert.NoError,
235 },
236 "Multiple Privileges, Single Command": {
237 data: []RuleSet{
238 {
239 Privilege: "privilege1",
240 Commands: []string{"command1"},
241 },
242 {
243 Privilege: "privilege2",
244 Commands: []string{"command1"},
245 },
246 },
247 expectedRules: []RuleSegment{
248 {
249 Command: Command{Name: "command1"},
250 Privilege: Privilege{Name: "privilege1"},
251 },
252 {
253 Command: Command{Name: "command1"},
254 Privilege: Privilege{Name: "privilege2"},
255 },
256 },
257 assertErr: assert.NoError,
258 },
259 "Multiple Privileges, Multiple Commands": {
260 data: []RuleSet{
261 {
262 Privilege: "privilege1",
263 Commands: []string{"command1", "command2"},
264 },
265 {
266 Privilege: "privilege2",
267 Commands: []string{"command3"},
268 },
269 },
270 expectedRules: []RuleSegment{
271 {
272 Command: Command{Name: "command1"},
273 Privilege: Privilege{Name: "privilege1"},
274 },
275 {
276 Command: Command{Name: "command2"},
277 Privilege: Privilege{Name: "privilege1"},
278 },
279 {
280 Command: Command{Name: "command3"},
281 Privilege: Privilege{Name: "privilege2"},
282 },
283 },
284 assertErr: assert.NoError,
285 },
286 "No Privileges": {
287 data: []RuleSet{},
288 expectedRules: []RuleSegment{},
289 assertErr: ErrorEqualMsg("empty rules list"),
290 },
291 }
292
293 for name, tc := range tests {
294 tc := tc
295 t.Run(name, func(t *testing.T) {
296 t.Parallel()
297 ctx := context.Background()
298
299
300 reng := RulesEngine{}
301
302
303 reng.ds = newMockDefaultRulesDS(func(_ context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) {
304
305 assert.ElementsMatch(t, tc.expectedRules, ruleSegments)
306 return AddRuleResult{}, nil
307 }, nil)
308
309
310 _, err := reng.AddDefaultRulesForPrivileges(ctx, tc.data)
311
312
313 tc.assertErr(t, err)
314 })
315 }
316 }
317
318 func TestGetDefaultRules(t *testing.T) {
319 t.Parallel()
320 tests := map[string]struct {
321 privilegeNames []string
322 defaultRules []RuleSegment
323 expectedRules []ReturnRuleSet
324 expectedErr error
325 }{
326 "Existing Privilege": {
327 privilegeNames: []string{"privilege1"},
328 defaultRules: []RuleSegment{
329 {
330 Command: Command{Name: "command1", ID: "commandID1"},
331 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
332 },
333 {
334 Command: Command{Name: "command2", ID: "commandID2"},
335 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
336 },
337 },
338 expectedRules: []ReturnRuleSet{
339 {
340 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
341 Commands: []Command{
342 {Name: "command1", ID: "commandID1"},
343 {Name: "command2", ID: "commandID2"},
344 },
345 },
346 },
347 expectedErr: nil,
348 },
349 "Non-Existing Privilege": {
350 privilegeNames: []string{"privilege2"},
351 defaultRules: []RuleSegment{
352 {
353 Command: Command{Name: "command1", ID: "commandID1"},
354 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
355 },
356 {
357 Command: Command{Name: "command2", ID: "commandID2"},
358 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
359 },
360 },
361 expectedRules: []ReturnRuleSet{},
362 expectedErr: nil,
363 },
364 "Empty Default Rules": {
365 privilegeNames: []string{"privilege1"},
366 defaultRules: []RuleSegment{},
367 expectedRules: []ReturnRuleSet{},
368 expectedErr: nil,
369 },
370 "Error Reading Default Rules": {
371 privilegeNames: []string{"privilege1"},
372 defaultRules: nil,
373 expectedRules: []ReturnRuleSet{},
374 expectedErr: fmt.Errorf("error when reading all default rules: some error"),
375 },
376 "No Privilege Names": {
377 privilegeNames: []string{},
378 defaultRules: []RuleSegment{
379 {
380 Command: Command{Name: "command1", ID: "commandID1"},
381 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
382 },
383 {
384 Command: Command{Name: "command2", ID: "commandID2"},
385 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
386 },
387 },
388 expectedRules: []ReturnRuleSet{
389 {
390 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
391 Commands: []Command{
392 {Name: "command1", ID: "commandID1"},
393 {Name: "command2", ID: "commandID2"},
394 },
395 },
396 },
397 expectedErr: nil,
398 },
399 "Multiple privilege Names": {
400 privilegeNames: []string{"privilege1", "privilege2"},
401 defaultRules: []RuleSegment{
402 {
403 Command: Command{Name: "command1", ID: "commandID1"},
404 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
405 },
406 {
407 Command: Command{Name: "command2", ID: "commandID2"},
408 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
409 },
410 {
411 Command: Command{Name: "command3", ID: "commandID3"},
412 Privilege: Privilege{Name: "privilege2", ID: "privID2"},
413 },
414 },
415 expectedRules: []ReturnRuleSet{
416 {
417 Privilege: Privilege{Name: "privilege1", ID: "privID1"},
418 Commands: []Command{
419 {Name: "command1", ID: "commandID1"},
420 {Name: "command2", ID: "commandID2"}},
421 },
422 {
423 Privilege: Privilege{Name: "privilege2", ID: "privID2"},
424 Commands: []Command{{Name: "command3", ID: "commandID3"}},
425 },
426 },
427 expectedErr: nil,
428 },
429 }
430
431 for name, tc := range tests {
432 tc := tc
433 t.Run(name, func(t *testing.T) {
434 t.Parallel()
435 ctx := context.Background()
436 reng := RulesEngine{}
437
438 reng.ds = newMockDefaultRulesDS(nil, func(_ context.Context) ([]RuleSegment, error) {
439 return tc.defaultRules, tc.expectedErr
440 })
441
442 rules, err := reng.GetDefaultRules(ctx, tc.privilegeNames...)
443
444
445 assert.EqualValues(t, tc.expectedRules, rules)
446 assert.Equal(t, tc.expectedErr, err)
447 })
448 }
449 }
450
451 func TestAddDefaultRules(t *testing.T) {
452 t.Parallel()
453
454 tests := map[string]struct {
455 rules WriteRules
456 assertErr assert.ErrorAssertionFunc
457 }{
458 "Empty rules": {
459 rules: WriteRules{},
460 assertErr: ErrorEqualMsg("empty rules list"),
461 },
462 "Valid rules": {
463 rules: WriteRules{
464 {
465 Command: "command1",
466 Privileges: []string{"privilege1", "privilege2"},
467 },
468 {
469 Command: "command2",
470 Privileges: []string{"privilege1"},
471 },
472 },
473 assertErr: assert.NoError,
474 },
475 "Invalid command": {
476 rules: WriteRules{
477 {
478 Command: "",
479 Privileges: []string{"privilege1", "privilege2"},
480 },
481 },
482 assertErr: ErrorEqualMsg("invalid rule at 0: empty command name"),
483 },
484 "Invalid privilege": {
485 rules: WriteRules{
486 {
487 Command: "command1",
488 Privileges: []string{""},
489 },
490 },
491 assertErr: ErrorEqualMsg("invalid rule at 0: empty privilege name in array at 0"),
492 },
493 }
494
495 for name, tc := range tests {
496 tc := tc
497 t.Run(name, func(t *testing.T) {
498 t.Parallel()
499
500 ctx := context.Background()
501 reng := RulesEngine{}
502
503 reng.ds = newMockDefaultRulesDS(func(_ context.Context, _ []RuleSegment) (AddRuleResult, error) {
504 return AddRuleResult{}, nil
505 },
506 nil)
507
508 _, err := reng.AddDefaultRules(ctx, tc.rules)
509 tc.assertErr(t, err)
510 })
511 }
512 }
513
View as plain text