k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/releng/config-forker/main_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 main
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  
    23  	"github.com/google/go-cmp/cmp"
    24  	"github.com/google/go-cmp/cmp/cmpopts"
    25  
    26  	v1 "k8s.io/api/core/v1"
    27  	"k8s.io/apimachinery/pkg/util/diff"
    28  	prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    29  	"sigs.k8s.io/prow/pkg/config"
    30  )
    31  
    32  func TestCleanAnnotations(t *testing.T) {
    33  	tests := []struct {
    34  		name        string
    35  		annotations map[string]string
    36  		expected    map[string]string
    37  	}{
    38  		{
    39  			name:        "no annotations",
    40  			annotations: map[string]string{},
    41  			expected:    map[string]string{},
    42  		},
    43  		{
    44  			name: "only removable annotations",
    45  			annotations: map[string]string{
    46  				forkAnnotation:        "true",
    47  				replacementAnnotation: "foo -> bar",
    48  			},
    49  			expected: map[string]string{},
    50  		},
    51  		{
    52  			name: "all our annotations",
    53  			annotations: map[string]string{
    54  				forkAnnotation:             "true",
    55  				replacementAnnotation:      "foo -> bar",
    56  				periodicIntervalAnnotation: "2h",
    57  			},
    58  			expected: map[string]string{
    59  				periodicIntervalAnnotation: "2h",
    60  			},
    61  		},
    62  		{
    63  			name: "foreign annotations",
    64  			annotations: map[string]string{
    65  				"someOtherAnnotation": "pony party",
    66  			},
    67  			expected: map[string]string{
    68  				"someOtherAnnotation": "pony party",
    69  			},
    70  		},
    71  		{
    72  			name: "blank periodic annotations",
    73  			annotations: map[string]string{
    74  				periodicIntervalAnnotation: "",
    75  				cronAnnotation:             "",
    76  			},
    77  			expected: map[string]string{},
    78  		},
    79  	}
    80  
    81  	for _, tc := range tests {
    82  		t.Run(tc.name, func(t *testing.T) {
    83  			oldAnnotations := map[string]string{}
    84  			for k, v := range tc.annotations {
    85  				oldAnnotations[k] = v
    86  			}
    87  			result := cleanAnnotations(tc.annotations)
    88  			if !reflect.DeepEqual(result, tc.expected) {
    89  				t.Errorf("Expected result %#v', got %#v", tc.expected, result)
    90  			}
    91  			if !reflect.DeepEqual(oldAnnotations, tc.annotations) {
    92  				t.Errorf("Input annotations map changed: used to be %#v, now %#v", oldAnnotations, tc.annotations)
    93  			}
    94  		})
    95  	}
    96  }
    97  
    98  func TestEvaluateTemplate(t *testing.T) {
    99  	const expected = "Foo Substitution! Baz"
   100  	result, err := evaluateTemplate("Foo {{.Bar}} Baz", map[string]string{"Bar": "Substitution!"})
   101  	if err != nil {
   102  		t.Fatalf("Unexpected error: %v", err)
   103  	}
   104  	if result != expected {
   105  		t.Errorf("Expected result %q, got %q", expected, result)
   106  	}
   107  }
   108  
   109  func TestPerformArgReplacements(t *testing.T) {
   110  	tests := []struct {
   111  		name         string
   112  		args         []string
   113  		replacements string
   114  		expected     []string
   115  		expectErr    bool
   116  	}{
   117  		{
   118  			name:         "nil arguments remain nil",
   119  			args:         nil,
   120  			replacements: "foo -> bar",
   121  			expected:     nil,
   122  		},
   123  		{
   124  			name:         "empty arguments remain empty",
   125  			args:         []string{},
   126  			replacements: "foo -> bar",
   127  			expected:     []string{},
   128  		},
   129  		{
   130  			name:         "empty replacements do nothing",
   131  			args:         []string{"foo", "bar"},
   132  			replacements: "",
   133  			expected:     []string{"foo", "bar"},
   134  		},
   135  		{
   136  			name:         "simple replacement works",
   137  			args:         []string{"foos", "bars", "bazzes"},
   138  			replacements: "foo -> bar",
   139  			expected:     []string{"bars", "bars", "bazzes"},
   140  		},
   141  		{
   142  			name:         "multiple replacements work",
   143  			args:         []string{"some foos", "bars", "bazzes"},
   144  			replacements: "foo -> bar, bars -> bazzes",
   145  			expected:     []string{"some bars", "bazzes", "bazzes"},
   146  		},
   147  		{
   148  			name:         "template expansion works",
   149  			args:         []string{"version: special one"},
   150  			replacements: "special one -> {{.Version}}",
   151  			expected:     []string{"version: 1.15"},
   152  		},
   153  		{
   154  			name:         "invalid template is an error",
   155  			args:         []string{"version: special one"},
   156  			replacements: "special one -> {{Version}}",
   157  			expectErr:    true,
   158  		},
   159  		{
   160  			name:         "unparseable replacements are an error",
   161  			args:         []string{"foo"},
   162  			replacements: "foo -> bar, baz",
   163  			expectErr:    true,
   164  		},
   165  	}
   166  
   167  	for _, tc := range tests {
   168  		t.Run(tc.name, func(t *testing.T) {
   169  			result, err := performReplacement(tc.args, templateVars{Version: "1.15"}, tc.replacements)
   170  			if err != nil {
   171  				if !tc.expectErr {
   172  					t.Fatalf("Unexpected error: %v", err)
   173  				}
   174  				return
   175  			}
   176  			if tc.expectErr {
   177  				t.Fatalf("Expected an error, but got %v", result)
   178  			}
   179  			if !reflect.DeepEqual(result, tc.expected) {
   180  				t.Errorf("Expected result %v, but got %v instead", tc.expected, result)
   181  			}
   182  		})
   183  	}
   184  }
   185  
   186  func TestPerformArgDeletions(t *testing.T) {
   187  	tests := []struct {
   188  		name      string
   189  		args      map[string]string
   190  		deletions string
   191  		expected  map[string]string
   192  	}{
   193  		{
   194  			name:      "nil arguments remain nil",
   195  			args:      nil,
   196  			deletions: "",
   197  			expected:  nil,
   198  		},
   199  		{
   200  			name:      "empty arguments remain empty",
   201  			args:      map[string]string{},
   202  			deletions: "",
   203  			expected:  map[string]string{},
   204  		},
   205  		{
   206  			name:      "empty deletions do nothing",
   207  			args:      map[string]string{"foo": "bar"},
   208  			deletions: "",
   209  			expected:  map[string]string{"foo": "bar"},
   210  		},
   211  		{
   212  			name:      "simple deletion works",
   213  			args:      map[string]string{"foo": "bar", "baz": "baz2"},
   214  			deletions: "foo",
   215  			expected:  map[string]string{"baz": "baz2"},
   216  		},
   217  		{
   218  			name:      "multiple deletions work",
   219  			args:      map[string]string{"foo": "bar", "baz": "baz2", "hello": "world"},
   220  			deletions: "foo, baz",
   221  			expected:  map[string]string{"hello": "world"},
   222  		},
   223  	}
   224  
   225  	for _, tc := range tests {
   226  		t.Run(tc.name, func(t *testing.T) {
   227  			result := performDeletion(tc.args, tc.deletions)
   228  			if !reflect.DeepEqual(result, tc.expected) {
   229  				t.Errorf("Expected result %v, but got %v instead", tc.expected, result)
   230  			}
   231  		})
   232  	}
   233  }
   234  
   235  func TestFixImage(t *testing.T) {
   236  	tests := []struct {
   237  		name     string
   238  		image    string
   239  		expected string
   240  	}{
   241  		{
   242  			name:     "replaces -master with -[version]",
   243  			image:    "kubekins-e2e-blahblahblah-master",
   244  			expected: "kubekins-e2e-blahblahblah-1.15",
   245  		},
   246  		{
   247  			name:     "does nothing with non-master images",
   248  			image:    "golang:1.12.2",
   249  			expected: "golang:1.12.2",
   250  		},
   251  	}
   252  
   253  	for _, tc := range tests {
   254  		t.Run(tc.name, func(t *testing.T) {
   255  			if result := fixImage(tc.image, "1.15"); result != tc.expected {
   256  				t.Errorf("Expected %q, but got %q", tc.expected, result)
   257  			}
   258  		})
   259  	}
   260  }
   261  
   262  func TestFixBootstrapArgs(t *testing.T) {
   263  	tests := []struct {
   264  		name     string
   265  		args     []string
   266  		expected []string
   267  	}{
   268  		{
   269  			name:     "replaces repo with no branch specified",
   270  			args:     []string{"--repo=k8s.io/kubernetes"},
   271  			expected: []string{"--repo=k8s.io/kubernetes=release-1.15"},
   272  		},
   273  		{
   274  			name:     "replaces repo with master branch specified",
   275  			args:     []string{"--repo=k8s.io/kubernetes=master"},
   276  			expected: []string{"--repo=k8s.io/kubernetes=release-1.15"},
   277  		},
   278  		{
   279  			name:     "replaces master branch with release branch",
   280  			args:     []string{"--branch=master"},
   281  			expected: []string{"--branch=release-1.15"},
   282  		},
   283  		{
   284  			name:     "replaces both repo and branch",
   285  			args:     []string{"--repo=k8s.io/kubernetes=master", "--branch=master"},
   286  			expected: []string{"--repo=k8s.io/kubernetes=release-1.15", "--branch=release-1.15"},
   287  		},
   288  		{
   289  			name:     "doesn't replace other repos",
   290  			args:     []string{"--repo=k8s.io/test-infra"},
   291  			expected: []string{"--repo=k8s.io/test-infra"},
   292  		},
   293  		{
   294  			name:     "doesn't touch other flags",
   295  			args:     []string{"--foo=bar", "--branch=master"},
   296  			expected: []string{"--foo=bar", "--branch=release-1.15"},
   297  		},
   298  		{
   299  			name:     "nil args are still nil",
   300  			args:     nil,
   301  			expected: nil,
   302  		},
   303  	}
   304  
   305  	for _, tc := range tests {
   306  		t.Run(tc.name, func(t *testing.T) {
   307  			if result := fixBootstrapArgs(tc.args, "1.15"); !reflect.DeepEqual(result, tc.expected) {
   308  				t.Errorf("Expected args %v, but got %v instead", tc.expected, result)
   309  			}
   310  		})
   311  	}
   312  }
   313  
   314  func TestFixExtraRefs(t *testing.T) {
   315  	tests := []struct {
   316  		name     string
   317  		refs     []prowapi.Refs
   318  		expected []prowapi.Refs
   319  	}{
   320  		{
   321  			name:     "replaces kubernetes master with release branch",
   322  			refs:     []prowapi.Refs{{Org: "kubernetes", Repo: "kubernetes", BaseRef: "master"}},
   323  			expected: []prowapi.Refs{{Org: "kubernetes", Repo: "kubernetes", BaseRef: "release-1.15"}},
   324  		},
   325  		{
   326  			name:     "ignores kubernetes repos other than kubernetes",
   327  			refs:     []prowapi.Refs{{Org: "kubernetes", Repo: "test-infra", BaseRef: "master"}},
   328  			expected: []prowapi.Refs{{Org: "kubernetes", Repo: "test-infra", BaseRef: "master"}},
   329  		},
   330  		{
   331  			name:     "ignores repos called kubernetes in other orgs",
   332  			refs:     []prowapi.Refs{{Org: "Katharine", Repo: "kubernetes", BaseRef: "master"}},
   333  			expected: []prowapi.Refs{{Org: "Katharine", Repo: "kubernetes", BaseRef: "master"}},
   334  		},
   335  		{
   336  			name:     "ignores non-master branches",
   337  			refs:     []prowapi.Refs{{Org: "kubernetes", Repo: "kubernetes", BaseRef: "other-branch"}},
   338  			expected: []prowapi.Refs{{Org: "kubernetes", Repo: "kubernetes", BaseRef: "other-branch"}},
   339  		},
   340  		{
   341  			name:     "handles multiple refs",
   342  			refs:     []prowapi.Refs{{Org: "kubernetes", Repo: "test-infra", BaseRef: "master"}, {Org: "kubernetes", Repo: "kubernetes", BaseRef: "master"}},
   343  			expected: []prowapi.Refs{{Org: "kubernetes", Repo: "test-infra", BaseRef: "master"}, {Org: "kubernetes", Repo: "kubernetes", BaseRef: "release-1.15"}},
   344  		},
   345  	}
   346  
   347  	for _, tc := range tests {
   348  		t.Run(tc.name, func(t *testing.T) {
   349  			if result := fixExtraRefs(tc.refs, "1.15"); !reflect.DeepEqual(result, tc.expected) {
   350  				t.Errorf("Result does not match expected. Difference:\n%s", diff.ObjectDiff(tc.expected, result))
   351  			}
   352  		})
   353  	}
   354  }
   355  
   356  func TestFixEnvVars(t *testing.T) {
   357  	tests := []struct {
   358  		name     string
   359  		vars     []v1.EnvVar
   360  		expected []v1.EnvVar
   361  	}{
   362  		{
   363  			name:     "replaces BRANCH-like jobs referencing master",
   364  			vars:     []v1.EnvVar{{Name: "KUBERNETES_BRANCH", Value: "master"}},
   365  			expected: []v1.EnvVar{{Name: "KUBERNETES_BRANCH", Value: "release-1.15"}},
   366  		},
   367  		{
   368  			name:     "ignores BRANCH-like jobs referencing something else",
   369  			vars:     []v1.EnvVar{{Name: "KUBERNETES_BRANCH", Value: "something-else"}},
   370  			expected: []v1.EnvVar{{Name: "KUBERNETES_BRANCH", Value: "something-else"}},
   371  		},
   372  		{
   373  			name:     "names are case-insensitive",
   374  			vars:     []v1.EnvVar{{Name: "branch", Value: "master"}},
   375  			expected: []v1.EnvVar{{Name: "branch", Value: "release-1.15"}},
   376  		},
   377  		{
   378  			name:     "other vars are not touched",
   379  			vars:     []v1.EnvVar{{Name: "foo", Value: "bar"}, {Name: "baz", ValueFrom: &v1.EnvVarSource{SecretKeyRef: &v1.SecretKeySelector{Key: "baz-secret"}}}},
   380  			expected: []v1.EnvVar{{Name: "foo", Value: "bar"}, {Name: "baz", ValueFrom: &v1.EnvVarSource{SecretKeyRef: &v1.SecretKeySelector{Key: "baz-secret"}}}},
   381  		},
   382  	}
   383  
   384  	for _, tc := range tests {
   385  		t.Run(tc.name, func(t *testing.T) {
   386  			if result := fixEnvVars(tc.vars, "1.15"); !reflect.DeepEqual(result, tc.expected) {
   387  				t.Errorf("Result does not match expected. Difference:\n%s", diff.ObjectDiff(tc.expected, result))
   388  			}
   389  		})
   390  	}
   391  }
   392  
   393  func TestFixTestgridAnnotations(t *testing.T) {
   394  	tests := []struct {
   395  		name        string
   396  		annotations map[string]string
   397  		expected    map[string]string
   398  		isPresubmit bool
   399  	}{
   400  		{
   401  			name:        "remove presubmit additions to dashboards",
   402  			annotations: map[string]string{testgridDashboardsAnnotation: "sig-release-master-blocking, google-unit"},
   403  			expected:    map[string]string{},
   404  			isPresubmit: true,
   405  		},
   406  		{
   407  			name:        "periodic updates master-blocking to point at 1.15-blocking",
   408  			annotations: map[string]string{testgridDashboardsAnnotation: "sig-release-master-blocking"},
   409  			expected:    map[string]string{testgridDashboardsAnnotation: "sig-release-1.15-blocking"},
   410  			isPresubmit: false,
   411  		},
   412  		{
   413  			name:        "periodic updates with no dashboard annotation points to job-config-errors",
   414  			annotations: map[string]string{},
   415  			expected:    map[string]string{testgridDashboardsAnnotation: "sig-release-job-config-errors"},
   416  			isPresubmit: false,
   417  		},
   418  		{
   419  			name:        "drop 'description'",
   420  			annotations: map[string]string{descriptionAnnotation: "some description"},
   421  			expected:    map[string]string{},
   422  			isPresubmit: true,
   423  		},
   424  		{
   425  			name:        "update tab names",
   426  			annotations: map[string]string{testgridTabNameAnnotation: "foo master"},
   427  			expected:    map[string]string{testgridDashboardsAnnotation: "sig-release-job-config-errors", testgridTabNameAnnotation: "foo 1.15"},
   428  			isPresubmit: false,
   429  		},
   430  	}
   431  
   432  	for _, tc := range tests {
   433  		t.Run(tc.name, func(t *testing.T) {
   434  			result := fixTestgridAnnotations(tc.annotations, "1.15", tc.isPresubmit)
   435  			if !reflect.DeepEqual(result, tc.expected) {
   436  				t.Errorf("Result does not match expected. Difference:\n%s", diff.ObjectDiff(tc.expected, result))
   437  			}
   438  		})
   439  	}
   440  }
   441  
   442  func TestGenerateNameVariant(t *testing.T) {
   443  	tests := []struct {
   444  		name          string
   445  		testName      string
   446  		genericSuffix bool
   447  		expected      string
   448  	}{
   449  		{
   450  			name:     "jobs ending in -master have it replaced with a version",
   451  			testName: "ci-party-master",
   452  			expected: "ci-party-1-15",
   453  		},
   454  		{
   455  			name:          "generic jobs ending in -master have it replaced with -beta",
   456  			testName:      "ci-party-master",
   457  			genericSuffix: true,
   458  			expected:      "ci-party-beta",
   459  		},
   460  		{
   461  			name:     "jobs not ending in in -master have a number appended",
   462  			testName: "ci-party",
   463  			expected: "ci-party-1-15",
   464  		},
   465  		{
   466  			name:          "generic jobs not ending in in -master have 'beta' appended",
   467  			testName:      "ci-party",
   468  			genericSuffix: true,
   469  			expected:      "ci-party-beta",
   470  		},
   471  	}
   472  
   473  	for _, tc := range tests {
   474  		t.Run(tc.name, func(t *testing.T) {
   475  			if result := generateNameVariant(tc.testName, "1.15", tc.genericSuffix); result != tc.expected {
   476  				t.Errorf("Expected name %q, but got name %q.", tc.expected, result)
   477  			}
   478  		})
   479  	}
   480  }
   481  
   482  func TestGeneratePresubmits(t *testing.T) {
   483  	presubmits := map[string][]config.Presubmit{
   484  		"kubernetes/kubernetes": {
   485  			{
   486  				JobBase: config.JobBase{
   487  					Name:        "pull-kubernetes-e2e",
   488  					Annotations: map[string]string{forkAnnotation: "true"},
   489  				},
   490  				Brancher: config.Brancher{
   491  					SkipBranches: []string{`release-\d\.\d`},
   492  				},
   493  			},
   494  			{
   495  				JobBase: config.JobBase{
   496  					Name:        "pull-kubernetes-e2e-branch-in-name-master",
   497  					Annotations: map[string]string{forkAnnotation: "true"},
   498  				},
   499  				Brancher: config.Brancher{
   500  					SkipBranches: []string{`release-\d\.\d`},
   501  				},
   502  			},
   503  			{
   504  				JobBase: config.JobBase{
   505  					Name:        "pull-kubernetes-e2e-keep-context",
   506  					Annotations: map[string]string{forkAnnotation: "true"},
   507  				},
   508  				Brancher: config.Brancher{
   509  					SkipBranches: []string{`release-\d\.\d`},
   510  				},
   511  				Reporter: config.Reporter{
   512  					Context: "mycontext",
   513  				},
   514  			},
   515  			{
   516  				JobBase: config.JobBase{
   517  					Name:        "pull-kubernetes-e2e-replace-context",
   518  					Annotations: map[string]string{forkAnnotation: "true"},
   519  				},
   520  				Brancher: config.Brancher{
   521  					SkipBranches: []string{`release-\d\.\d`},
   522  				},
   523  				Reporter: config.Reporter{
   524  					Context: "mycontext-master",
   525  				},
   526  			},
   527  			{
   528  				JobBase: config.JobBase{
   529  					Name: "pull-replace-some-things",
   530  					Annotations: map[string]string{
   531  						forkAnnotation:                 "true",
   532  						replacementAnnotation:          "foo -> {{.Version}}, GO_VERSION= -> GO_VERSION={{.GoVersion}}",
   533  						"testgrid-generate-test-group": "true",
   534  						"some-annotation":              "yup",
   535  					},
   536  					Spec: &v1.PodSpec{
   537  						Containers: []v1.Container{
   538  							{
   539  								Image:   "gcr.io/k8s-staging-test-infra/kubekins-e2e:blahblahblah-master",
   540  								Command: []string{"--arg1=test", "--something=foo"},
   541  								Args:    []string{"--repo=k8s.io/kubernetes", "--something=foo"},
   542  								Env:     []v1.EnvVar{{Name: "BRANCH", Value: "master"}, {Name: "GO_VERSION"}},
   543  							},
   544  						},
   545  					},
   546  				},
   547  				Brancher: config.Brancher{
   548  					SkipBranches: []string{`release-\d\.\d`},
   549  				},
   550  			},
   551  			{
   552  				JobBase: config.JobBase{
   553  					Name:        "pull-not-forked",
   554  					Annotations: map[string]string{"foo": "bar"},
   555  				},
   556  			},
   557  		},
   558  	}
   559  
   560  	expected := map[string][]config.Presubmit{
   561  		"kubernetes/kubernetes": {
   562  			{
   563  				JobBase: config.JobBase{
   564  					Name:        "pull-kubernetes-e2e",
   565  					Annotations: map[string]string{},
   566  				},
   567  				Brancher: config.Brancher{
   568  					Branches: []string{"release-1.15"},
   569  				},
   570  				Reporter: config.Reporter{
   571  					Context: "pull-kubernetes-e2e",
   572  				},
   573  			},
   574  			{
   575  				JobBase: config.JobBase{
   576  					Name:        "pull-kubernetes-e2e-branch-in-name-master",
   577  					Annotations: map[string]string{},
   578  				},
   579  				Brancher: config.Brancher{
   580  					Branches: []string{"release-1.15"},
   581  				},
   582  				Reporter: config.Reporter{
   583  					Context: "pull-kubernetes-e2e-branch-in-name-1.15",
   584  				},
   585  			},
   586  			{
   587  				JobBase: config.JobBase{
   588  					Name:        "pull-kubernetes-e2e-keep-context",
   589  					Annotations: map[string]string{},
   590  				},
   591  				Brancher: config.Brancher{
   592  					Branches: []string{"release-1.15"},
   593  				},
   594  				Reporter: config.Reporter{
   595  					Context: "mycontext",
   596  				},
   597  			},
   598  			{
   599  				JobBase: config.JobBase{
   600  					Name:        "pull-kubernetes-e2e-replace-context",
   601  					Annotations: map[string]string{},
   602  				},
   603  				Brancher: config.Brancher{
   604  					Branches: []string{"release-1.15"},
   605  				},
   606  				Reporter: config.Reporter{
   607  					Context: "mycontext-1.15",
   608  				},
   609  			},
   610  			{
   611  				JobBase: config.JobBase{
   612  					Name: "pull-replace-some-things",
   613  					Annotations: map[string]string{
   614  						"some-annotation": "yup",
   615  					},
   616  					Spec: &v1.PodSpec{
   617  						Containers: []v1.Container{
   618  							{
   619  								Image:   "gcr.io/k8s-staging-test-infra/kubekins-e2e:blahblahblah-1.15",
   620  								Command: []string{"--arg1=test", "--something=1.15"},
   621  								Args:    []string{"--repo=k8s.io/kubernetes", "--something=1.15"},
   622  								Env:     []v1.EnvVar{{Name: "BRANCH", Value: "release-1.15"}, {Name: "GO_VERSION", Value: "1.20.2"}},
   623  							},
   624  						},
   625  					},
   626  				},
   627  				Brancher: config.Brancher{
   628  					Branches: []string{"release-1.15"},
   629  				},
   630  				Reporter: config.Reporter{
   631  					Context: "pull-replace-some-things",
   632  				},
   633  			},
   634  		},
   635  	}
   636  
   637  	result, err := generatePresubmits(config.JobConfig{PresubmitsStatic: presubmits}, templateVars{Version: "1.15", GoVersion: "1.20.2"})
   638  	if err != nil {
   639  		t.Fatalf("Unexpected error: %v", err)
   640  	}
   641  
   642  	if !reflect.DeepEqual(result, expected) {
   643  		t.Errorf("Result does not match expected. Difference:\n%s", cmp.Diff(expected, result, cmpopts.IgnoreUnexported(config.Brancher{}, config.RegexpChangeMatcher{}, config.Presubmit{})))
   644  	}
   645  }
   646  
   647  func TestGeneratePeriodics(t *testing.T) {
   648  	yes := true
   649  	periodics := []config.Periodic{
   650  		{
   651  			Cron: "0 * * * *",
   652  			JobBase: config.JobBase{
   653  				Name:        "some-forked-periodic-master",
   654  				Annotations: map[string]string{forkAnnotation: "true"},
   655  			},
   656  		},
   657  		{
   658  			Cron: "0 * * * *",
   659  			JobBase: config.JobBase{
   660  				Name:        "some-generic-periodic-master",
   661  				Annotations: map[string]string{forkAnnotation: "true", suffixAnnotation: "true"},
   662  			},
   663  		},
   664  		{
   665  			Cron: "0 * * * *",
   666  			JobBase: config.JobBase{
   667  				Name: "generic-periodic-with-deletions-master",
   668  				Annotations: map[string]string{
   669  					forkAnnotation:     "true",
   670  					deletionAnnotation: "preset-e2e-scalability-periodics-master",
   671  					suffixAnnotation:   "true",
   672  				},
   673  				Labels: map[string]string{
   674  					"preset-e2e-scalability-periodics":        "true",
   675  					"preset-e2e-scalability-periodics-master": "true",
   676  				},
   677  			},
   678  		},
   679  		{
   680  			Interval: "1h",
   681  			JobBase: config.JobBase{
   682  				Name: "periodic-with-replacements",
   683  				Annotations: map[string]string{
   684  					forkAnnotation:             "true",
   685  					periodicIntervalAnnotation: "6h 12h 24h 24h",
   686  					replacementAnnotation:      "stable -> {{.Version}}, GO_VERSION= -> GO_VERSION={{.GoVersion}}",
   687  				},
   688  				Spec: &v1.PodSpec{
   689  					Containers: []v1.Container{
   690  						{
   691  							Image:   "gcr.io/k8s-testinfra/kubekins-e2e:blahblahblah-master",
   692  							Command: []string{"--args1=test", "--version=stable"},
   693  							Args:    []string{"--repo=k8s.io/kubernetes", "--version=stable"},
   694  							Env:     []v1.EnvVar{{Name: "BRANCH", Value: "master"}, {Name: "GO_VERSION"}},
   695  						},
   696  					},
   697  				},
   698  			},
   699  			Tags: []string{"ver: stable"},
   700  		},
   701  		{
   702  			Interval: "2h",
   703  			JobBase: config.JobBase{
   704  				Name: "decorated-periodic",
   705  				Annotations: map[string]string{
   706  					forkAnnotation: "true",
   707  				},
   708  				UtilityConfig: config.UtilityConfig{
   709  					Decorate:  &yes,
   710  					ExtraRefs: []prowapi.Refs{{Org: "kubernetes", Repo: "kubernetes", BaseRef: "master"}},
   711  				},
   712  			},
   713  		},
   714  		{
   715  			JobBase: config.JobBase{
   716  				Name: "not-forked",
   717  			},
   718  		},
   719  	}
   720  
   721  	expected := []config.Periodic{
   722  		{
   723  			Cron: "0 * * * *",
   724  			JobBase: config.JobBase{
   725  				Name:        "some-forked-periodic-1-15",
   726  				Annotations: map[string]string{testgridDashboardsAnnotation: "sig-release-job-config-errors"},
   727  			},
   728  		},
   729  		{
   730  			Cron: "0 * * * *",
   731  			JobBase: config.JobBase{
   732  				Name:        "some-generic-periodic-beta",
   733  				Annotations: map[string]string{suffixAnnotation: "true", testgridDashboardsAnnotation: "sig-release-job-config-errors"},
   734  			},
   735  		},
   736  		{
   737  			Cron: "0 * * * *",
   738  			JobBase: config.JobBase{
   739  				Name:        "generic-periodic-with-deletions-beta",
   740  				Annotations: map[string]string{suffixAnnotation: "true", testgridDashboardsAnnotation: "sig-release-job-config-errors"},
   741  				Labels: map[string]string{
   742  					"preset-e2e-scalability-periodics": "true",
   743  				},
   744  			},
   745  		},
   746  		{
   747  			Interval: "6h",
   748  			JobBase: config.JobBase{
   749  				Name: "periodic-with-replacements-1-15",
   750  				Annotations: map[string]string{
   751  					periodicIntervalAnnotation:   "12h 24h 24h",
   752  					testgridDashboardsAnnotation: "sig-release-job-config-errors",
   753  				},
   754  				Spec: &v1.PodSpec{
   755  					Containers: []v1.Container{
   756  						{
   757  							Image:   "gcr.io/k8s-testinfra/kubekins-e2e:blahblahblah-1.15",
   758  							Command: []string{"--args1=test", "--version=1.15"},
   759  							Args:    []string{"--repo=k8s.io/kubernetes=release-1.15", "--version=1.15"},
   760  							Env:     []v1.EnvVar{{Name: "BRANCH", Value: "release-1.15"}, {Name: "GO_VERSION", Value: "1.20.2"}},
   761  						},
   762  					},
   763  				},
   764  			},
   765  			Tags: []string{"ver: 1.15"},
   766  		},
   767  		{
   768  			Interval: "2h",
   769  			JobBase: config.JobBase{
   770  				Name:        "decorated-periodic-1-15",
   771  				Annotations: map[string]string{testgridDashboardsAnnotation: "sig-release-job-config-errors"},
   772  				UtilityConfig: config.UtilityConfig{
   773  					Decorate:  &yes,
   774  					ExtraRefs: []prowapi.Refs{{Org: "kubernetes", Repo: "kubernetes", BaseRef: "release-1.15"}},
   775  				},
   776  			},
   777  		},
   778  	}
   779  
   780  	result, err := generatePeriodics(config.JobConfig{Periodics: periodics}, templateVars{Version: "1.15", GoVersion: "1.20.2"})
   781  	if err != nil {
   782  		t.Fatalf("Unexpected error: %v", err)
   783  	}
   784  
   785  	if !reflect.DeepEqual(result, expected) {
   786  		t.Errorf("Result does not match expected. Difference:\n%s\n", cmp.Diff(expected, result, cmpopts.IgnoreUnexported(config.Periodic{})))
   787  	}
   788  }
   789  
   790  func TestGeneratePostsubmits(t *testing.T) {
   791  	postsubmits := map[string][]config.Postsubmit{
   792  		"kubernetes/kubernetes": {
   793  			{
   794  				JobBase: config.JobBase{
   795  					Name:        "post-kubernetes-e2e",
   796  					Annotations: map[string]string{forkAnnotation: "true"},
   797  				},
   798  				Brancher: config.Brancher{
   799  					SkipBranches: []string{`release-\d\.\d`},
   800  				},
   801  			},
   802  			{
   803  				JobBase: config.JobBase{
   804  					Name: "post-kubernetes-generic",
   805  					Annotations: map[string]string{
   806  						forkAnnotation:               "true",
   807  						suffixAnnotation:             "true",
   808  						testgridDashboardsAnnotation: "sig-release-master-blocking, google-unit",
   809  					},
   810  				},
   811  				Brancher: config.Brancher{
   812  					SkipBranches: []string{`release-\d\.\d`},
   813  				},
   814  			},
   815  			{
   816  				JobBase: config.JobBase{
   817  					Name: "post-kubernetes-generic-will-end-up-in-all",
   818  					Annotations: map[string]string{
   819  						forkAnnotation:               "true",
   820  						suffixAnnotation:             "true",
   821  						testgridDashboardsAnnotation: "google-unit",
   822  					},
   823  				},
   824  				Brancher: config.Brancher{
   825  					SkipBranches: []string{`release-\d\.\d`},
   826  				},
   827  			},
   828  			{
   829  				JobBase: config.JobBase{
   830  					Name: "post-replace-some-things-master",
   831  					Annotations: map[string]string{
   832  						forkAnnotation:        "true",
   833  						replacementAnnotation: "foo -> {{.Version}}, GO_VERSION= -> GO_VERSION={{.GoVersion}}",
   834  						"some-annotation":     "yup",
   835  					},
   836  					Spec: &v1.PodSpec{
   837  						Containers: []v1.Container{
   838  							{
   839  								Image:   "gcr.io/k8s-staging-test-infra/kubekins-e2e:blahblahblah-master",
   840  								Command: []string{"--args1=test", "--something=foo"},
   841  								Args:    []string{"--repo=k8s.io/kubernetes", "--something=foo"},
   842  								Env:     []v1.EnvVar{{Name: "BRANCH", Value: "master"}, {Name: "GO_VERSION"}},
   843  							},
   844  						},
   845  					},
   846  				},
   847  				Brancher: config.Brancher{
   848  					SkipBranches: []string{`release-\d\.\d`},
   849  				},
   850  			},
   851  			{
   852  				JobBase: config.JobBase{
   853  					Name:        "post-not-forked",
   854  					Annotations: map[string]string{"foo": "bar"},
   855  				},
   856  			},
   857  		},
   858  	}
   859  
   860  	expected := map[string][]config.Postsubmit{
   861  		"kubernetes/kubernetes": {
   862  			{
   863  				JobBase: config.JobBase{
   864  					Name:        "post-kubernetes-e2e-1-15",
   865  					Annotations: map[string]string{testgridDashboardsAnnotation: "sig-release-job-config-errors"},
   866  				},
   867  				Brancher: config.Brancher{
   868  					Branches: []string{"release-1.15"},
   869  				},
   870  			},
   871  			{
   872  				JobBase: config.JobBase{
   873  					Name: "post-kubernetes-generic-beta",
   874  					Annotations: map[string]string{
   875  						suffixAnnotation:             "true",
   876  						testgridDashboardsAnnotation: "sig-release-1.15-blocking, google-unit",
   877  					},
   878  				},
   879  				Brancher: config.Brancher{
   880  					Branches: []string{"release-1.15"},
   881  				},
   882  			},
   883  			{
   884  				JobBase: config.JobBase{
   885  					Name: "post-kubernetes-generic-will-end-up-in-all-beta",
   886  					Annotations: map[string]string{
   887  						suffixAnnotation:             "true",
   888  						testgridDashboardsAnnotation: "google-unit, sig-release-job-config-errors",
   889  					},
   890  				},
   891  				Brancher: config.Brancher{
   892  					Branches: []string{"release-1.15"},
   893  				},
   894  			},
   895  			{
   896  				JobBase: config.JobBase{
   897  					Name: "post-replace-some-things-1-15",
   898  					Annotations: map[string]string{
   899  						"some-annotation":            "yup",
   900  						testgridDashboardsAnnotation: "sig-release-job-config-errors",
   901  					},
   902  					Spec: &v1.PodSpec{
   903  						Containers: []v1.Container{
   904  							{
   905  								Image:   "gcr.io/k8s-staging-test-infra/kubekins-e2e:blahblahblah-1.15",
   906  								Command: []string{"--args1=test", "--something=1.15"},
   907  								Args:    []string{"--repo=k8s.io/kubernetes", "--something=1.15"},
   908  								Env:     []v1.EnvVar{{Name: "BRANCH", Value: "release-1.15"}, {Name: "GO_VERSION", Value: "1.20.2"}},
   909  							},
   910  						},
   911  					},
   912  				},
   913  				Brancher: config.Brancher{
   914  					Branches: []string{"release-1.15"},
   915  				},
   916  			},
   917  		},
   918  	}
   919  
   920  	result, err := generatePostsubmits(config.JobConfig{PostsubmitsStatic: postsubmits}, templateVars{Version: "1.15", GoVersion: "1.20.2"})
   921  	if err != nil {
   922  		t.Fatalf("Unexpected error: %v", err)
   923  	}
   924  
   925  	if !reflect.DeepEqual(result, expected) {
   926  		t.Errorf("Result does not match expected. Difference:\n%s", diff.ObjectDiff(expected, result))
   927  	}
   928  }