github.com/GoogleCloudPlatform/testgrid@v0.0.174/internal/result/results_test.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes 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 result
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"math/rand"
    23  	"reflect"
    24  	"testing"
    25  
    26  	configpb "github.com/GoogleCloudPlatform/testgrid/pb/config"
    27  	statuspb "github.com/GoogleCloudPlatform/testgrid/pb/test_status"
    28  )
    29  
    30  func TestPassing(t *testing.T) {
    31  	cases := []struct {
    32  		status   statuspb.TestStatus
    33  		expected bool
    34  	}{
    35  		{
    36  			status: statuspb.TestStatus_NO_RESULT,
    37  		},
    38  		{
    39  			status:   statuspb.TestStatus_BUILD_PASSED,
    40  			expected: true,
    41  		},
    42  		{
    43  			status:   statuspb.TestStatus_PASS,
    44  			expected: true,
    45  		},
    46  		{
    47  			status:   statuspb.TestStatus_PASS_WITH_SKIPS,
    48  			expected: true,
    49  		},
    50  		{
    51  			status:   statuspb.TestStatus_PASS_WITH_ERRORS,
    52  			expected: true,
    53  		},
    54  		{
    55  			status: statuspb.TestStatus_RUNNING,
    56  		},
    57  		{
    58  			status: statuspb.TestStatus_CATEGORIZED_ABORT,
    59  		},
    60  		{
    61  			status: statuspb.TestStatus_FLAKY,
    62  		},
    63  		{
    64  			status: statuspb.TestStatus_FAIL,
    65  		},
    66  	}
    67  
    68  	for _, tc := range cases {
    69  		t.Run(tc.status.String(), func(t *testing.T) {
    70  			if actual := Passing(tc.status); actual != tc.expected {
    71  				t.Errorf("Passing(%v) got %t, want %t", tc.status, actual, tc.expected)
    72  			}
    73  		})
    74  	}
    75  }
    76  
    77  func TestFailing(t *testing.T) {
    78  	cases := []struct {
    79  		status   statuspb.TestStatus
    80  		expected bool
    81  	}{
    82  		{
    83  			status: statuspb.TestStatus_NO_RESULT,
    84  		},
    85  		{
    86  			status: statuspb.TestStatus_BUILD_PASSED,
    87  		},
    88  		{
    89  			status: statuspb.TestStatus_PASS,
    90  		},
    91  		{
    92  			status: statuspb.TestStatus_RUNNING,
    93  		},
    94  		{
    95  			status: statuspb.TestStatus_CATEGORIZED_ABORT,
    96  		},
    97  		{
    98  			status: statuspb.TestStatus_UNKNOWN,
    99  		},
   100  		{
   101  			status: statuspb.TestStatus_CANCEL,
   102  		},
   103  		{
   104  			status: statuspb.TestStatus_FLAKY,
   105  		},
   106  		{
   107  			status:   statuspb.TestStatus_TOOL_FAIL,
   108  			expected: true,
   109  		},
   110  		{
   111  			status:   statuspb.TestStatus_TIMED_OUT,
   112  			expected: true,
   113  		},
   114  		{
   115  			status:   statuspb.TestStatus_CATEGORIZED_FAIL,
   116  			expected: true,
   117  		},
   118  		{
   119  			status:   statuspb.TestStatus_BUILD_FAIL,
   120  			expected: true,
   121  		},
   122  		{
   123  			status:   statuspb.TestStatus_FAIL,
   124  			expected: true,
   125  		},
   126  	}
   127  
   128  	for _, tc := range cases {
   129  		t.Run(tc.status.String(), func(t *testing.T) {
   130  			if actual := Failing(tc.status); actual != tc.expected {
   131  				t.Errorf("Failing(%v) got %t, want %t", tc.status, actual, tc.expected)
   132  			}
   133  		})
   134  	}
   135  }
   136  
   137  func TestIgnored(t *testing.T) {
   138  	cases := []struct {
   139  		name     string
   140  		status   statuspb.TestStatus
   141  		opts     *configpb.DashboardTabStatusCustomizationOptions
   142  		expected bool
   143  	}{
   144  		{
   145  			name:   "categorized abort ignored",
   146  			status: statuspb.TestStatus_CATEGORIZED_ABORT,
   147  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   148  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   149  					configpb.DashboardTabStatusCustomizationOptions_CATEGORIZED_ABORT,
   150  				},
   151  			},
   152  			expected: true,
   153  		},
   154  		{
   155  			name:   "categorized abort not ignored",
   156  			status: statuspb.TestStatus_CATEGORIZED_ABORT,
   157  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   158  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   159  					configpb.DashboardTabStatusCustomizationOptions_UNKNOWN,
   160  					configpb.DashboardTabStatusCustomizationOptions_BLOCKED,
   161  				},
   162  			},
   163  		},
   164  		{
   165  			name:   "unknown ignored",
   166  			status: statuspb.TestStatus_UNKNOWN,
   167  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   168  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   169  					configpb.DashboardTabStatusCustomizationOptions_UNKNOWN,
   170  					configpb.DashboardTabStatusCustomizationOptions_CANCEL,
   171  				},
   172  			},
   173  			expected: true,
   174  		},
   175  		{
   176  			name:   "unknown not ignored",
   177  			status: statuspb.TestStatus_UNKNOWN,
   178  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   179  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   180  					configpb.DashboardTabStatusCustomizationOptions_BLOCKED,
   181  					configpb.DashboardTabStatusCustomizationOptions_CANCEL,
   182  				},
   183  			},
   184  		},
   185  		{
   186  			name:   "cancel ignored",
   187  			status: statuspb.TestStatus_CANCEL,
   188  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   189  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   190  					configpb.DashboardTabStatusCustomizationOptions_CANCEL,
   191  					configpb.DashboardTabStatusCustomizationOptions_BLOCKED,
   192  				},
   193  			},
   194  			expected: true,
   195  		},
   196  		{
   197  			name:   "cancel not ignored",
   198  			status: statuspb.TestStatus_CANCEL,
   199  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   200  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   201  					configpb.DashboardTabStatusCustomizationOptions_BLOCKED,
   202  				},
   203  			},
   204  		},
   205  		{
   206  			name:   "blocked ignored",
   207  			status: statuspb.TestStatus_BLOCKED,
   208  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   209  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   210  					configpb.DashboardTabStatusCustomizationOptions_CANCEL,
   211  					configpb.DashboardTabStatusCustomizationOptions_BLOCKED,
   212  				},
   213  			},
   214  			expected: true,
   215  		},
   216  		{
   217  			name:   "blocked not ignored",
   218  			status: statuspb.TestStatus_BLOCKED,
   219  			opts: &configpb.DashboardTabStatusCustomizationOptions{
   220  				IgnoredTestStatuses: []configpb.DashboardTabStatusCustomizationOptions_IgnoredTestStatus{
   221  					configpb.DashboardTabStatusCustomizationOptions_CANCEL,
   222  				},
   223  			},
   224  		},
   225  		{
   226  			name:   "ignored statuses not set",
   227  			status: statuspb.TestStatus_BLOCKED,
   228  		},
   229  	}
   230  
   231  	for _, tc := range cases {
   232  		t.Run(tc.name, func(t *testing.T) {
   233  			if actual := Ignored(tc.status, tc.opts); actual != tc.expected {
   234  				t.Errorf("Ignored(%v) got %t, want %t", tc.status, actual, tc.expected)
   235  			}
   236  		})
   237  	}
   238  }
   239  
   240  func TestCoalesce(t *testing.T) {
   241  	cases := []struct {
   242  		status        statuspb.TestStatus
   243  		ignoreRunning bool
   244  		expected      statuspb.TestStatus
   245  	}{
   246  		{
   247  			status:        statuspb.TestStatus_NO_RESULT,
   248  			ignoreRunning: true,
   249  			expected:      statuspb.TestStatus_NO_RESULT,
   250  		},
   251  		{
   252  			status:   statuspb.TestStatus_NO_RESULT,
   253  			expected: statuspb.TestStatus_NO_RESULT,
   254  		},
   255  		{
   256  			status:   statuspb.TestStatus_BUILD_PASSED,
   257  			expected: statuspb.TestStatus_PASS,
   258  		},
   259  		{
   260  			status:   statuspb.TestStatus_PASS,
   261  			expected: statuspb.TestStatus_PASS,
   262  		},
   263  		{
   264  			status:        statuspb.TestStatus_PASS_WITH_ERRORS,
   265  			ignoreRunning: true,
   266  			expected:      statuspb.TestStatus_PASS,
   267  		},
   268  		{
   269  			status:        statuspb.TestStatus_RUNNING,
   270  			ignoreRunning: true,
   271  			expected:      statuspb.TestStatus_NO_RESULT,
   272  		},
   273  		{
   274  			status:   statuspb.TestStatus_RUNNING,
   275  			expected: statuspb.TestStatus_UNKNOWN,
   276  		},
   277  		{
   278  			status:   statuspb.TestStatus_CANCEL,
   279  			expected: statuspb.TestStatus_UNKNOWN,
   280  		},
   281  		{
   282  			status:        statuspb.TestStatus_TOOL_FAIL,
   283  			ignoreRunning: true,
   284  			expected:      statuspb.TestStatus_FAIL,
   285  		},
   286  		{
   287  			status:   statuspb.TestStatus_TOOL_FAIL,
   288  			expected: statuspb.TestStatus_FAIL,
   289  		},
   290  		{
   291  			status:        statuspb.TestStatus_CATEGORIZED_FAIL,
   292  			ignoreRunning: true,
   293  			expected:      statuspb.TestStatus_FAIL,
   294  		},
   295  		{
   296  			status:   statuspb.TestStatus_FAIL,
   297  			expected: statuspb.TestStatus_FAIL,
   298  		},
   299  	}
   300  
   301  	for _, tc := range cases {
   302  		name := fmt.Sprintf("Coalesce(%v,%t)", tc.status, tc.ignoreRunning)
   303  		t.Run(name, func(t *testing.T) {
   304  			if actual := Coalesce(tc.status, tc.ignoreRunning); actual != tc.expected {
   305  				t.Errorf("got %v, want %v", actual, tc.expected)
   306  			}
   307  		})
   308  	}
   309  }
   310  
   311  func TestIter(t *testing.T) {
   312  	stoi := func(s statuspb.TestStatus) int32 { return int32(s) }
   313  	cases := []struct {
   314  		name     string
   315  		ctx      context.Context
   316  		results  []int32
   317  		expected []statuspb.TestStatus
   318  	}{
   319  		{
   320  			name: "basically works",
   321  		},
   322  		{
   323  			name: "works correctly",
   324  			results: []int32{
   325  				stoi(statuspb.TestStatus_FAIL), 1,
   326  				stoi(statuspb.TestStatus_PASS), 2,
   327  				stoi(statuspb.TestStatus_FLAKY), 3,
   328  			},
   329  			expected: []statuspb.TestStatus{
   330  				statuspb.TestStatus_FAIL,
   331  				statuspb.TestStatus_PASS,
   332  				statuspb.TestStatus_PASS,
   333  				statuspb.TestStatus_FLAKY,
   334  				statuspb.TestStatus_FLAKY,
   335  				statuspb.TestStatus_FLAKY,
   336  			},
   337  		},
   338  	}
   339  
   340  	for _, tc := range cases {
   341  		t.Run(tc.name, func(t *testing.T) {
   342  			if tc.ctx == nil {
   343  				tc.ctx = context.Background()
   344  			}
   345  			var actual []statuspb.TestStatus
   346  			f := Iter(tc.results)
   347  			for {
   348  				item, more := f()
   349  				if !more {
   350  					break
   351  				}
   352  				actual = append(actual, item)
   353  			}
   354  			if !reflect.DeepEqual(actual, tc.expected) {
   355  				t.Errorf("Iter(%v) got %v, want %v", tc.results, actual, tc.expected)
   356  			}
   357  		})
   358  	}
   359  }
   360  
   361  const totalResults = 10e6
   362  
   363  func benchmarkResults(remain int32) []int32 {
   364  	rand.Seed(42)
   365  
   366  	var statuses []int32
   367  	for num := range statuspb.TestStatus_name {
   368  		statuses = append(statuses, num)
   369  	}
   370  	var results []int32
   371  	n := int32(len(statuses))
   372  	for remain > 0 {
   373  		result := rand.Int31() % n
   374  		count := rand.Int31() % 100
   375  		if count > remain {
   376  			count = remain
   377  		}
   378  		results = append(results, result, count)
   379  		remain -= count
   380  	}
   381  	return results
   382  }
   383  
   384  func BenchmarkIter(b *testing.B) {
   385  
   386  	loopCh := func(results []int32) int32 {
   387  		var n int32
   388  		ch := iterSlow(context.Background(), results)
   389  		for range ch {
   390  			n++
   391  		}
   392  		return n
   393  	}
   394  
   395  	loopF := func(results []int32) int32 {
   396  		var n int32
   397  		f := iterFast(results)
   398  		for {
   399  			_, more := f()
   400  			if !more {
   401  				break
   402  			}
   403  			n++
   404  		}
   405  		return n
   406  	}
   407  
   408  	const (
   409  		few  = 1e6
   410  		many = 10e6
   411  	)
   412  
   413  	cases := []struct {
   414  		name    string
   415  		results int32
   416  		loop    func([]int32) int32
   417  	}{
   418  		{
   419  			name:    "few chan",
   420  			results: few,
   421  			loop:    loopCh,
   422  		},
   423  		{
   424  			name:    "few func",
   425  			results: few,
   426  			loop:    loopF,
   427  		},
   428  		{
   429  			name:    "many chan",
   430  			results: many,
   431  			loop:    loopCh,
   432  		},
   433  		{
   434  			name:    "many func",
   435  			results: many,
   436  			loop:    loopF,
   437  		},
   438  	}
   439  
   440  	for _, tc := range cases {
   441  		b.Run(tc.name, func(b *testing.B) {
   442  			results := benchmarkResults(int32(tc.results))
   443  			b.ResetTimer()
   444  			for i := 0; i < b.N; i++ {
   445  				n := tc.loop(results)
   446  				if n != tc.results {
   447  					b.Fatalf("Got %d results, wanted %d", n, tc.results)
   448  				}
   449  			}
   450  		})
   451  	}
   452  }