package rulesengine import ( "context" "fmt" "testing" "github.com/stretchr/testify/assert" ) var commandNames = []Command{ {Name: "a"}, {Name: "b"}, {Name: "c"}, } var privilegeNames = []Privilege{ {Name: "a"}, {Name: "b"}, {Name: "c"}, } func TestSplitPostDefaultRulesToRuleSegment(t *testing.T) { t.Parallel() tests := map[string]struct { rules WriteRules exp []RuleSegment }{ "One Rule": { rules: WriteRules{ { Command: commandNames[0].Name, Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name}, }, }, exp: []RuleSegment{ {Command: commandNames[0], Privilege: privilegeNames[0]}, {Command: commandNames[0], Privilege: privilegeNames[1]}, }, }, "Multiple Rules": { rules: WriteRules{ { Command: commandNames[0].Name, Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name}, }, { Command: commandNames[1].Name, Privileges: []string{privilegeNames[1].Name, privilegeNames[2].Name}, }, { Command: commandNames[2].Name, Privileges: []string{privilegeNames[0].Name, privilegeNames[1].Name, privilegeNames[2].Name}, }, }, exp: []RuleSegment{ {Command: commandNames[0], Privilege: privilegeNames[0]}, {Command: commandNames[0], Privilege: privilegeNames[1]}, {Command: commandNames[1], Privilege: privilegeNames[1]}, {Command: commandNames[1], Privilege: privilegeNames[2]}, {Command: commandNames[2], Privilege: privilegeNames[0]}, {Command: commandNames[2], Privilege: privilegeNames[1]}, {Command: commandNames[2], Privilege: privilegeNames[2]}, }, }, } for name, tc := range tests { tc := tc t.Run(name, func(t *testing.T) { t.Parallel() segments := splitPostDefaultRulesToRuleSegment(tc.rules) assert.Equal(t, tc.exp, segments) }) } } func TestAssembleRules(t *testing.T) { tests := map[string]struct { ruleSegments []RuleSegment expectedRes []Rule }{ "2 privs 2 commands": { ruleSegments: []RuleSegment{ { Command: Command{ Name: "com1", ID: "comID1"}, Privilege: Privilege{ Name: "priv1", ID: "privID1", }, }, { Command: Command{ Name: "com1", ID: "comID1"}, Privilege: Privilege{ Name: "priv2", ID: "privID2", }, }, { Command: Command{ Name: "com2", ID: "comID2"}, Privilege: Privilege{ Name: "priv3", ID: "privID3", }, }, }, expectedRes: []Rule{ { Command: Command{Name: "com1", ID: "comID1"}, Privileges: []Privilege{{Name: "priv1", ID: "privID1"}, {Name: "priv2", ID: "privID2"}}, }, { Command: Command{Name: "com2", ID: "comID2"}, Privileges: []Privilege{{Name: "priv3", ID: "privID3"}}, }, }, }, "Banner ignored": { ruleSegments: []RuleSegment{ { Banner: Banner{BannerName: "bannername", BannerID: "bannerID"}, Command: Command{ Name: "com1", ID: "comID1"}, Privilege: Privilege{ Name: "priv1", ID: "privID1", }, }, }, expectedRes: []Rule{ { Command: Command{Name: "com1", ID: "comID1"}, Privileges: []Privilege{{Name: "priv1", ID: "privID1"}}, }}, }, } for name, tc := range tests { t.Run(name, func(t *testing.T) { assert.EqualValues(t, tc.expectedRes, assembleRules(tc.ruleSegments)) }) } } type mockDefaultRulesDS struct { addDefaultRulesFunc func(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) readDefaultRulesFunc func(ctx context.Context) ([]RuleSegment, error) Dataset } func (m *mockDefaultRulesDS) AddDefaultRules(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) { if m.addDefaultRulesFunc != nil { return m.addDefaultRulesFunc(ctx, ruleSegments) } return AddRuleResult{}, fmt.Errorf("AddDefaultRules not implemented") } func (m *mockDefaultRulesDS) ReadAllDefaultRules(ctx context.Context) ([]RuleSegment, error) { if m.readDefaultRulesFunc != nil { return m.readDefaultRulesFunc(ctx) } return nil, fmt.Errorf("ReadDefaultRules not implemented") } func newMockDefaultRulesDS(addDefaultRulesFunc func(ctx context.Context, ruleSegments []RuleSegment) (AddRuleResult, error), readDefaultRulesFunc func(ctx context.Context) ([]RuleSegment, error)) *mockDefaultRulesDS { return &mockDefaultRulesDS{ addDefaultRulesFunc: addDefaultRulesFunc, readDefaultRulesFunc: readDefaultRulesFunc, } } type helper interface { Helper() } func ErrorEqualMsg(message string) assert.ErrorAssertionFunc { return func(t assert.TestingT, err error, i ...interface{}) bool { if tt, ok := t.(helper); ok { tt.Helper() } return assert.EqualError(t, err, message, i...) } } func TestAddDefaultRulesForPrivileges(t *testing.T) { t.Parallel() tests := map[string]struct { data []RuleSet expectedRules []RuleSegment assertErr assert.ErrorAssertionFunc }{ "Single Privilege, Single Command": { data: []RuleSet{ { Privilege: "privilege1", Commands: []string{"command1"}, }, }, expectedRules: []RuleSegment{ { Command: Command{Name: "command1"}, Privilege: Privilege{Name: "privilege1"}, }, }, assertErr: assert.NoError, }, "Single Privilege, Multiple Commands": { data: []RuleSet{ { Privilege: "privilege1", Commands: []string{"command1", "command2"}, }, }, expectedRules: []RuleSegment{ { Command: Command{Name: "command1"}, Privilege: Privilege{Name: "privilege1"}, }, { Command: Command{Name: "command2"}, Privilege: Privilege{Name: "privilege1"}, }, }, assertErr: assert.NoError, }, "Multiple Privileges, Single Command": { data: []RuleSet{ { Privilege: "privilege1", Commands: []string{"command1"}, }, { Privilege: "privilege2", Commands: []string{"command1"}, }, }, expectedRules: []RuleSegment{ { Command: Command{Name: "command1"}, Privilege: Privilege{Name: "privilege1"}, }, { Command: Command{Name: "command1"}, Privilege: Privilege{Name: "privilege2"}, }, }, assertErr: assert.NoError, }, "Multiple Privileges, Multiple Commands": { data: []RuleSet{ { Privilege: "privilege1", Commands: []string{"command1", "command2"}, }, { Privilege: "privilege2", Commands: []string{"command3"}, }, }, expectedRules: []RuleSegment{ { Command: Command{Name: "command1"}, Privilege: Privilege{Name: "privilege1"}, }, { Command: Command{Name: "command2"}, Privilege: Privilege{Name: "privilege1"}, }, { Command: Command{Name: "command3"}, Privilege: Privilege{Name: "privilege2"}, }, }, assertErr: assert.NoError, }, "No Privileges": { data: []RuleSet{}, expectedRules: []RuleSegment{}, assertErr: ErrorEqualMsg("empty rules list"), }, } for name, tc := range tests { tc := tc t.Run(name, func(t *testing.T) { t.Parallel() ctx := context.Background() // Create an instance of the RulesEngine reng := RulesEngine{} // Set up a mock ds reng.ds = newMockDefaultRulesDS(func(_ context.Context, ruleSegments []RuleSegment) (AddRuleResult, error) { // test the rulesegments match the expected rules assert.ElementsMatch(t, tc.expectedRules, ruleSegments) return AddRuleResult{}, nil }, nil) // Call the AddDefaultRulesFromData function _, err := reng.AddDefaultRulesForPrivileges(ctx, tc.data) // check the error tc.assertErr(t, err) }) } } func TestGetDefaultRules(t *testing.T) { t.Parallel() tests := map[string]struct { privilegeNames []string defaultRules []RuleSegment expectedRules []ReturnRuleSet expectedErr error }{ "Existing Privilege": { privilegeNames: []string{"privilege1"}, defaultRules: []RuleSegment{ { Command: Command{Name: "command1", ID: "commandID1"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, { Command: Command{Name: "command2", ID: "commandID2"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, }, expectedRules: []ReturnRuleSet{ { Privilege: Privilege{Name: "privilege1", ID: "privID1"}, Commands: []Command{ {Name: "command1", ID: "commandID1"}, {Name: "command2", ID: "commandID2"}, }, }, }, expectedErr: nil, }, "Non-Existing Privilege": { privilegeNames: []string{"privilege2"}, defaultRules: []RuleSegment{ { Command: Command{Name: "command1", ID: "commandID1"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, { Command: Command{Name: "command2", ID: "commandID2"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, }, expectedRules: []ReturnRuleSet{}, expectedErr: nil, }, "Empty Default Rules": { privilegeNames: []string{"privilege1"}, defaultRules: []RuleSegment{}, expectedRules: []ReturnRuleSet{}, expectedErr: nil, }, "Error Reading Default Rules": { privilegeNames: []string{"privilege1"}, defaultRules: nil, expectedRules: []ReturnRuleSet{}, expectedErr: fmt.Errorf("error when reading all default rules: some error"), }, "No Privilege Names": { privilegeNames: []string{}, defaultRules: []RuleSegment{ { Command: Command{Name: "command1", ID: "commandID1"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, { Command: Command{Name: "command2", ID: "commandID2"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, }, expectedRules: []ReturnRuleSet{ { Privilege: Privilege{Name: "privilege1", ID: "privID1"}, Commands: []Command{ {Name: "command1", ID: "commandID1"}, {Name: "command2", ID: "commandID2"}, }, }, }, expectedErr: nil, }, "Multiple privilege Names": { privilegeNames: []string{"privilege1", "privilege2"}, defaultRules: []RuleSegment{ { Command: Command{Name: "command1", ID: "commandID1"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, { Command: Command{Name: "command2", ID: "commandID2"}, Privilege: Privilege{Name: "privilege1", ID: "privID1"}, }, { Command: Command{Name: "command3", ID: "commandID3"}, Privilege: Privilege{Name: "privilege2", ID: "privID2"}, }, }, expectedRules: []ReturnRuleSet{ { Privilege: Privilege{Name: "privilege1", ID: "privID1"}, Commands: []Command{ {Name: "command1", ID: "commandID1"}, {Name: "command2", ID: "commandID2"}}, }, { Privilege: Privilege{Name: "privilege2", ID: "privID2"}, Commands: []Command{{Name: "command3", ID: "commandID3"}}, }, }, expectedErr: nil, }, } for name, tc := range tests { tc := tc t.Run(name, func(t *testing.T) { t.Parallel() ctx := context.Background() reng := RulesEngine{} // Set up a mock ds reng.ds = newMockDefaultRulesDS(nil, func(_ context.Context) ([]RuleSegment, error) { return tc.defaultRules, tc.expectedErr }) // Call the GetDefaultRules function rules, err := reng.GetDefaultRules(ctx, tc.privilegeNames...) // Test the result and error assert.EqualValues(t, tc.expectedRules, rules) assert.Equal(t, tc.expectedErr, err) }) } } func TestAddDefaultRules(t *testing.T) { t.Parallel() tests := map[string]struct { rules WriteRules assertErr assert.ErrorAssertionFunc }{ "Empty rules": { rules: WriteRules{}, assertErr: ErrorEqualMsg("empty rules list"), }, "Valid rules": { rules: WriteRules{ { Command: "command1", Privileges: []string{"privilege1", "privilege2"}, }, { Command: "command2", Privileges: []string{"privilege1"}, }, }, assertErr: assert.NoError, }, "Invalid command": { rules: WriteRules{ { Command: "", Privileges: []string{"privilege1", "privilege2"}, }, }, assertErr: ErrorEqualMsg("invalid rule at 0: empty command name"), }, "Invalid privilege": { rules: WriteRules{ { Command: "command1", Privileges: []string{""}, }, }, assertErr: ErrorEqualMsg("invalid rule at 0: empty privilege name in array at 0"), }, } for name, tc := range tests { tc := tc t.Run(name, func(t *testing.T) { t.Parallel() ctx := context.Background() reng := RulesEngine{} // Set up a mock ds reng.ds = newMockDefaultRulesDS(func(_ context.Context, _ []RuleSegment) (AddRuleResult, error) { return AddRuleResult{}, nil }, nil) _, err := reng.AddDefaultRules(ctx, tc.rules) tc.assertErr(t, err) }) } }