github.com/jlmeeker/kismatic@v1.10.1-0.20180612190640-57f9005a1f1a/pkg/inspector/rule/engine_test.go (about) 1 package rule 2 3 import ( 4 "errors" 5 "reflect" 6 "testing" 7 8 "github.com/apprenda/kismatic/pkg/inspector/check" 9 ) 10 11 type fakeCheck struct { 12 ok bool 13 err error 14 } 15 16 func (c fakeCheck) Check() (bool, error) { 17 return c.ok, c.err 18 } 19 20 type fakeRule struct { 21 Meta 22 name string 23 isRemote bool 24 } 25 26 func (r fakeRule) Name() string { return r.name } 27 func (r fakeRule) IsRemoteRule() bool { return r.isRemote } 28 func (r fakeRule) Validate() []error { return nil } 29 30 type fakeRuleCheckMapper struct { 31 check check.Check 32 err error 33 } 34 35 func (m fakeRuleCheckMapper) GetCheckForRule(Rule) (check.Check, error) { 36 return m.check, m.err 37 } 38 39 func TestEngine(t *testing.T) { 40 dummyError := errors.New("dummy error...") 41 tests := []struct { 42 mapper fakeRuleCheckMapper 43 rule fakeRule 44 ruleWhen [][]string 45 facts []string 46 expectedResults []Result 47 expectErr bool 48 }{ 49 // Single rule that passes 50 { 51 mapper: fakeRuleCheckMapper{ 52 check: fakeCheck{ok: true}, 53 }, 54 rule: fakeRule{ 55 name: "SuccessRule", 56 }, 57 facts: []string{}, 58 expectedResults: []Result{ 59 { 60 Name: "SuccessRule", 61 Success: true, 62 }, 63 }, 64 }, 65 // Single rule that fails 66 { 67 mapper: fakeRuleCheckMapper{ 68 check: fakeCheck{ok: false, err: dummyError}, 69 }, 70 rule: fakeRule{ 71 name: "FailRule", 72 }, 73 facts: []string{}, 74 expectedResults: []Result{ 75 { 76 Name: "FailRule", 77 Success: false, 78 Error: dummyError.Error(), 79 }, 80 }, 81 }, 82 // Single rule that should run due to facts 83 { 84 mapper: fakeRuleCheckMapper{ 85 check: fakeCheck{ok: false, err: dummyError}, 86 }, 87 rule: fakeRule{ 88 name: "FailRule", 89 }, 90 ruleWhen: [][]string{[]string{"ubuntu"}, []string{"worker"}}, 91 facts: []string{"ubuntu", "worker", "otherFact"}, 92 expectedResults: []Result{ 93 { 94 Name: "FailRule", 95 Success: false, 96 Error: dummyError.Error(), 97 }, 98 }, 99 }, 100 { 101 mapper: fakeRuleCheckMapper{ 102 check: fakeCheck{ok: false, err: dummyError}, 103 }, 104 rule: fakeRule{ 105 name: "FailRule", 106 }, 107 ruleWhen: [][]string{[]string{"ubuntu"}, []string{"master", "worker"}}, 108 facts: []string{"ubuntu", "worker", "otherFact"}, 109 expectedResults: []Result{ 110 { 111 Name: "FailRule", 112 Success: false, 113 Error: dummyError.Error(), 114 }, 115 }, 116 }, 117 { 118 mapper: fakeRuleCheckMapper{ 119 check: fakeCheck{ok: false, err: dummyError}, 120 }, 121 rule: fakeRule{ 122 name: "FailRule", 123 }, 124 ruleWhen: [][]string{[]string{"centos", "rhel"}, []string{"worker"}}, 125 facts: []string{"centos", "worker", "otherFact"}, 126 expectedResults: []Result{ 127 { 128 Name: "FailRule", 129 Success: false, 130 Error: dummyError.Error(), 131 }, 132 }, 133 }, 134 // Single rule that should not run due to facts 135 { 136 mapper: fakeRuleCheckMapper{ 137 check: fakeCheck{ok: false, err: dummyError}, 138 }, 139 rule: fakeRule{ 140 name: "FailRule", 141 }, 142 ruleWhen: [][]string{[]string{"ubuntu"}}, 143 facts: []string{"otherFact"}, 144 expectedResults: []Result{}, 145 }, 146 // Single rule that should run regardless of facts 147 { 148 mapper: fakeRuleCheckMapper{ 149 check: fakeCheck{ok: false, err: dummyError}, 150 }, 151 rule: fakeRule{ 152 name: "FailRule", 153 }, 154 ruleWhen: [][]string{}, 155 facts: []string{"ubuntu"}, 156 expectedResults: []Result{ 157 { 158 Name: "FailRule", 159 Success: false, 160 Error: dummyError.Error(), 161 }, 162 }, 163 }, 164 // Mapper returns an error, engine should return error 165 { 166 mapper: fakeRuleCheckMapper{ 167 err: dummyError, 168 }, 169 rule: fakeRule{}, 170 expectErr: true, 171 }, 172 } 173 174 for _, test := range tests { 175 // Set the rule when conditions here because of embedding :( 176 if test.ruleWhen != nil { 177 test.rule.When = test.ruleWhen 178 } 179 e := Engine{ 180 RuleCheckMapper: test.mapper, 181 } 182 result, err := e.ExecuteRules([]Rule{test.rule}, test.facts) 183 if test.expectErr && err == nil { 184 t.Errorf("expected an error, but didn't get one") 185 continue 186 } 187 if err != nil && !test.expectErr { 188 t.Errorf("got an unexpected error: %v", err) 189 continue 190 } 191 192 if !reflect.DeepEqual(test.expectedResults, result) { 193 t.Errorf("expected %+v, but got %+v", test.expectedResults, result) 194 } 195 } 196 } 197 198 type fakeClosableCheck struct { 199 success bool 200 closeCalled bool 201 } 202 203 func (c *fakeClosableCheck) Check() (bool, error) { return c.success, nil } 204 205 func (c *fakeClosableCheck) Close() error { 206 c.closeCalled = true 207 return nil 208 } 209 210 func TestEngineClosableCheckSuccess(t *testing.T) { 211 fakeCheck := &fakeClosableCheck{success: true} 212 mapper := fakeRuleCheckMapper{ 213 check: fakeCheck, 214 } 215 e := Engine{ 216 RuleCheckMapper: mapper, 217 } 218 rule := fakeRule{} 219 _, err := e.ExecuteRules([]Rule{rule}, []string{}) 220 if err != nil { 221 t.Errorf("unexpected error when executing closable check: %v", err) 222 } 223 224 if err := e.CloseChecks(); err != nil { 225 t.Errorf("unexpected error when closing checks: %v", err) 226 } 227 228 if !fakeCheck.closeCalled { 229 t.Errorf("The check was not closed") 230 } 231 } 232 233 func TestEngineClosableCheckFail(t *testing.T) { 234 fakeCheck := &fakeClosableCheck{success: false} 235 mapper := fakeRuleCheckMapper{ 236 check: fakeCheck, 237 } 238 e := Engine{ 239 RuleCheckMapper: mapper, 240 } 241 rule := fakeRule{} 242 _, err := e.ExecuteRules([]Rule{rule}, []string{}) 243 if err != nil { 244 t.Errorf("unexpected error when executing closable check: %v", err) 245 } 246 247 if err := e.CloseChecks(); err != nil { 248 t.Errorf("unexpected error when closing checks: %v", err) 249 } 250 251 if fakeCheck.closeCalled { 252 t.Errorf("The check failed, and close was called on it") 253 } 254 }