k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/testgrid/pkg/configurator/prow/prow_test.go (about)

     1  /*
     2  Copyright 2021 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 prow
    18  
    19  import (
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/GoogleCloudPlatform/testgrid/config/yamlcfg"
    25  	"github.com/GoogleCloudPlatform/testgrid/pb/config"
    26  
    27  	prowapi "sigs.k8s.io/prow/pkg/apis/prowjobs/v1"
    28  	prowConfig "sigs.k8s.io/prow/pkg/config"
    29  	"sigs.k8s.io/prow/pkg/pjutil"
    30  )
    31  
    32  const ProwDefaultGCSPath = "pathPrefix/"
    33  const ProwJobName = "TestJob"
    34  const ProwJobSourcePath = "jobs/org/repo/testjob.yaml"
    35  const ProwJobURLPrefix = "https://go.k8s.io/prowjobs/"
    36  const ExampleRepository = "test/repo"
    37  const ProwJobDefaultDescription = "prowjob_name: " + ProwJobName
    38  
    39  func Test_applySingleProwjobAnnotations(t *testing.T) {
    40  	tests := []*struct {
    41  		name              string
    42  		initialConfig     config.Configuration
    43  		updateDescription bool
    44  		prowJobURLPrefix  string
    45  		prowJobType       prowapi.ProwJobType
    46  		annotations       map[string]string
    47  		expectedConfig    config.Configuration
    48  		expectError       bool
    49  	}{
    50  		{
    51  			name:           "Presubmit with no Annotations: no change",
    52  			prowJobType:    prowapi.PresubmitJob,
    53  			expectedConfig: config.Configuration{},
    54  		},
    55  		{
    56  			name:        "Non-presubmit with no Annotations: test group only",
    57  			prowJobType: prowapi.PostsubmitJob,
    58  			expectedConfig: config.Configuration{
    59  				TestGroups: []*config.TestGroup{
    60  					{
    61  						Name:      ProwJobName,
    62  						GcsPrefix: ProwDefaultGCSPath + "logs/" + ProwJobName,
    63  					},
    64  				},
    65  			},
    66  		},
    67  		{
    68  			name:        "Presubmit forcing test group creation: sets hardcoded default",
    69  			prowJobType: prowapi.PresubmitJob,
    70  			annotations: map[string]string{
    71  				"testgrid-create-test-group": "true",
    72  			},
    73  			expectedConfig: config.Configuration{
    74  				TestGroups: []*config.TestGroup{
    75  					{
    76  						Name:             ProwJobName,
    77  						GcsPrefix:        ProwDefaultGCSPath + "pr-logs/directory/" + ProwJobName,
    78  						NumColumnsRecent: 20,
    79  					},
    80  				},
    81  			},
    82  		},
    83  		{
    84  			name:        "Set columns below hardcoded minimum: annotation overwrites",
    85  			prowJobType: prowapi.PresubmitJob,
    86  			annotations: map[string]string{
    87  				"testgrid-create-test-group":  "true",
    88  				"testgrid-num-columns-recent": "10",
    89  			},
    90  			expectedConfig: config.Configuration{
    91  				TestGroups: []*config.TestGroup{
    92  					{
    93  						Name:             ProwJobName,
    94  						GcsPrefix:        ProwDefaultGCSPath + "pr-logs/directory/" + ProwJobName,
    95  						NumColumnsRecent: 10,
    96  					},
    97  				},
    98  			},
    99  		},
   100  		{
   101  			name:        "Non-presubmit excluding test group",
   102  			prowJobType: prowapi.PostsubmitJob,
   103  			annotations: map[string]string{
   104  				"testgrid-create-test-group": "false",
   105  			},
   106  			expectedConfig: config.Configuration{},
   107  		},
   108  		{
   109  			name: "Force-add job to existing test group: fails",
   110  			initialConfig: config.Configuration{
   111  				TestGroups: []*config.TestGroup{
   112  					{Name: ProwJobName},
   113  				},
   114  			},
   115  			prowJobType: prowapi.PostsubmitJob,
   116  			annotations: map[string]string{
   117  				"testgrid-create-test-group": "true",
   118  			},
   119  			expectError: true,
   120  		},
   121  		{
   122  			name: "Add job to existing dashboard",
   123  			initialConfig: config.Configuration{
   124  				Dashboards: []*config.Dashboard{
   125  					{Name: "Wash"},
   126  				},
   127  			},
   128  			prowJobType: prowapi.PostsubmitJob,
   129  			annotations: map[string]string{
   130  				"testgrid-dashboards": "Wash",
   131  			},
   132  			expectedConfig: config.Configuration{
   133  				TestGroups: []*config.TestGroup{
   134  					{
   135  						Name:      ProwJobName,
   136  						GcsPrefix: ProwDefaultGCSPath + "logs/" + ProwJobName,
   137  					},
   138  				},
   139  				Dashboards: []*config.Dashboard{
   140  					{
   141  						Name: "Wash",
   142  						DashboardTab: []*config.DashboardTab{
   143  							{
   144  								Name:          ProwJobName,
   145  								Description:   ProwJobDefaultDescription,
   146  								TestGroupName: ProwJobName,
   147  								CodeSearchUrlTemplate: &config.LinkTemplate{
   148  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   149  								},
   150  								OpenBugTemplate: &config.LinkTemplate{
   151  									Url: "https://github.com/test/repo/issues/",
   152  								},
   153  							},
   154  						},
   155  					},
   156  				},
   157  			},
   158  		},
   159  		{
   160  			name:        "Add job to new dashboard: fails",
   161  			prowJobType: prowapi.PostsubmitJob,
   162  			annotations: map[string]string{
   163  				"testgrid-dashboards": "Black",
   164  			},
   165  			expectError: true,
   166  		},
   167  		{
   168  			name: "Add email to multiple dashboards: Two tabs, one email",
   169  			initialConfig: config.Configuration{
   170  				Dashboards: []*config.Dashboard{
   171  					{Name: "Dart"},
   172  					{Name: "Peg"},
   173  				},
   174  			},
   175  			prowJobType: prowapi.PostsubmitJob,
   176  			annotations: map[string]string{
   177  				"testgrid-dashboards":  "Dart, Peg",
   178  				"testgrid-alert-email": "test@example.com",
   179  			},
   180  			expectedConfig: config.Configuration{
   181  				TestGroups: []*config.TestGroup{
   182  					{
   183  						Name:      ProwJobName,
   184  						GcsPrefix: ProwDefaultGCSPath + "logs/" + ProwJobName,
   185  					},
   186  				},
   187  				Dashboards: []*config.Dashboard{
   188  					{
   189  						Name: "Dart",
   190  						DashboardTab: []*config.DashboardTab{
   191  							{
   192  								Name:          ProwJobName,
   193  								Description:   ProwJobDefaultDescription,
   194  								TestGroupName: ProwJobName,
   195  								CodeSearchUrlTemplate: &config.LinkTemplate{
   196  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   197  								},
   198  								OpenBugTemplate: &config.LinkTemplate{
   199  									Url: "https://github.com/test/repo/issues/",
   200  								},
   201  								AlertOptions: &config.DashboardTabAlertOptions{
   202  									AlertMailToAddresses: "test@example.com",
   203  								},
   204  							},
   205  						},
   206  					},
   207  					{
   208  						Name: "Peg",
   209  						DashboardTab: []*config.DashboardTab{
   210  							{
   211  								Name:          ProwJobName,
   212  								Description:   ProwJobDefaultDescription,
   213  								TestGroupName: ProwJobName,
   214  								CodeSearchUrlTemplate: &config.LinkTemplate{
   215  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   216  								},
   217  								OpenBugTemplate: &config.LinkTemplate{
   218  									Url: "https://github.com/test/repo/issues/",
   219  								},
   220  							},
   221  						},
   222  					},
   223  				},
   224  			},
   225  		},
   226  		{
   227  			name: "Add job that already exists: keeps test group, makes duplicate tab",
   228  			initialConfig: config.Configuration{
   229  				TestGroups: []*config.TestGroup{
   230  					{
   231  						Name:      ProwJobName,
   232  						GcsPrefix: "CustomFoo",
   233  					},
   234  				},
   235  				Dashboards: []*config.Dashboard{
   236  					{
   237  						Name: "Surf",
   238  						DashboardTab: []*config.DashboardTab{
   239  							{
   240  								Name:          ProwJobName,
   241  								Description:   "RegularHumanDescription",
   242  								TestGroupName: ProwJobName,
   243  							},
   244  						},
   245  					},
   246  				},
   247  			},
   248  			prowJobType: prowapi.PostsubmitJob,
   249  			annotations: map[string]string{
   250  				"testgrid-dashboards": "Surf",
   251  			},
   252  			expectedConfig: config.Configuration{
   253  				TestGroups: []*config.TestGroup{
   254  					{
   255  						Name:      ProwJobName,
   256  						GcsPrefix: "CustomFoo",
   257  					},
   258  				},
   259  				Dashboards: []*config.Dashboard{
   260  					{
   261  						Name: "Surf",
   262  						DashboardTab: []*config.DashboardTab{
   263  							{
   264  								Name:          ProwJobName,
   265  								Description:   "RegularHumanDescription",
   266  								TestGroupName: ProwJobName,
   267  							},
   268  							{
   269  								Name:          ProwJobName,
   270  								Description:   ProwJobDefaultDescription,
   271  								TestGroupName: ProwJobName,
   272  								CodeSearchUrlTemplate: &config.LinkTemplate{
   273  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   274  								},
   275  								OpenBugTemplate: &config.LinkTemplate{
   276  									Url: "https://github.com/test/repo/issues/",
   277  								},
   278  							},
   279  						},
   280  					},
   281  				},
   282  			},
   283  		},
   284  		{
   285  			name: "Add job to existing dashboard with --prowjob-url-prefix configured",
   286  			initialConfig: config.Configuration{
   287  				Dashboards: []*config.Dashboard{
   288  					{Name: "Wash"},
   289  				},
   290  			},
   291  			prowJobURLPrefix: ProwJobURLPrefix,
   292  			prowJobType:      prowapi.PostsubmitJob,
   293  			annotations: map[string]string{
   294  				"testgrid-dashboards": "Wash",
   295  			},
   296  			expectedConfig: config.Configuration{
   297  				TestGroups: []*config.TestGroup{
   298  					{
   299  						Name:      ProwJobName,
   300  						GcsPrefix: ProwDefaultGCSPath + "logs/" + ProwJobName,
   301  					},
   302  				},
   303  				Dashboards: []*config.Dashboard{
   304  					{
   305  						Name: "Wash",
   306  						DashboardTab: []*config.DashboardTab{
   307  							{
   308  								Name:          ProwJobName,
   309  								Description:   ProwJobDefaultDescription + "\nprowjob_config_url: " + ProwJobURLPrefix + ProwJobSourcePath,
   310  								TestGroupName: ProwJobName,
   311  								CodeSearchUrlTemplate: &config.LinkTemplate{
   312  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   313  								},
   314  								OpenBugTemplate: &config.LinkTemplate{
   315  									Url: "https://github.com/test/repo/issues/",
   316  								},
   317  							},
   318  						},
   319  					},
   320  				},
   321  			},
   322  		},
   323  		{
   324  			name: "Full Annotations with --update-description enabled",
   325  			initialConfig: config.Configuration{
   326  				Dashboards: []*config.Dashboard{
   327  					{Name: "Ouija"},
   328  				},
   329  			},
   330  			updateDescription: true,
   331  			prowJobType:       prowapi.PostsubmitJob,
   332  			annotations: map[string]string{
   333  				"testgrid-dashboards":                "Ouija",
   334  				"testgrid-tab-name":                  "Planchette",
   335  				"testgrid-alert-email":               "ghost@example.com",
   336  				"description":                        "spooky scary",
   337  				"testgrid-num-columns-recent":        "13",
   338  				"testgrid-num-failures-to-alert":     "4",
   339  				"testgrid-alert-stale-results-hours": "24",
   340  				"testgrid-days-of-results":           "30",
   341  				"testgrid-in-cell-metric":            "haunted-house",
   342  				"testgrid-disable-prowjob-analysis":  "true",
   343  				"testgrid-base-options":              "exclude-filter-by-regex=^kubetest.Test$",
   344  				"testgrid-broken-column-threshold":   "0.5",
   345  			},
   346  			expectedConfig: config.Configuration{
   347  				TestGroups: []*config.TestGroup{
   348  					{
   349  						Name:                   ProwJobName,
   350  						GcsPrefix:              ProwDefaultGCSPath + "logs/" + ProwJobName,
   351  						NumColumnsRecent:       13,
   352  						DaysOfResults:          30,
   353  						ShortTextMetric:        "haunted-house",
   354  						DisableProwjobAnalysis: true,
   355  						NumFailuresToAlert:     4,
   356  					},
   357  				},
   358  				Dashboards: []*config.Dashboard{
   359  					{
   360  						Name: "Ouija",
   361  						DashboardTab: []*config.DashboardTab{
   362  							{
   363  								Name:          "Planchette",
   364  								Description:   ProwJobDefaultDescription + "\nprowjob_description: spooky scary",
   365  								TestGroupName: ProwJobName,
   366  								AlertOptions: &config.DashboardTabAlertOptions{
   367  									AlertMailToAddresses:   "ghost@example.com",
   368  									NumFailuresToAlert:     4,
   369  									AlertStaleResultsHours: 24,
   370  								},
   371  								CodeSearchUrlTemplate: &config.LinkTemplate{
   372  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   373  								},
   374  								OpenBugTemplate: &config.LinkTemplate{
   375  									Url: "https://github.com/test/repo/issues/",
   376  								},
   377  								BaseOptions:           "exclude-filter-by-regex=^kubetest.Test$",
   378  								BrokenColumnThreshold: 0.5,
   379  							},
   380  						},
   381  					},
   382  				},
   383  			},
   384  		},
   385  	}
   386  
   387  	for _, test := range tests {
   388  		t.Run(test.name, func(t *testing.T) {
   389  			pac := ProwAwareConfigurator{
   390  				ProwConfig:            fakeProwConfig(),
   391  				DefaultTestgridConfig: nil,
   392  				ProwJobURLPrefix:      test.prowJobURLPrefix,
   393  				UpdateDescription:     test.updateDescription,
   394  			}
   395  			jobBase := prowConfig.JobBase{
   396  				Name:        ProwJobName,
   397  				Annotations: test.annotations,
   398  				SourcePath:  ProwJobSourcePath,
   399  			}
   400  
   401  			pj := genProwJob(jobBase, test.prowJobType, ExampleRepository)
   402  
   403  			err := pac.ApplySingleProwjobAnnotations(&test.initialConfig, jobBase, pj)
   404  
   405  			if test.expectError {
   406  				if err == nil {
   407  					t.Error("Expected an error, but got none")
   408  				}
   409  			} else {
   410  				if err != nil {
   411  					t.Errorf("Unexpected error: %v", err)
   412  				}
   413  
   414  				if !reflect.DeepEqual(&test.initialConfig, &test.expectedConfig) {
   415  					t.Errorf("Configurations did not match; got %s, expected %s", test.initialConfig.String(), test.expectedConfig.String())
   416  				}
   417  			}
   418  		})
   419  	}
   420  }
   421  
   422  func Test_applySingleProwjobAnnotation_WithDefaults(t *testing.T) {
   423  
   424  	defaultConfig := &yamlcfg.DefaultConfiguration{
   425  		DefaultTestGroup: &config.TestGroup{
   426  			GcsPrefix:        "originalConfigPrefix", //Default is Overwritten
   427  			DaysOfResults:    5,                      //Default is Kept
   428  			NumColumnsRecent: 10,                     //Sometimes Overwritten; see test
   429  		},
   430  		DefaultDashboardTab: &config.DashboardTab{
   431  			Name:        "DefaultTab",          //Overwritten
   432  			Description: "Default Description", //Overwritten
   433  			ResultsText: "Default Text",        //Kept
   434  			AlertOptions: &config.DashboardTabAlertOptions{
   435  				AlertMailToAddresses: "default_admin@example.com", //Kept; see test
   436  			},
   437  			CodeSearchUrlTemplate: &config.LinkTemplate{ //Overwritten
   438  				Url: "https://example.com/code_search",
   439  			},
   440  			OpenBugTemplate: &config.LinkTemplate{ //Overwritten
   441  				Url: "https://example.com/open_bug",
   442  			},
   443  		},
   444  	}
   445  
   446  	tests := []struct {
   447  		name           string
   448  		initialConfig  *config.Configuration
   449  		prowJobType    prowapi.ProwJobType
   450  		annotations    map[string]string
   451  		expectedConfig *config.Configuration
   452  	}{
   453  		{
   454  			name:           "Presubmit with no Annotations: no change",
   455  			prowJobType:    prowapi.PresubmitJob,
   456  			expectedConfig: &config.Configuration{},
   457  		},
   458  		{
   459  			name:        "Non-presubmit with no Annotations: test group with assumed defaults",
   460  			prowJobType: prowapi.PostsubmitJob,
   461  			expectedConfig: &config.Configuration{
   462  				TestGroups: []*config.TestGroup{
   463  					{
   464  						Name:                ProwJobName,
   465  						GcsPrefix:           ProwDefaultGCSPath + "logs/" + ProwJobName,
   466  						DaysOfResults:       5,
   467  						NumColumnsRecent:    10,
   468  						UseKubernetesClient: true,
   469  						IsExternal:          true,
   470  					},
   471  				},
   472  			},
   473  		},
   474  		{
   475  			name:        "Presubmit forcing test group creation: hardcoded default over config default",
   476  			prowJobType: prowapi.PresubmitJob,
   477  			annotations: map[string]string{
   478  				"testgrid-create-test-group": "true",
   479  			},
   480  			expectedConfig: &config.Configuration{
   481  				TestGroups: []*config.TestGroup{
   482  					{
   483  						Name:                ProwJobName,
   484  						GcsPrefix:           ProwDefaultGCSPath + "pr-logs/directory/" + ProwJobName,
   485  						DaysOfResults:       5,
   486  						NumColumnsRecent:    20,
   487  						UseKubernetesClient: true,
   488  						IsExternal:          true,
   489  					},
   490  				},
   491  			},
   492  		},
   493  		{
   494  			name: "Add job to existing dashboard: merge with defaults",
   495  			initialConfig: &config.Configuration{
   496  				Dashboards: []*config.Dashboard{
   497  					{Name: "Wash"},
   498  				},
   499  			},
   500  			prowJobType: prowapi.PostsubmitJob,
   501  			annotations: map[string]string{
   502  				"testgrid-dashboards": "Wash",
   503  			},
   504  			expectedConfig: &config.Configuration{
   505  				TestGroups: []*config.TestGroup{
   506  					{
   507  						Name:                ProwJobName,
   508  						GcsPrefix:           ProwDefaultGCSPath + "logs/" + ProwJobName,
   509  						DaysOfResults:       5,
   510  						NumColumnsRecent:    10,
   511  						UseKubernetesClient: true,
   512  						IsExternal:          true,
   513  					},
   514  				},
   515  				Dashboards: []*config.Dashboard{
   516  					{
   517  						Name: "Wash",
   518  						DashboardTab: []*config.DashboardTab{
   519  							{
   520  								Name:          ProwJobName,
   521  								Description:   ProwJobDefaultDescription,
   522  								TestGroupName: ProwJobName,
   523  								ResultsText:   "Default Text",
   524  								CodeSearchUrlTemplate: &config.LinkTemplate{
   525  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   526  								},
   527  								OpenBugTemplate: &config.LinkTemplate{
   528  									Url: "https://github.com/test/repo/issues/",
   529  								},
   530  								AlertOptions: &config.DashboardTabAlertOptions{
   531  									AlertMailToAddresses: "default_admin@example.com",
   532  								},
   533  							},
   534  						},
   535  					},
   536  				},
   537  			},
   538  		},
   539  		{
   540  			name: "Add email to multiple dashboards: Two tabs, Different Emails",
   541  			initialConfig: &config.Configuration{
   542  				Dashboards: []*config.Dashboard{
   543  					{Name: "Dart"},
   544  					{Name: "Peg"},
   545  				},
   546  			},
   547  			prowJobType: prowapi.PostsubmitJob,
   548  			annotations: map[string]string{
   549  				"testgrid-dashboards":  "Dart, Peg",
   550  				"testgrid-alert-email": "test@example.com",
   551  			},
   552  			expectedConfig: &config.Configuration{
   553  				TestGroups: []*config.TestGroup{
   554  					{
   555  						Name:                ProwJobName,
   556  						GcsPrefix:           ProwDefaultGCSPath + "logs/" + ProwJobName,
   557  						DaysOfResults:       5,
   558  						NumColumnsRecent:    10,
   559  						UseKubernetesClient: true,
   560  						IsExternal:          true,
   561  					},
   562  				},
   563  				Dashboards: []*config.Dashboard{
   564  					{
   565  						Name: "Dart",
   566  						DashboardTab: []*config.DashboardTab{
   567  							{
   568  								Name:          ProwJobName,
   569  								Description:   ProwJobDefaultDescription,
   570  								TestGroupName: ProwJobName,
   571  								ResultsText:   "Default Text",
   572  								CodeSearchUrlTemplate: &config.LinkTemplate{
   573  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   574  								},
   575  								OpenBugTemplate: &config.LinkTemplate{
   576  									Url: "https://github.com/test/repo/issues/",
   577  								},
   578  								AlertOptions: &config.DashboardTabAlertOptions{
   579  									AlertMailToAddresses: "test@example.com",
   580  								},
   581  							},
   582  						},
   583  					},
   584  					{
   585  						Name: "Peg",
   586  						DashboardTab: []*config.DashboardTab{
   587  							{
   588  								Name:          ProwJobName,
   589  								Description:   ProwJobDefaultDescription,
   590  								TestGroupName: ProwJobName,
   591  								ResultsText:   "Default Text",
   592  								CodeSearchUrlTemplate: &config.LinkTemplate{
   593  									Url: "https://github.com/test/repo/compare/<start-custom-0>...<end-custom-0>",
   594  								},
   595  								OpenBugTemplate: &config.LinkTemplate{
   596  									Url: "https://github.com/test/repo/issues/",
   597  								},
   598  								AlertOptions: &config.DashboardTabAlertOptions{
   599  									AlertMailToAddresses: "default_admin@example.com",
   600  								},
   601  							},
   602  						},
   603  					},
   604  				},
   605  			},
   606  		},
   607  	}
   608  
   609  	for _, test := range tests {
   610  		t.Run(test.name, func(t *testing.T) {
   611  
   612  			if test.initialConfig == nil {
   613  				test.initialConfig = &config.Configuration{}
   614  			}
   615  
   616  			pac := ProwAwareConfigurator{
   617  				ProwConfig:            fakeProwConfig(),
   618  				DefaultTestgridConfig: defaultConfig,
   619  			}
   620  
   621  			jobBase := prowConfig.JobBase{
   622  				Name:        ProwJobName,
   623  				Annotations: test.annotations,
   624  			}
   625  
   626  			pj := genProwJob(jobBase, test.prowJobType, ExampleRepository)
   627  
   628  			err := pac.ApplySingleProwjobAnnotations(test.initialConfig, jobBase, pj)
   629  
   630  			if test.expectedConfig == nil {
   631  				if err == nil {
   632  					t.Error("Expected an error, but got none")
   633  				}
   634  			} else {
   635  				if err != nil {
   636  					t.Errorf("Unexpected error: %v", err)
   637  				}
   638  
   639  				if !reflect.DeepEqual(test.initialConfig, test.expectedConfig) {
   640  					t.Errorf("Configurations did not match; got %s, expected %s", test.initialConfig.String(), test.expectedConfig.String())
   641  				}
   642  			}
   643  		})
   644  	}
   645  
   646  }
   647  
   648  func Test_applySingleProwjobAnnotations_OpenTestTemplate(t *testing.T) {
   649  	tests := []*struct {
   650  		name                     string
   651  		jobURLPrefixConfig       map[string]string
   652  		defaultConfig            *yamlcfg.DefaultConfiguration
   653  		expectedOpenTestTemplate *config.LinkTemplate
   654  	}{
   655  		{
   656  			name: "job url prefix without specific suffix",
   657  			jobURLPrefixConfig: map[string]string{
   658  				"*": "https://config.go.k8s.io/",
   659  			},
   660  			expectedOpenTestTemplate: &config.LinkTemplate{
   661  				Url: "https://config.go.k8s.io/gs/<gcs_prefix>/<changelist>",
   662  			},
   663  		},
   664  		{
   665  			name: "job url prefix ends in /view, kept",
   666  			jobURLPrefixConfig: map[string]string{
   667  				"*": "https://config.go.k8s.io/view",
   668  			},
   669  			expectedOpenTestTemplate: &config.LinkTemplate{
   670  				Url: "https://config.go.k8s.io/view/gs/<gcs_prefix>/<changelist>",
   671  			},
   672  		},
   673  		{
   674  			name: "job url prefix for org is preferred over *",
   675  			jobURLPrefixConfig: map[string]string{
   676  				"*":    "https://some.other.url",
   677  				"test": "https://config.go.k8s.io/",
   678  			},
   679  			expectedOpenTestTemplate: &config.LinkTemplate{
   680  				Url: "https://config.go.k8s.io/gs/<gcs_prefix>/<changelist>",
   681  			},
   682  		},
   683  		{
   684  			name: "job url prefix for org/repo is preferred over org and *",
   685  			jobURLPrefixConfig: map[string]string{
   686  				"*":         "https://some.other.url",
   687  				"test":      "https://even.another.url",
   688  				"test/repo": "https://config.go.k8s.io/",
   689  			},
   690  			expectedOpenTestTemplate: &config.LinkTemplate{
   691  				Url: "https://config.go.k8s.io/gs/<gcs_prefix>/<changelist>",
   692  			},
   693  		},
   694  		{
   695  			name: "default config is overwritten",
   696  			jobURLPrefixConfig: map[string]string{
   697  				"*": "https://config.go.k8s.io/",
   698  			},
   699  			defaultConfig: &yamlcfg.DefaultConfiguration{
   700  				DefaultTestGroup: &config.TestGroup{},
   701  				DefaultDashboardTab: &config.DashboardTab{
   702  					OpenTestTemplate: &config.LinkTemplate{ //Overwritten
   703  						Url: "https://example.com/open_test",
   704  					},
   705  				},
   706  			},
   707  			expectedOpenTestTemplate: &config.LinkTemplate{
   708  				Url: "https://config.go.k8s.io/gs/<gcs_prefix>/<changelist>",
   709  			},
   710  		},
   711  	}
   712  
   713  	for _, test := range tests {
   714  		t.Run(test.name, func(t *testing.T) {
   715  			initialConfig := &config.Configuration{
   716  				Dashboards: []*config.Dashboard{
   717  					{Name: "Pizza"},
   718  				},
   719  			}
   720  			annotations := map[string]string{
   721  				"testgrid-dashboards": "Pizza",
   722  			}
   723  
   724  			prowCfg := fakeProwConfig()
   725  			prowCfg.Plank.JobURLPrefixConfig = test.jobURLPrefixConfig
   726  			pac := ProwAwareConfigurator{
   727  				ProwConfig: prowCfg,
   728  			}
   729  			if test.defaultConfig != nil {
   730  				pac.DefaultTestgridConfig = test.defaultConfig
   731  			}
   732  
   733  			jobBase := prowConfig.JobBase{
   734  				Name:        ProwJobName,
   735  				Annotations: annotations,
   736  				SourcePath:  ProwJobSourcePath,
   737  			}
   738  
   739  			pj := genProwJob(jobBase, prowapi.PresubmitJob, ExampleRepository)
   740  
   741  			err := pac.ApplySingleProwjobAnnotations(initialConfig, jobBase, pj)
   742  
   743  			if err != nil {
   744  				t.Errorf("Unexpected error: %v", err)
   745  			}
   746  
   747  			actual := initialConfig.Dashboards[0].DashboardTab[0].OpenTestTemplate
   748  			if !reflect.DeepEqual(actual, test.expectedOpenTestTemplate) {
   749  				t.Errorf("Configurations did not match; got %s, expected %s", actual.String(), test.expectedOpenTestTemplate.String())
   750  			}
   751  		})
   752  	}
   753  }
   754  
   755  func TestSortPresubmitRepoOrder(t *testing.T) {
   756  	tests := []struct {
   757  		name          string
   758  		presubmits    map[string][]prowConfig.Presubmit
   759  		expectedRepos []string
   760  	}{
   761  		{
   762  			name:          "empty list of presubmits",
   763  			presubmits:    map[string][]prowConfig.Presubmit{},
   764  			expectedRepos: []string{},
   765  		},
   766  		{
   767  			name: "unordered list of presubmits",
   768  			presubmits: map[string][]prowConfig.Presubmit{
   769  				"istio/proxy": {
   770  					prowConfig.Presubmit{
   771  						JobBase: prowConfig.JobBase{
   772  							Name: "lint_release-1.5",
   773  						},
   774  					},
   775  					prowConfig.Presubmit{
   776  						JobBase: prowConfig.JobBase{
   777  							Name: "gen_check_master",
   778  						},
   779  					},
   780  					prowConfig.Presubmit{
   781  						JobBase: prowConfig.JobBase{
   782  							Name: "lint_master",
   783  						},
   784  					},
   785  				},
   786  				"kubernetes/test-infra": {
   787  					prowConfig.Presubmit{
   788  						JobBase: prowConfig.JobBase{
   789  							Name: "pull-test-bazel",
   790  						},
   791  					},
   792  				},
   793  				"helm/helm": {
   794  					prowConfig.Presubmit{
   795  						JobBase: prowConfig.JobBase{
   796  							Name: "pull-test-go",
   797  						},
   798  					},
   799  				},
   800  			},
   801  			expectedRepos: []string{"helm/helm", "istio/proxy", "kubernetes/test-infra"},
   802  		},
   803  	}
   804  
   805  	for _, test := range tests {
   806  		t.Run(test.name, func(t *testing.T) {
   807  			actualRepos := sortPresubmits(test.presubmits)
   808  
   809  			if !reflect.DeepEqual(test.expectedRepos, actualRepos) {
   810  				t.Fatalf("Presubmit repos do not match; actual: %v\n expected %v\n", test.expectedRepos, actualRepos)
   811  			}
   812  		})
   813  	}
   814  }
   815  
   816  func TestSortPostsubmitRepoOrder(t *testing.T) {
   817  	tests := []struct {
   818  		name          string
   819  		postsubmits   map[string][]prowConfig.Postsubmit
   820  		expectedRepos []string
   821  	}{
   822  		{
   823  			name:          "empty list of postsubmits",
   824  			postsubmits:   map[string][]prowConfig.Postsubmit{},
   825  			expectedRepos: []string{},
   826  		},
   827  		{
   828  			name: "unordered list of postsubmits",
   829  			postsubmits: map[string][]prowConfig.Postsubmit{
   830  				"GoogleCloudPlatform/oss-test-infra": {
   831  					prowConfig.Postsubmit{
   832  						JobBase: prowConfig.JobBase{
   833  							Name: "pull-test-infra-go-test",
   834  						},
   835  					},
   836  				},
   837  				"kubernetes/kubernetes": {
   838  					prowConfig.Postsubmit{
   839  						JobBase: prowConfig.JobBase{
   840  							Name: "ci-kubernetes-e2e",
   841  						},
   842  					},
   843  					prowConfig.Postsubmit{
   844  						JobBase: prowConfig.JobBase{
   845  							Name: "ci-kubernetes-unit",
   846  						},
   847  					},
   848  				},
   849  				"containerd/cri": {
   850  					prowConfig.Postsubmit{
   851  						JobBase: prowConfig.JobBase{
   852  							Name: "pull-cri-containerd-build",
   853  						},
   854  					},
   855  				},
   856  			},
   857  			expectedRepos: []string{"GoogleCloudPlatform/oss-test-infra", "containerd/cri", "kubernetes/kubernetes"},
   858  		},
   859  	}
   860  
   861  	for _, test := range tests {
   862  		t.Run(test.name, func(t *testing.T) {
   863  			actualRepos := sortPostsubmits(test.postsubmits)
   864  
   865  			if !reflect.DeepEqual(test.expectedRepos, actualRepos) {
   866  				t.Fatalf("Postsubmit repos do not match; actual: %v\n expected %v\n", test.expectedRepos, actualRepos)
   867  			}
   868  		})
   869  	}
   870  }
   871  
   872  func TestSortPeriodicJobOrder(t *testing.T) {
   873  	tests := []struct {
   874  		name              string
   875  		periodics         []prowConfig.Periodic
   876  		expectedPeriodics []prowConfig.Periodic
   877  	}{
   878  		{
   879  			name:              "empty list of periodics",
   880  			periodics:         []prowConfig.Periodic{},
   881  			expectedPeriodics: []prowConfig.Periodic{},
   882  		},
   883  		{
   884  			name: "unordered list of periodics",
   885  			periodics: []prowConfig.Periodic{
   886  				{
   887  					JobBase: prowConfig.JobBase{
   888  						Name: "ESPv2-continuous-build",
   889  					},
   890  				},
   891  				{
   892  					JobBase: prowConfig.JobBase{
   893  						Name: "everlast-bump",
   894  					},
   895  				},
   896  				{
   897  					JobBase: prowConfig.JobBase{
   898  						Name: "ci-oss-test-infra-autobump-prow",
   899  					},
   900  				},
   901  			},
   902  			expectedPeriodics: []prowConfig.Periodic{
   903  				{
   904  					JobBase: prowConfig.JobBase{
   905  						Name: "ESPv2-continuous-build",
   906  					},
   907  				},
   908  				{
   909  					JobBase: prowConfig.JobBase{
   910  						Name: "ci-oss-test-infra-autobump-prow",
   911  					},
   912  				},
   913  				{
   914  					JobBase: prowConfig.JobBase{
   915  						Name: "everlast-bump",
   916  					},
   917  				},
   918  			},
   919  		},
   920  	}
   921  
   922  	for _, test := range tests {
   923  		t.Run(test.name, func(t *testing.T) {
   924  			sortPeriodics(test.periodics)
   925  
   926  			if !reflect.DeepEqual(test.expectedPeriodics, test.periodics) {
   927  				t.Fatalf("Periodic jobs do not match; actual: %v\n expected %v\n", test.expectedPeriodics, test.periodics)
   928  			}
   929  		})
   930  	}
   931  }
   932  
   933  func TestSortPresubmitJobOrder(t *testing.T) {
   934  	tests := []struct {
   935  		name               string
   936  		presubmits         map[string][]prowConfig.Presubmit
   937  		expectedPresubmits map[string][]prowConfig.Presubmit
   938  	}{
   939  		{
   940  			name:               "empty list of presubmits",
   941  			presubmits:         map[string][]prowConfig.Presubmit{},
   942  			expectedPresubmits: map[string][]prowConfig.Presubmit{},
   943  		},
   944  		{
   945  			name: "unordered list of presubmits",
   946  			presubmits: map[string][]prowConfig.Presubmit{
   947  				"istio/proxy": {
   948  					prowConfig.Presubmit{
   949  						JobBase: prowConfig.JobBase{
   950  							Name: "lint_release-1.5",
   951  						},
   952  					},
   953  					prowConfig.Presubmit{
   954  						JobBase: prowConfig.JobBase{
   955  							Name: "gen_check_master",
   956  						},
   957  					},
   958  					prowConfig.Presubmit{
   959  						JobBase: prowConfig.JobBase{
   960  							Name: "lint_master",
   961  						},
   962  					},
   963  				},
   964  				"kubernetes/test-infra": {
   965  					prowConfig.Presubmit{
   966  						JobBase: prowConfig.JobBase{
   967  							Name: "pull-test-go",
   968  						},
   969  					},
   970  					prowConfig.Presubmit{
   971  						JobBase: prowConfig.JobBase{
   972  							Name: "pull-test-bazel",
   973  						},
   974  					},
   975  				},
   976  			},
   977  			expectedPresubmits: map[string][]prowConfig.Presubmit{
   978  				"istio/proxy": {
   979  					prowConfig.Presubmit{
   980  						JobBase: prowConfig.JobBase{
   981  							Name: "gen_check_master",
   982  						},
   983  					},
   984  					prowConfig.Presubmit{
   985  						JobBase: prowConfig.JobBase{
   986  							Name: "lint_master",
   987  						},
   988  					},
   989  					prowConfig.Presubmit{
   990  						JobBase: prowConfig.JobBase{
   991  							Name: "lint_release-1.5",
   992  						},
   993  					},
   994  				},
   995  				"kubernetes/test-infra": {
   996  					prowConfig.Presubmit{
   997  						JobBase: prowConfig.JobBase{
   998  							Name: "pull-test-bazel",
   999  						},
  1000  					},
  1001  					prowConfig.Presubmit{
  1002  						JobBase: prowConfig.JobBase{
  1003  							Name: "pull-test-go",
  1004  						},
  1005  					},
  1006  				},
  1007  			},
  1008  		},
  1009  	}
  1010  
  1011  	for _, test := range tests {
  1012  		t.Run(test.name, func(t *testing.T) {
  1013  			sortPresubmits(test.presubmits)
  1014  
  1015  			for orgrepo := range test.expectedPresubmits {
  1016  				if !reflect.DeepEqual(test.expectedPresubmits[orgrepo], test.presubmits[orgrepo]) {
  1017  					t.Fatalf("Presubmit jobs do not match for repo: %s; actual: %v\n expected %v\n", orgrepo, test.expectedPresubmits[orgrepo], test.presubmits[orgrepo])
  1018  				}
  1019  			}
  1020  		})
  1021  	}
  1022  }
  1023  
  1024  func TestSortPostsubmitJobOrder(t *testing.T) {
  1025  	tests := []struct {
  1026  		name                string
  1027  		postsubmits         map[string][]prowConfig.Postsubmit
  1028  		expectedPostsubmits map[string][]prowConfig.Postsubmit
  1029  	}{
  1030  		{
  1031  			name:                "empty list of postsubmits",
  1032  			postsubmits:         map[string][]prowConfig.Postsubmit{},
  1033  			expectedPostsubmits: map[string][]prowConfig.Postsubmit{},
  1034  		},
  1035  		{
  1036  			name: "unordered list of postsubmits",
  1037  			postsubmits: map[string][]prowConfig.Postsubmit{
  1038  				"GoogleCloudPlatform/oss-test-infra": {
  1039  					prowConfig.Postsubmit{
  1040  						JobBase: prowConfig.JobBase{
  1041  							Name: "pull-test-infra-go-test",
  1042  						},
  1043  					},
  1044  					prowConfig.Postsubmit{
  1045  						JobBase: prowConfig.JobBase{
  1046  							Name: "pull-cri-containerd-build",
  1047  						},
  1048  					},
  1049  				},
  1050  				"kubernetes/kubernetes": {
  1051  					prowConfig.Postsubmit{
  1052  						JobBase: prowConfig.JobBase{
  1053  							Name: "ci-kubernetes-e2e",
  1054  						},
  1055  					},
  1056  					prowConfig.Postsubmit{
  1057  						JobBase: prowConfig.JobBase{
  1058  							Name: "ci-kubernetes-unit",
  1059  						},
  1060  					},
  1061  				},
  1062  			},
  1063  			expectedPostsubmits: map[string][]prowConfig.Postsubmit{
  1064  				"GoogleCloudPlatform/oss-test-infra": {
  1065  					prowConfig.Postsubmit{
  1066  						JobBase: prowConfig.JobBase{
  1067  							Name: "pull-cri-containerd-build",
  1068  						},
  1069  					},
  1070  					prowConfig.Postsubmit{
  1071  						JobBase: prowConfig.JobBase{
  1072  							Name: "pull-test-infra-go-test",
  1073  						},
  1074  					},
  1075  				},
  1076  				"kubernetes/kubernetes": {
  1077  					prowConfig.Postsubmit{
  1078  						JobBase: prowConfig.JobBase{
  1079  							Name: "ci-kubernetes-e2e",
  1080  						},
  1081  					},
  1082  					prowConfig.Postsubmit{
  1083  						JobBase: prowConfig.JobBase{
  1084  							Name: "ci-kubernetes-unit",
  1085  						},
  1086  					},
  1087  				},
  1088  			},
  1089  		},
  1090  	}
  1091  
  1092  	for _, test := range tests {
  1093  		t.Run(test.name, func(t *testing.T) {
  1094  			sortPostsubmits(test.postsubmits)
  1095  
  1096  			for orgrepo := range test.expectedPostsubmits {
  1097  				if !reflect.DeepEqual(test.expectedPostsubmits[orgrepo], test.postsubmits[orgrepo]) {
  1098  					t.Fatalf("Postsubmit jobs do not match for repo: %s; actual: %v\n expected %v\n", orgrepo, test.expectedPostsubmits[orgrepo], test.postsubmits[orgrepo])
  1099  				}
  1100  			}
  1101  		})
  1102  	}
  1103  }
  1104  
  1105  func fakeProwConfig() *prowConfig.Config {
  1106  	return &prowConfig.Config{
  1107  		ProwConfig: prowConfig.ProwConfig{
  1108  			Plank: prowConfig.Plank{
  1109  				DefaultDecorationConfigs: []*prowConfig.DefaultDecorationConfigEntry{
  1110  					{
  1111  						Config: &prowapi.DecorationConfig{
  1112  							GCSConfiguration: &prowapi.GCSConfiguration{
  1113  								PathPrefix: ProwDefaultGCSPath,
  1114  							},
  1115  						},
  1116  					},
  1117  				},
  1118  			},
  1119  		},
  1120  	}
  1121  }
  1122  
  1123  func genProwJob(jobBase prowConfig.JobBase, jobType prowapi.ProwJobType, orgrepo string) prowapi.ProwJob {
  1124  	if jobType == prowapi.PeriodicJob {
  1125  		pjSpec := pjutil.PeriodicSpec(prowConfig.Periodic{JobBase: jobBase})
  1126  		return pjutil.NewProwJob(pjSpec, nil, nil)
  1127  	}
  1128  
  1129  	items := strings.Split(orgrepo, "/")
  1130  	if jobType == prowapi.PostsubmitJob {
  1131  		pjSpec := pjutil.PostsubmitSpec(
  1132  			prowConfig.Postsubmit{JobBase: jobBase},
  1133  			prowapi.Refs{
  1134  				Org:  items[0],
  1135  				Repo: items[1],
  1136  			},
  1137  		)
  1138  		return pjutil.NewProwJob(pjSpec, nil, nil)
  1139  	}
  1140  
  1141  	pjSpec := pjutil.PresubmitSpec(
  1142  		prowConfig.Presubmit{JobBase: jobBase},
  1143  		prowapi.Refs{
  1144  			Org:  items[0],
  1145  			Repo: items[1],
  1146  		},
  1147  	)
  1148  	return pjutil.NewProwJob(pjSpec, nil, nil)
  1149  }