github.com/GoogleCloudPlatform/testgrid@v0.0.174/metadata/job_test.go (about)

     1  /*
     2  Copyright 2019 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 metadata
    18  
    19  import (
    20  	"encoding/json"
    21  	"reflect"
    22  	"testing"
    23  )
    24  
    25  func TestMeta(t *testing.T) {
    26  	world := "world"
    27  	olam := "olam"
    28  	const key = "target-key"
    29  	cases := []struct {
    30  		name    string
    31  		in      Metadata
    32  		call    func(actual Metadata) (interface{}, bool)
    33  		val     interface{}
    34  		present bool
    35  	}{
    36  		{
    37  			name: "can match string",
    38  			in: Metadata{
    39  				key: world,
    40  			},
    41  			call: func(actual Metadata) (interface{}, bool) {
    42  				return actual.String(key)
    43  			},
    44  			val:     &world,
    45  			present: true,
    46  		},
    47  		{
    48  			name: "detect value is not a string",
    49  			in: Metadata{
    50  				key: Metadata{"super": "fancy"},
    51  			},
    52  			call: func(actual Metadata) (interface{}, bool) {
    53  				return actual.String(key)
    54  			},
    55  			val:     (*string)(nil),
    56  			present: true,
    57  		},
    58  		{
    59  			name: "can match metadata",
    60  			in: Metadata{
    61  				key: Metadata{
    62  					"super": "fancy",
    63  					"one":   1,
    64  				},
    65  			},
    66  			call: func(actual Metadata) (interface{}, bool) {
    67  				return actual.Meta(key)
    68  			},
    69  			val: &Metadata{
    70  				"super": "fancy",
    71  				"one":   1.0, // LOL json
    72  			},
    73  			present: true,
    74  		},
    75  		{
    76  			name: "detect value is not metadata",
    77  			in: Metadata{
    78  				key: "not metadata",
    79  			},
    80  			call: func(actual Metadata) (interface{}, bool) {
    81  				return actual.Meta(key)
    82  			},
    83  			val:     (*Metadata)(nil),
    84  			present: true,
    85  		},
    86  		{
    87  			name: "detect key absence for string",
    88  			in: Metadata{
    89  				"random-key": "hello",
    90  			},
    91  			call: func(actual Metadata) (interface{}, bool) {
    92  				return actual.String(key)
    93  			},
    94  			val: (*string)(nil),
    95  		},
    96  		{
    97  			name: "detect key absence for metadata",
    98  			in: Metadata{
    99  				"random-key": Metadata{},
   100  			},
   101  			call: func(actual Metadata) (interface{}, bool) {
   102  				return actual.Meta(key)
   103  			},
   104  			val: (*Metadata)(nil),
   105  		},
   106  		{
   107  			name: "get list of strings",
   108  			in: Metadata{
   109  				key: []string{world, olam},
   110  			},
   111  			call: func(actual Metadata) (interface{}, bool) {
   112  				return actual.MultiString(key)
   113  			},
   114  			val:     []string{world, olam},
   115  			present: true,
   116  		},
   117  		{
   118  			name: "get list of strings from list of interfaces",
   119  			in: Metadata{
   120  				key: []interface{}{world, olam},
   121  			},
   122  			call: func(actual Metadata) (interface{}, bool) {
   123  				return actual.MultiString(key)
   124  			},
   125  			val:     []string{world, olam},
   126  			present: true,
   127  		},
   128  		{
   129  			name: "non string in list of interfaces",
   130  			in: Metadata{
   131  				key: []interface{}{world, 1337},
   132  			},
   133  			call: func(actual Metadata) (interface{}, bool) {
   134  				return actual.MultiString(key)
   135  			},
   136  			val:     []string{},
   137  			present: true,
   138  		},
   139  		{
   140  			name: "not list of strings",
   141  			in: Metadata{
   142  				key: []int{42, 1337},
   143  			},
   144  			call: func(actual Metadata) (interface{}, bool) {
   145  				return actual.MultiString(key)
   146  			},
   147  			val:     []string{},
   148  			present: true,
   149  		},
   150  		{
   151  			name: "given empty list",
   152  			in: Metadata{
   153  				key: []interface{}{},
   154  			},
   155  			call: func(actual Metadata) (interface{}, bool) {
   156  				return actual.MultiString(key)
   157  			},
   158  			val:     []string{},
   159  			present: true,
   160  		},
   161  		{
   162  			name: "return empty list if key absence",
   163  			in: Metadata{
   164  				"random-key": []string{world},
   165  			},
   166  			call: func(actual Metadata) (interface{}, bool) {
   167  				return actual.MultiString(key)
   168  			},
   169  			val: []string{},
   170  		},
   171  	}
   172  
   173  	for _, tc := range cases {
   174  		t.Run(tc.name, func(t *testing.T) {
   175  			out, err := json.Marshal(tc.in)
   176  			if err != nil {
   177  				t.Errorf("marshal: %v", err)
   178  			}
   179  			var actual Metadata
   180  			if err := json.Unmarshal(out, &actual); err != nil {
   181  				t.Errorf("unmarshal: %v", err)
   182  			}
   183  			val, present := tc.call(actual)
   184  			if !reflect.DeepEqual(val, tc.val) {
   185  				t.Errorf("%#v != expected %#v", val, tc.val) // Remember json doesn't have ints
   186  			}
   187  			if present != tc.present {
   188  				t.Errorf("present %t != expected %t", present, tc.present)
   189  			}
   190  		})
   191  	}
   192  }
   193  
   194  func TestVersion(t *testing.T) {
   195  	cases := []struct {
   196  		name     string
   197  		started  Started
   198  		finished Finished
   199  		expected string
   200  	}{
   201  		{
   202  			name:     "missing by default",
   203  			expected: Missing,
   204  		},
   205  		{
   206  			name: "DEPRECATED: finished job version over started",
   207  			started: Started{
   208  				DeprecatedJobVersion: "wrong",
   209  			},
   210  			finished: Finished{
   211  				DeprecatedJobVersion: "right",
   212  			},
   213  			expected: "right",
   214  		},
   215  		{
   216  			name: "DEPRECATED: job version over repo version",
   217  			started: Started{
   218  				DeprecatedJobVersion:  "yes-job",
   219  				DeprecatedRepoVersion: "no-repo",
   220  			},
   221  			expected: "yes-job",
   222  		},
   223  		{
   224  			name: "DEPRECATED: started repo version over finished",
   225  			started: Started{
   226  				DeprecatedRepoVersion: "right",
   227  			},
   228  			finished: Finished{
   229  				DeprecatedRepoVersion: "wrong-finish",
   230  			},
   231  			expected: "right",
   232  		},
   233  		{
   234  			name: "job-version over repo-commit",
   235  			started: Started{
   236  				RepoCommit: "nope",
   237  			},
   238  			finished: Finished{
   239  				Metadata: Metadata{
   240  					JobVersion: "yes",
   241  				},
   242  			},
   243  			expected: "yes",
   244  		},
   245  		{
   246  			name: "find repo-commit",
   247  			started: Started{
   248  				RepoCommit: "yay",
   249  			},
   250  			expected: "yay",
   251  		},
   252  		{
   253  			name: "truncate to 9 chars",
   254  			started: Started{
   255  				RepoCommit: "12345678900000000",
   256  			},
   257  			expected: "123456789",
   258  		},
   259  		{
   260  			name: "drop part before the first +",
   261  			started: Started{
   262  				RepoCommit: "ignore+hello+yes",
   263  			},
   264  			expected: "hello+yes",
   265  		},
   266  		{
   267  			name: "trucate part after +",
   268  			started: Started{
   269  				RepoCommit: "deadbeef+12345678900000000",
   270  			},
   271  			expected: "123456789",
   272  		},
   273  	}
   274  
   275  	for _, tc := range cases {
   276  		t.Run(tc.name, func(t *testing.T) {
   277  			if actual := Version(tc.started, tc.finished); actual != tc.expected {
   278  				t.Errorf("actual %s != expected %s", actual, tc.expected)
   279  			}
   280  		})
   281  	}
   282  }
   283  
   284  func TestSetVersion(t *testing.T) {
   285  	cases := []struct {
   286  		name       string
   287  		repoCommit string
   288  		jobVersion string
   289  		started    bool
   290  		finished   bool
   291  		expected   string
   292  	}{
   293  		{
   294  			name:       "basically works",
   295  			repoCommit: "repo",
   296  			jobVersion: "job",
   297  			started:    true,
   298  			finished:   true,
   299  			expected:   "job",
   300  		},
   301  		{
   302  			name:     "missing by default",
   303  			started:  true,
   304  			finished: true,
   305  			expected: Missing,
   306  		},
   307  		{
   308  			name:       "can pass in nothing",
   309  			repoCommit: "ignore",
   310  			jobVersion: "me",
   311  			expected:   Missing,
   312  		},
   313  		{
   314  			name:       "match repo commit when job version not set",
   315  			repoCommit: "deadbeef",
   316  			started:    true,
   317  			finished:   true,
   318  			expected:   "deadbeef",
   319  		},
   320  		{
   321  			name:       "match repo commit when just started",
   322  			repoCommit: "aaa",
   323  			jobVersion: "ignore",
   324  			started:    true,
   325  			expected:   "aaa",
   326  		},
   327  	}
   328  
   329  	for _, tc := range cases {
   330  		t.Run(tc.name, func(t *testing.T) {
   331  			var s Started
   332  			var f Finished
   333  			var ps *Started
   334  			var pf *Finished
   335  			if tc.started {
   336  				ps = &s
   337  			}
   338  			if tc.finished {
   339  				pf = &f
   340  			}
   341  			SetVersion(ps, pf, tc.repoCommit, tc.jobVersion)
   342  			if actual := Version(s, f); actual != tc.expected {
   343  				t.Errorf("actual %s != expected %s", actual, tc.expected)
   344  			}
   345  		})
   346  	}
   347  
   348  }