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  }