github.com/GoogleCloudPlatform/testgrid@v0.0.174/pkg/updater/eval_test.go (about) 1 /* 2 Copyright 2022 The TestGrid Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package updater 18 19 import ( 20 "regexp" 21 "testing" 22 23 evalpb "github.com/GoogleCloudPlatform/testgrid/pb/custom_evaluator" 24 tspb "github.com/GoogleCloudPlatform/testgrid/pb/test_status" 25 ) 26 27 func TestStrReg(t *testing.T) { 28 cases := []struct { 29 expr string 30 val string 31 res map[string]*regexp.Regexp 32 want bool 33 }{ 34 { 35 expr: `hello`, 36 val: "hello world", 37 want: true, 38 }, 39 { 40 expr: `hello`, 41 val: "stranger", 42 }, 43 { 44 expr: `prefer cached regexps`, 45 val: "surprisingly this works", 46 res: map[string]*regexp.Regexp{ 47 "prefer cached regexps": regexp.MustCompile("this"), 48 }, 49 want: true, 50 }, 51 { 52 expr: `.**`, 53 val: "bad regexp should fail", 54 }, 55 } 56 57 orig := res 58 defer func() { res = orig }() 59 60 for _, tc := range cases { 61 t.Run(tc.expr+" "+tc.val, func(t *testing.T) { 62 res = tc.res 63 if res == nil { 64 res = map[string]*regexp.Regexp{} 65 } 66 if got := strReg(tc.val, tc.expr); got != tc.want { 67 t.Errorf("strReg() got %t, want %t", got, tc.want) 68 } 69 }) 70 } 71 } 72 73 type fakeTestResult struct { 74 properties map[string][]string 75 } 76 77 func (r fakeTestResult) Properties() map[string][]string { 78 return r.properties 79 } 80 81 func (r fakeTestResult) Name() string { 82 panic("boom") 83 } 84 85 func (r fakeTestResult) Errors() int { 86 panic("boom") 87 } 88 89 func (r fakeTestResult) Failures() int { 90 panic("boom") 91 } 92 93 func (r fakeTestResult) Exceptions() []string { 94 panic("boom") 95 } 96 97 func makeResult(props map[string][]string) *fakeTestResult { 98 return &fakeTestResult{ 99 properties: props, 100 } 101 } 102 103 func TestCustomStatus(t *testing.T) { 104 timedOut := tspb.TestStatus_TIMED_OUT 105 abort := tspb.TestStatus_CATEGORIZED_ABORT 106 cases := []struct { 107 name string 108 rules []*evalpb.Rule 109 tr TestResult 110 want *tspb.TestStatus 111 }{ 112 { 113 name: "empty", 114 }, 115 { 116 name: "basic", 117 rules: []*evalpb.Rule{ 118 { 119 ComputedStatus: tspb.TestStatus_TIMED_OUT, 120 TestResultComparisons: []*evalpb.TestResultComparison{ 121 { 122 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 123 PropertyKey: "foo", 124 }, 125 Comparison: &evalpb.Comparison{ 126 Op: evalpb.Comparison_OP_EQ, 127 ComparisonValue: &evalpb.Comparison_StringValue{ 128 StringValue: "goal", 129 }, 130 }, 131 }, 132 }, 133 }, 134 }, 135 tr: makeResult(map[string][]string{ 136 "foo": {"goal"}, 137 }), 138 139 want: &timedOut, 140 }, 141 { 142 name: "wrong string value", 143 rules: []*evalpb.Rule{ 144 { 145 ComputedStatus: tspb.TestStatus_TIMED_OUT, 146 TestResultComparisons: []*evalpb.TestResultComparison{ 147 { 148 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 149 PropertyKey: "foo", 150 }, 151 Comparison: &evalpb.Comparison{ 152 Op: evalpb.Comparison_OP_EQ, 153 ComparisonValue: &evalpb.Comparison_StringValue{ 154 StringValue: "goal", 155 }, 156 }, 157 }, 158 }, 159 }, 160 }, 161 tr: makeResult(map[string][]string{ 162 "foo": {"wrong-value"}, 163 }), 164 }, 165 { 166 name: "not equal, string", 167 rules: []*evalpb.Rule{ 168 { 169 ComputedStatus: tspb.TestStatus_TIMED_OUT, 170 TestResultComparisons: []*evalpb.TestResultComparison{ 171 { 172 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 173 PropertyKey: "foo", 174 }, 175 Comparison: &evalpb.Comparison{ 176 Op: evalpb.Comparison_OP_NE, 177 ComparisonValue: &evalpb.Comparison_StringValue{ 178 StringValue: "goal", 179 }, 180 }, 181 }, 182 }, 183 }, 184 }, 185 tr: makeResult(map[string][]string{ 186 "foo": {"no"}, 187 }), 188 want: &timedOut, 189 }, 190 { 191 name: "not equal, string, is equal", 192 rules: []*evalpb.Rule{ 193 { 194 ComputedStatus: tspb.TestStatus_TIMED_OUT, 195 TestResultComparisons: []*evalpb.TestResultComparison{ 196 { 197 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 198 PropertyKey: "foo", 199 }, 200 Comparison: &evalpb.Comparison{ 201 Op: evalpb.Comparison_OP_NE, 202 ComparisonValue: &evalpb.Comparison_StringValue{ 203 StringValue: "goal", 204 }, 205 }, 206 }, 207 }, 208 }, 209 }, 210 tr: makeResult(map[string][]string{ 211 "foo": {"goal"}, 212 }), 213 }, 214 { 215 name: "string contains", 216 rules: []*evalpb.Rule{ 217 { 218 ComputedStatus: tspb.TestStatus_TIMED_OUT, 219 TestResultComparisons: []*evalpb.TestResultComparison{ 220 { 221 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 222 PropertyKey: "foo", 223 }, 224 Comparison: &evalpb.Comparison{ 225 Op: evalpb.Comparison_OP_CONTAINS, 226 ComparisonValue: &evalpb.Comparison_StringValue{ 227 StringValue: "goal", 228 }, 229 }, 230 }, 231 }, 232 }, 233 }, 234 tr: makeResult(map[string][]string{ 235 "foo": {"this is the goal"}, 236 }), 237 want: &timedOut, 238 }, 239 { 240 name: "string does not contains", 241 rules: []*evalpb.Rule{ 242 { 243 ComputedStatus: tspb.TestStatus_TIMED_OUT, 244 TestResultComparisons: []*evalpb.TestResultComparison{ 245 { 246 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 247 PropertyKey: "foo", 248 }, 249 Comparison: &evalpb.Comparison{ 250 Op: evalpb.Comparison_OP_CONTAINS, 251 ComparisonValue: &evalpb.Comparison_StringValue{ 252 StringValue: "goal", 253 }, 254 }, 255 }, 256 }, 257 }, 258 }, 259 tr: makeResult(map[string][]string{ 260 "foo": {"i am not a matching message"}, 261 }), 262 }, 263 { 264 name: "missing property", 265 rules: []*evalpb.Rule{ 266 { 267 ComputedStatus: tspb.TestStatus_TIMED_OUT, 268 TestResultComparisons: []*evalpb.TestResultComparison{ 269 { 270 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 271 PropertyKey: "want", 272 }, 273 Comparison: &evalpb.Comparison{ 274 Op: evalpb.Comparison_OP_EQ, 275 ComparisonValue: &evalpb.Comparison_StringValue{ 276 StringValue: "goal", 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 tr: makeResult(map[string][]string{ 284 "wrong-key": {"goal"}, 285 }), 286 }, 287 { 288 name: "match regex", 289 rules: []*evalpb.Rule{ 290 { 291 ComputedStatus: tspb.TestStatus_CATEGORIZED_ABORT, 292 TestResultComparisons: []*evalpb.TestResultComparison{ 293 { 294 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 295 PropertyKey: "want", 296 }, 297 Comparison: &evalpb.Comparison{ 298 Op: evalpb.Comparison_OP_REGEX, 299 ComparisonValue: &evalpb.Comparison_StringValue{ 300 StringValue: ".*(No response|Error executing).*", 301 }, 302 }, 303 }, 304 }, 305 }, 306 }, 307 tr: makeResult(map[string][]string{ 308 "want": {"prefix No response from server. Stopping testing"}, 309 }), 310 want: &abort, 311 }, 312 { 313 name: "not match regex", 314 rules: []*evalpb.Rule{ 315 { 316 ComputedStatus: tspb.TestStatus_CATEGORIZED_ABORT, 317 TestResultComparisons: []*evalpb.TestResultComparison{ 318 { 319 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 320 PropertyKey: "want", 321 }, 322 Comparison: &evalpb.Comparison{ 323 Op: evalpb.Comparison_OP_REGEX, 324 ComparisonValue: &evalpb.Comparison_StringValue{ 325 StringValue: ".*(No response|Error executing).*", 326 }, 327 }, 328 }, 329 }, 330 }, 331 }, 332 tr: makeResult(map[string][]string{ 333 "want": {"Random stuff"}, 334 }), 335 }, 336 { 337 name: "no comparisons", 338 rules: []*evalpb.Rule{ 339 { 340 ComputedStatus: tspb.TestStatus_TIMED_OUT, 341 }, 342 }, 343 tr: makeResult(map[string][]string{ 344 "foo": {"goal"}, 345 }), 346 want: &timedOut, 347 }, 348 { 349 name: "no rules", 350 tr: makeResult(map[string][]string{ 351 "foo": {"goal"}, 352 }), 353 }, 354 // TODO(fejta): more test coverage 355 } 356 357 for _, tc := range cases { 358 t.Run(tc.name, func(t *testing.T) { 359 got := CustomStatus(tc.rules, tc.tr) 360 switch { 361 case got == nil: 362 if tc.want != nil { 363 t.Errorf("customStatus() got nil, want %v", tc.want) 364 } 365 case tc.want == nil: 366 t.Errorf("customStatus() should be nil, not %v", got) 367 case *tc.want != *got: 368 t.Errorf("customStatus() got %v, want %v", *got, *tc.want) 369 370 } 371 }) 372 } 373 } 374 375 type fakeTargetResult struct { 376 targetStatus tspb.TestStatus 377 } 378 379 func (r fakeTargetResult) TargetStatus() tspb.TestStatus { 380 return r.targetStatus 381 } 382 383 func makeTargetResult(status tspb.TestStatus) *fakeTargetResult { 384 return &fakeTargetResult{ 385 targetStatus: status, 386 } 387 } 388 389 func TestCustomTargetStatus(t *testing.T) { 390 abort := tspb.TestStatus_CATEGORIZED_ABORT 391 cases := []struct { 392 name string 393 rules []*evalpb.Rule 394 tgr TargetResult 395 want *tspb.TestStatus 396 }{ 397 { 398 name: "empty", 399 }, 400 { 401 name: "target status equal", 402 rules: []*evalpb.Rule{ 403 { 404 ComputedStatus: tspb.TestStatus_CATEGORIZED_ABORT, 405 TestResultComparisons: []*evalpb.TestResultComparison{ 406 { 407 TestResultInfo: &evalpb.TestResultComparison_TargetStatus{ 408 TargetStatus: true, 409 }, 410 Comparison: &evalpb.Comparison{ 411 Op: evalpb.Comparison_OP_EQ, 412 ComparisonValue: &evalpb.Comparison_TargetStatusValue{ 413 TargetStatusValue: tspb.TestStatus_TOOL_FAIL, 414 }, 415 }, 416 }, 417 }, 418 }, 419 }, 420 tgr: makeTargetResult(tspb.TestStatus_TOOL_FAIL), 421 want: &abort, 422 }, 423 { 424 name: "target status not equal", 425 rules: []*evalpb.Rule{ 426 { 427 ComputedStatus: tspb.TestStatus_TIMED_OUT, 428 TestResultComparisons: []*evalpb.TestResultComparison{ 429 { 430 TestResultInfo: &evalpb.TestResultComparison_TargetStatus{ 431 TargetStatus: true, 432 }, 433 Comparison: &evalpb.Comparison{ 434 Op: evalpb.Comparison_OP_EQ, 435 ComparisonValue: &evalpb.Comparison_TargetStatusValue{ 436 TargetStatusValue: tspb.TestStatus_CATEGORIZED_ABORT, 437 }, 438 }, 439 }, 440 }, 441 }, 442 }, 443 tgr: makeTargetResult(tspb.TestStatus_TOOL_FAIL), 444 want: nil, 445 }, 446 { 447 name: "target status comparation not enabled", 448 rules: []*evalpb.Rule{ 449 { 450 ComputedStatus: tspb.TestStatus_CATEGORIZED_ABORT, 451 TestResultComparisons: []*evalpb.TestResultComparison{ 452 { 453 TestResultInfo: &evalpb.TestResultComparison_PropertyKey{ 454 PropertyKey: "want", 455 }, 456 Comparison: &evalpb.Comparison{ 457 Op: evalpb.Comparison_OP_EQ, 458 ComparisonValue: &evalpb.Comparison_TargetStatusValue{ 459 TargetStatusValue: tspb.TestStatus_TOOL_FAIL, 460 }, 461 }, 462 }, 463 }, 464 }, 465 }, 466 tgr: makeTargetResult(tspb.TestStatus_TOOL_FAIL), 467 want: nil, 468 }, 469 } 470 471 for _, tc := range cases { 472 t.Run(tc.name, func(t *testing.T) { 473 got := CustomTargetStatus(tc.rules, tc.tgr) 474 switch { 475 case got == nil: 476 if tc.want != nil { 477 t.Errorf("CustomTargetStatus() got nil, want %v", tc.want) 478 } 479 case tc.want == nil: 480 t.Errorf("CustomTargetStatus() should be nil, not %v", got) 481 case *tc.want != *got: 482 t.Errorf("CustomTargetStatus() got %v, want %v", *got, *tc.want) 483 } 484 }) 485 } 486 }