github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/testgrid/cmd/updater/main_test.go (about)

     1  /*
     2  Copyright 2018 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 main
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	"github.com/golang/protobuf/proto"
    24  	"k8s.io/test-infra/testgrid/state"
    25  )
    26  
    27  func Test_ValidateName(t *testing.T) {
    28  	cases := []struct {
    29  		name      string
    30  		input     string
    31  		context   string
    32  		timestamp string
    33  		thread    string
    34  		empty     bool
    35  	}{
    36  
    37  		{
    38  			name:  "not junit",
    39  			input: "./started.json",
    40  			empty: true,
    41  		},
    42  		{
    43  			name:  "forgot suffix",
    44  			input: "./junit",
    45  			empty: true,
    46  		},
    47  		{
    48  			name:  "basic",
    49  			input: "./junit.xml",
    50  		},
    51  		{
    52  			name:    "context",
    53  			input:   "./junit_hello world isn't-this exciting!.xml",
    54  			context: "hello world isn't-this exciting!",
    55  		},
    56  		{
    57  			name:    "numeric context",
    58  			input:   "./junit_12345.xml",
    59  			context: "12345",
    60  		},
    61  		{
    62  			name:    "context and thread",
    63  			input:   "./junit_context_12345.xml",
    64  			context: "context",
    65  			thread:  "12345",
    66  		},
    67  		{
    68  			name:      "context and timestamp",
    69  			input:     "./junit_context_20180102-1234.xml",
    70  			context:   "context",
    71  			timestamp: "20180102-1234",
    72  		},
    73  		{
    74  			name:      "context thread timestamp",
    75  			input:     "./junit_context_20180102-1234_5555.xml",
    76  			context:   "context",
    77  			timestamp: "20180102-1234",
    78  			thread:    "5555",
    79  		},
    80  	}
    81  
    82  	for _, tc := range cases {
    83  		actual := ValidateName(tc.input)
    84  		switch {
    85  		case actual == nil && !tc.empty:
    86  			t.Errorf("%s: unexpected nil map", tc.name)
    87  		case actual != nil && tc.empty:
    88  			t.Errorf("%s: should not have returned a map: %v", tc.name, actual)
    89  		case actual != nil:
    90  			for k, expected := range map[string]string{
    91  				"Context":   tc.context,
    92  				"Thread":    tc.thread,
    93  				"Timestamp": tc.timestamp,
    94  			} {
    95  				if a, ok := actual[k]; !ok {
    96  					t.Errorf("%s: missing key %s", tc.name, k)
    97  				} else if a != expected {
    98  					t.Errorf("%s: %s actual %s != expected %s", tc.name, k, a, expected)
    99  				}
   100  			}
   101  		}
   102  	}
   103  
   104  }
   105  
   106  func Test_ExtractRows(t *testing.T) {
   107  	cases := []struct {
   108  		name     string
   109  		content  string
   110  		metadata map[string]string
   111  		rows     map[string][]Row
   112  		err      bool
   113  	}{
   114  		{
   115  			name:    "not xml",
   116  			content: `{"super": 123}`,
   117  			err:     true,
   118  		},
   119  		{
   120  			name:    "not junit",
   121  			content: `<amazing><content/></amazing>`,
   122  			err:     true,
   123  		},
   124  		{
   125  			name: "basic testsuite",
   126  			content: `
   127  			  <testsuite>
   128  			    <testcase name="good"/>
   129  			    <testcase name="bad"><failure/></testcase>
   130  			    <testcase name="skip"><skipped/></testcase>
   131  			  </testsuite>`,
   132  			rows: map[string][]Row{
   133  				"good": {
   134  					{
   135  						Result: state.Row_PASS,
   136  						Metadata: map[string]string{
   137  							"Tests name": "good",
   138  						},
   139  					},
   140  				},
   141  				"bad": {
   142  					{
   143  						Result: state.Row_FAIL,
   144  						Metadata: map[string]string{
   145  							"Tests name": "bad",
   146  						},
   147  					},
   148  				},
   149  			},
   150  		},
   151  		{
   152  			name: "basic testsuites",
   153  			content: `
   154  			  <testsuites>
   155  			  <testsuite>
   156  			    <testcase name="good"/>
   157  			  </testsuite>
   158  			  <testsuite>
   159  			    <testcase name="bad"><failure/></testcase>
   160  			    <testcase name="skip"><skipped/></testcase>
   161  			  </testsuite>
   162  			  </testsuites>`,
   163  			rows: map[string][]Row{
   164  				"good": {
   165  					{
   166  						Result: state.Row_PASS,
   167  						Metadata: map[string]string{
   168  							"Tests name": "good",
   169  						},
   170  					},
   171  				},
   172  				"bad": {
   173  					{
   174  						Result: state.Row_FAIL,
   175  						Metadata: map[string]string{
   176  							"Tests name": "bad",
   177  						},
   178  					},
   179  				},
   180  			},
   181  		},
   182  		{
   183  			name: "suite name",
   184  			content: `
   185  			  <testsuite name="hello">
   186  			    <testcase name="world" />
   187  			  </testsuite>`,
   188  			rows: map[string][]Row{
   189  				"hello.world": {
   190  					{
   191  						Result: state.Row_PASS,
   192  						Metadata: map[string]string{
   193  							"Tests name": "hello.world",
   194  						},
   195  					},
   196  				},
   197  			},
   198  		},
   199  		{
   200  			name: "duplicate target names",
   201  			content: `
   202  			  <testsuite>
   203  			    <testcase name="multi">
   204  			      <failure>doh</failure>
   205  		            </testcase>
   206  			    <testcase name="multi" />
   207  			  </testsuite>`,
   208  			rows: map[string][]Row{
   209  				"multi": {
   210  					{
   211  						Result: state.Row_FAIL,
   212  						Metadata: map[string]string{
   213  							"Tests name": "multi",
   214  						},
   215  					},
   216  					{
   217  						Result: state.Row_PASS,
   218  						Metadata: map[string]string{
   219  							"Tests name": "multi",
   220  						},
   221  					},
   222  				},
   223  			},
   224  		},
   225  		{
   226  			name: "basic timing",
   227  			content: `
   228  			  <testsuite>
   229  			    <testcase name="slow" time="100.1" />
   230  			    <testcase name="slow-failure" time="123456789">
   231  			      <failure>terrible</failure>
   232  			    </testcase>
   233  			    <testcase name="fast" time="0.0001" />
   234  			    <testcase name="nothing-elapsed" time="0" />
   235  			  </testsuite>`,
   236  			rows: map[string][]Row{
   237  				"slow": {
   238  					{
   239  						Result:  state.Row_PASS,
   240  						Metrics: map[string]float64{elapsedKey: 100.1},
   241  						Metadata: map[string]string{
   242  							"Tests name": "slow",
   243  						},
   244  					},
   245  				},
   246  				"slow-failure": {
   247  					{
   248  						Result:  state.Row_FAIL,
   249  						Metrics: map[string]float64{elapsedKey: 123456789},
   250  						Metadata: map[string]string{
   251  							"Tests name": "slow-failure",
   252  						},
   253  					},
   254  				},
   255  				"fast": {
   256  					{
   257  						Result:  state.Row_PASS,
   258  						Metrics: map[string]float64{elapsedKey: 0.0001},
   259  						Metadata: map[string]string{
   260  							"Tests name": "fast",
   261  						},
   262  					},
   263  				},
   264  				"nothing-elapsed": {
   265  					{
   266  						Result: state.Row_PASS,
   267  						Metadata: map[string]string{
   268  							"Tests name": "nothing-elapsed",
   269  						},
   270  					},
   271  				},
   272  			},
   273  		},
   274  		{
   275  			name: "add metadata",
   276  			content: `
   277  			  <testsuite>
   278  			    <testcase name="fancy" />
   279  			    <testcase name="ketchup" />
   280  			  </testsuite>`,
   281  			metadata: map[string]string{
   282  				"Context":   "debian",
   283  				"Timestamp": "1234",
   284  				"Thread":    "7",
   285  			},
   286  			rows: map[string][]Row{
   287  				"fancy": {
   288  					{
   289  						Result: state.Row_PASS,
   290  						Metadata: map[string]string{
   291  							"Tests name": "fancy",
   292  							"Context":    "debian",
   293  							"Timestamp":  "1234",
   294  							"Thread":     "7",
   295  						},
   296  					},
   297  				},
   298  				"ketchup": {
   299  					{
   300  						Result: state.Row_PASS,
   301  						Metadata: map[string]string{
   302  							"Tests name": "ketchup",
   303  							"Context":    "debian",
   304  							"Timestamp":  "1234",
   305  							"Thread":     "7",
   306  						},
   307  					},
   308  				},
   309  			},
   310  		},
   311  	}
   312  
   313  	for _, tc := range cases {
   314  		rows := map[string][]Row{}
   315  
   316  		rows, err := extractRows([]byte(tc.content), tc.metadata)
   317  		switch {
   318  		case err == nil && tc.err:
   319  			t.Errorf("%s: failed to raise an error", tc.name)
   320  		case err != nil && !tc.err:
   321  			t.Errorf("%s: unexpected err: %v", tc.name, err)
   322  		case len(rows) > len(tc.rows):
   323  			t.Errorf("%s: extra rows: actual %v != expected %v", tc.name, rows, tc.rows)
   324  		default:
   325  			for target, expectedRows := range tc.rows {
   326  				actualRows, ok := rows[target]
   327  				if !ok {
   328  					t.Errorf("%s: missing row %s", tc.name, target)
   329  					continue
   330  				} else if len(actualRows) != len(expectedRows) {
   331  					t.Errorf("%s: bad results for %s: actual %v != expected %v", tc.name, target, actualRows, expectedRows)
   332  					continue
   333  				}
   334  				for i, er := range expectedRows {
   335  					ar := actualRows[i]
   336  					if er.Result != ar.Result {
   337  						t.Errorf("%s: %s %d actual %v != expected %v", tc.name, target, i, ar.Result, er.Result)
   338  					}
   339  
   340  					if len(ar.Metrics) > len(er.Metrics) {
   341  						t.Errorf("%s: extra %s %d metrics: actual %v != expected %v", tc.name, target, i, ar.Metrics, er.Metrics)
   342  					} else {
   343  						for m, ev := range er.Metrics {
   344  							if av, ok := ar.Metrics[m]; !ok {
   345  								t.Errorf("%s: %s %d missing %s metric", tc.name, target, i, m)
   346  							} else if ev != av {
   347  								t.Errorf("%s: %s %d bad %s metric: actual %f != expected %f", tc.name, target, i, m, av, ev)
   348  							}
   349  						}
   350  					}
   351  
   352  					if len(ar.Metadata) > len(er.Metadata) {
   353  						t.Errorf("%s: extra %s %d metadata: actual %v != expected %v", tc.name, target, i, ar.Metadata, er.Metadata)
   354  					} else {
   355  						for m, ev := range er.Metadata {
   356  							if av, ok := ar.Metadata[m]; !ok {
   357  								t.Errorf("%s: %s %d missing %s metadata", tc.name, target, i, m)
   358  							} else if ev != av {
   359  								t.Errorf("%s: %s %d bad %s metadata: actual %s != expected %s", tc.name, target, i, m, av, ev)
   360  							}
   361  						}
   362  					}
   363  				}
   364  			}
   365  		}
   366  	}
   367  }
   368  
   369  func Test_MarshalGrid(t *testing.T) {
   370  	g1 := state.Grid{
   371  		Columns: []*state.Column{
   372  			{Build: "alpha"},
   373  			{Build: "second"},
   374  		},
   375  	}
   376  	g2 := state.Grid{
   377  		Columns: []*state.Column{
   378  			{Build: "first"},
   379  			{Build: "second"},
   380  		},
   381  	}
   382  
   383  	b1, e1 := marshalGrid(g1)
   384  	b2, e2 := marshalGrid(g2)
   385  	uncompressed, e1a := proto.Marshal(&g1)
   386  
   387  	switch {
   388  	case e1 != nil, e2 != nil:
   389  		t.Errorf("unexpected error %v %v %v", e1, e2, e1a)
   390  	}
   391  
   392  	if reflect.DeepEqual(b1, b2) {
   393  		t.Errorf("unexpected equality %v == %v", b1, b2)
   394  	}
   395  
   396  	if reflect.DeepEqual(b1, uncompressed) {
   397  		t.Errorf("should be compressed but is not: %v", b1)
   398  	}
   399  }