github.com/jenkins-x/test-infra@v0.0.7/prow/config/jobs_test.go (about)

     1  /*
     2  Copyright 2017 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 config
    18  
    19  import (
    20  	"flag"
    21  	"fmt"
    22  	"os"
    23  	"regexp"
    24  	"testing"
    25  
    26  	"k8s.io/test-infra/prow/kube"
    27  )
    28  
    29  var c *Config
    30  var configPath = flag.String("config", "../config.yaml", "Path to prow config")
    31  var jobConfigPath = flag.String("job-config", "../../config/jobs", "Path to prow job config")
    32  var podRe = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`)
    33  
    34  // Consistent but meaningless order.
    35  func flattenJobs(jobs []Presubmit) []Presubmit {
    36  	ret := jobs
    37  	for _, job := range jobs {
    38  		if len(job.RunAfterSuccess) > 0 {
    39  			ret = append(ret, flattenJobs(job.RunAfterSuccess)...)
    40  		}
    41  	}
    42  	return ret
    43  }
    44  
    45  // Returns if two brancher has overlapping branches
    46  func checkOverlapBrancher(b1, b2 Brancher) bool {
    47  	if b1.RunsAgainstAllBranch() || b2.RunsAgainstAllBranch() {
    48  		return true
    49  	}
    50  
    51  	for _, run1 := range b1.Branches {
    52  		if b2.RunsAgainstBranch(run1) {
    53  			return true
    54  		}
    55  	}
    56  
    57  	for _, run2 := range b2.Branches {
    58  		if b1.RunsAgainstBranch(run2) {
    59  			return true
    60  		}
    61  	}
    62  
    63  	return false
    64  }
    65  
    66  func TestMain(m *testing.M) {
    67  	flag.Parse()
    68  	if *configPath == "" {
    69  		fmt.Println("--config must set")
    70  		os.Exit(1)
    71  	}
    72  
    73  	conf, err := Load(*configPath, *jobConfigPath)
    74  	if err != nil {
    75  		fmt.Printf("Could not load config: %v", err)
    76  		os.Exit(1)
    77  	}
    78  	c = conf
    79  
    80  	os.Exit(m.Run())
    81  }
    82  
    83  func TestPresubmits(t *testing.T) {
    84  	if len(c.Presubmits) == 0 {
    85  		t.Fatalf("No jobs found in presubmit.yaml.")
    86  	}
    87  
    88  	for _, rootJobs := range c.Presubmits {
    89  		jobs := flattenJobs(rootJobs)
    90  		for i, job := range jobs {
    91  			if job.Name == "" {
    92  				t.Errorf("Job %v needs a name.", job)
    93  				continue
    94  			}
    95  			if !job.SkipReport && job.Context == "" {
    96  				t.Errorf("Job %s needs a context.", job.Name)
    97  			}
    98  			if job.RerunCommand == "" || job.Trigger == "" {
    99  				t.Errorf("Job %s needs a trigger and a rerun command.", job.Name)
   100  				continue
   101  			}
   102  
   103  			if len(job.Brancher.Branches) > 0 && len(job.Brancher.SkipBranches) > 0 {
   104  				t.Errorf("Job %s : Cannot have both branches and skip_branches set", job.Name)
   105  			}
   106  			// Next check that the rerun command doesn't run any other jobs.
   107  			for j, job2 := range jobs[i+1:] {
   108  				if job.Name == job2.Name {
   109  					// Make sure max_concurrency are the same
   110  					if job.MaxConcurrency != job2.MaxConcurrency {
   111  						t.Errorf("Jobs %s share same name but has different max_concurrency", job.Name)
   112  					}
   113  					// Make sure branches are not overlapping
   114  					if checkOverlapBrancher(job.Brancher, job2.Brancher) {
   115  						t.Errorf("Two jobs have the same name: %s, and have conflicting branches", job.Name)
   116  					}
   117  				} else {
   118  					if job.Context == job2.Context {
   119  						t.Errorf("Jobs %s and %s have the same context: %s", job.Name, job2.Name, job.Context)
   120  					}
   121  					if job2.re.MatchString(job.RerunCommand) {
   122  						t.Errorf("%d, %d, RerunCommand \"%s\" from job %s matches \"%v\" from job %s but shouldn't.", i, j, job.RerunCommand, job.Name, job2.Trigger, job2.Name)
   123  					}
   124  				}
   125  			}
   126  		}
   127  	}
   128  }
   129  
   130  func TestCommentBodyMatches(t *testing.T) {
   131  	var testcases = []struct {
   132  		repo         string
   133  		body         string
   134  		expectedJobs []string
   135  	}{
   136  		{
   137  			"org/repo",
   138  			"this is a random comment",
   139  			[]string{},
   140  		},
   141  		{
   142  			"org/repo",
   143  			"/ok-to-test",
   144  			[]string{"gce", "unit"},
   145  		},
   146  		{
   147  			"org/repo",
   148  			"/test all",
   149  			[]string{"gce", "unit", "gke"},
   150  		},
   151  		{
   152  			"org/repo",
   153  			"/test unit",
   154  			[]string{"unit"},
   155  		},
   156  		{
   157  			"org/repo",
   158  			"/test federation",
   159  			[]string{"federation"},
   160  		},
   161  		{
   162  			"org/repo2",
   163  			"/test all",
   164  			[]string{"cadveapster", "after-cadveapster", "after-after-cadveapster"},
   165  		},
   166  		{
   167  			"org/repo2",
   168  			"/test really",
   169  			[]string{"after-cadveapster"},
   170  		},
   171  		{
   172  			"org/repo2",
   173  			"/test again really",
   174  			[]string{"after-after-cadveapster"},
   175  		},
   176  		{
   177  			"org/repo3",
   178  			"/test all",
   179  			[]string{},
   180  		},
   181  	}
   182  	c := &Config{
   183  		JobConfig: JobConfig{
   184  			Presubmits: map[string][]Presubmit{
   185  				"org/repo": {
   186  					{
   187  						JobBase: JobBase{
   188  							Name: "gce",
   189  						},
   190  						re:        regexp.MustCompile(`/test (gce|all)`),
   191  						AlwaysRun: true,
   192  					},
   193  					{
   194  						JobBase: JobBase{
   195  							Name: "unit",
   196  						},
   197  						re:        regexp.MustCompile(`/test (unit|all)`),
   198  						AlwaysRun: true,
   199  					},
   200  					{
   201  						JobBase: JobBase{
   202  							Name: "gke",
   203  						},
   204  						re:        regexp.MustCompile(`/test (gke|all)`),
   205  						AlwaysRun: false,
   206  					},
   207  					{
   208  						JobBase: JobBase{
   209  							Name: "federation",
   210  						},
   211  						re:        regexp.MustCompile(`/test federation`),
   212  						AlwaysRun: false,
   213  					},
   214  				},
   215  				"org/repo2": {
   216  					{
   217  						JobBase: JobBase{
   218  							Name: "cadveapster",
   219  						},
   220  						re:        regexp.MustCompile(`/test all`),
   221  						AlwaysRun: true,
   222  						RunAfterSuccess: []Presubmit{
   223  							{
   224  								JobBase: JobBase{
   225  									Name: "after-cadveapster",
   226  								},
   227  								re:        regexp.MustCompile(`/test (really|all)`),
   228  								AlwaysRun: true,
   229  								RunAfterSuccess: []Presubmit{
   230  									{
   231  										JobBase: JobBase{
   232  											Name: "after-after-cadveapster",
   233  										},
   234  										re:        regexp.MustCompile(`/test (again really|all)`),
   235  										AlwaysRun: true,
   236  									},
   237  								},
   238  							},
   239  							{
   240  								JobBase: JobBase{
   241  									Name: "another-after-cadveapster",
   242  								},
   243  								re:        regexp.MustCompile(`@k8s-bot don't test this`),
   244  								AlwaysRun: true,
   245  							},
   246  						},
   247  					},
   248  				},
   249  			},
   250  		},
   251  	}
   252  	for _, tc := range testcases {
   253  		actualJobs := c.MatchingPresubmits(tc.repo, tc.body, regexp.MustCompile(`/ok-to-test`).MatchString(tc.body))
   254  		match := true
   255  		if len(actualJobs) != len(tc.expectedJobs) {
   256  			match = false
   257  		} else {
   258  			for _, actualJob := range actualJobs {
   259  				found := false
   260  				for _, expectedJob := range tc.expectedJobs {
   261  					if expectedJob == actualJob.Name {
   262  						found = true
   263  						break
   264  					}
   265  				}
   266  				if !found {
   267  					match = false
   268  					break
   269  				}
   270  			}
   271  		}
   272  		if !match {
   273  			t.Errorf("Wrong jobs for body %s. Got %v, expected %v.", tc.body, actualJobs, tc.expectedJobs)
   274  		}
   275  	}
   276  }
   277  
   278  func TestRetestPresubmits(t *testing.T) {
   279  	var testcases = []struct {
   280  		skipContexts     map[string]bool
   281  		runContexts      map[string]bool
   282  		expectedContexts []string
   283  	}{
   284  		{
   285  			map[string]bool{},
   286  			map[string]bool{},
   287  			[]string{"gce", "unit"},
   288  		},
   289  		{
   290  			map[string]bool{"gce": true},
   291  			map[string]bool{},
   292  			[]string{"unit"},
   293  		},
   294  		{
   295  			map[string]bool{},
   296  			map[string]bool{"federation": true, "nonexistent": true},
   297  			[]string{"gce", "unit", "federation"},
   298  		},
   299  		{
   300  			map[string]bool{},
   301  			map[string]bool{"gke": true},
   302  			[]string{"gce", "unit", "gke"},
   303  		},
   304  		{
   305  			map[string]bool{"gce": true},
   306  			map[string]bool{"gce": true}, // should never happen
   307  			[]string{"unit"},
   308  		},
   309  	}
   310  	c := &Config{
   311  		JobConfig: JobConfig{
   312  			Presubmits: map[string][]Presubmit{
   313  				"org/repo": {
   314  					{
   315  						Context:   "gce",
   316  						AlwaysRun: true,
   317  					},
   318  					{
   319  						Context:   "unit",
   320  						AlwaysRun: true,
   321  					},
   322  					{
   323  						Context:   "gke",
   324  						AlwaysRun: false,
   325  					},
   326  					{
   327  						Context:   "federation",
   328  						AlwaysRun: false,
   329  					},
   330  				},
   331  				"org/repo2": {
   332  					{
   333  						Context:   "shouldneverrun",
   334  						AlwaysRun: true,
   335  					},
   336  				},
   337  			},
   338  		},
   339  	}
   340  	for _, tc := range testcases {
   341  		actualContexts := c.RetestPresubmits("org/repo", tc.skipContexts, tc.runContexts)
   342  		match := true
   343  		if len(actualContexts) != len(tc.expectedContexts) {
   344  			match = false
   345  		} else {
   346  			for _, actualJob := range actualContexts {
   347  				found := false
   348  				for _, expectedContext := range tc.expectedContexts {
   349  					if expectedContext == actualJob.Context {
   350  						found = true
   351  						break
   352  					}
   353  				}
   354  				if !found {
   355  					match = false
   356  					break
   357  				}
   358  			}
   359  		}
   360  		if !match {
   361  			t.Errorf("Wrong contexts for skip %v run %v. Got %v, expected %v.", tc.runContexts, tc.skipContexts, actualContexts, tc.expectedContexts)
   362  		}
   363  	}
   364  
   365  }
   366  
   367  func TestConditionalPresubmits(t *testing.T) {
   368  	presubmits := []Presubmit{
   369  		{
   370  			JobBase: JobBase{
   371  				Name: "cross build",
   372  			},
   373  			RegexpChangeMatcher: RegexpChangeMatcher{
   374  				RunIfChanged: `(Makefile|\.sh|_(windows|linux|osx|unknown)(_test)?\.go)$`,
   375  			},
   376  		},
   377  	}
   378  	SetPresubmitRegexes(presubmits)
   379  	ps := presubmits[0]
   380  	var testcases = []struct {
   381  		changes  []string
   382  		expected bool
   383  	}{
   384  		{[]string{"some random file"}, false},
   385  		{[]string{"./pkg/util/rlimit/rlimit_linux.go"}, true},
   386  		{[]string{"./pkg/util/rlimit/rlimit_unknown_test.go"}, true},
   387  		{[]string{"build.sh"}, true},
   388  		{[]string{"build.shoo"}, false},
   389  		{[]string{"Makefile"}, true},
   390  	}
   391  	for _, tc := range testcases {
   392  		actual := ps.RunsAgainstChanges(tc.changes)
   393  		if actual != tc.expected {
   394  			t.Errorf("wrong RunsAgainstChanges(%#v) result. Got %v, expected %v", tc.changes, actual, tc.expected)
   395  		}
   396  	}
   397  }
   398  
   399  func TestListPresubmit(t *testing.T) {
   400  	c := &Config{
   401  		JobConfig: JobConfig{
   402  			Presubmits: map[string][]Presubmit{
   403  				"r1": {
   404  					{
   405  						JobBase: JobBase{
   406  							Name: "a",
   407  						},
   408  						RunAfterSuccess: []Presubmit{
   409  							{JobBase: JobBase{Name: "aa"}},
   410  							{JobBase: JobBase{Name: "ab"}},
   411  						},
   412  					},
   413  					{JobBase: JobBase{Name: "b"}},
   414  				},
   415  				"r2": {
   416  					{
   417  						JobBase: JobBase{
   418  							Name: "c",
   419  						},
   420  						RunAfterSuccess: []Presubmit{
   421  							{JobBase: JobBase{Name: "ca"}},
   422  							{JobBase: JobBase{Name: "cb"}},
   423  						},
   424  					},
   425  					{JobBase: JobBase{Name: "d"}},
   426  				},
   427  			},
   428  			Postsubmits: map[string][]Postsubmit{
   429  				"r1": {{JobBase: JobBase{Name: "e"}}},
   430  			},
   431  			Periodics: []Periodic{
   432  				{JobBase: JobBase{Name: "f"}},
   433  			},
   434  		},
   435  	}
   436  
   437  	var testcases = []struct {
   438  		name     string
   439  		expected []string
   440  		repos    []string
   441  	}{
   442  		{
   443  			"all presubmits",
   444  			[]string{"a", "aa", "ab", "b", "c", "ca", "cb", "d"},
   445  			[]string{},
   446  		},
   447  		{
   448  			"r2 presubmits",
   449  			[]string{"c", "ca", "cb", "d"},
   450  			[]string{"r2"},
   451  		},
   452  	}
   453  
   454  	for _, tc := range testcases {
   455  		actual := c.AllPresubmits(tc.repos)
   456  		if len(actual) != len(tc.expected) {
   457  			t.Fatalf("test %s - Wrong number of jobs. Got %v, expected %v", tc.name, actual, tc.expected)
   458  		}
   459  		for _, j1 := range tc.expected {
   460  			found := false
   461  			for _, j2 := range actual {
   462  				if j1 == j2.Name {
   463  					found = true
   464  					break
   465  				}
   466  			}
   467  			if !found {
   468  				t.Errorf("test %s - Did not find job %s in output", tc.name, j1)
   469  			}
   470  		}
   471  	}
   472  }
   473  
   474  func TestListPostsubmit(t *testing.T) {
   475  	c := &Config{
   476  		JobConfig: JobConfig{
   477  			Presubmits: map[string][]Presubmit{
   478  				"r1": {{JobBase: JobBase{Name: "a"}}},
   479  			},
   480  			Postsubmits: map[string][]Postsubmit{
   481  				"r1": {
   482  					{
   483  						JobBase: JobBase{
   484  							Name: "c",
   485  						},
   486  						RunAfterSuccess: []Postsubmit{
   487  							{JobBase: JobBase{Name: "ca"}},
   488  							{JobBase: JobBase{Name: "cb"}},
   489  						},
   490  					},
   491  					{JobBase: JobBase{Name: "d"}},
   492  				},
   493  				"r2": {{JobBase: JobBase{Name: "e"}}},
   494  			},
   495  			Periodics: []Periodic{
   496  				{JobBase: JobBase{Name: "f"}},
   497  			},
   498  		},
   499  	}
   500  
   501  	var testcases = []struct {
   502  		name     string
   503  		expected []string
   504  		repos    []string
   505  	}{
   506  		{
   507  			"all postsubmits",
   508  			[]string{"c", "ca", "cb", "d", "e"},
   509  			[]string{},
   510  		},
   511  		{
   512  			"r2 presubmits",
   513  			[]string{"e"},
   514  			[]string{"r2"},
   515  		},
   516  	}
   517  
   518  	for _, tc := range testcases {
   519  		actual := c.AllPostsubmits(tc.repos)
   520  		if len(actual) != len(tc.expected) {
   521  			t.Fatalf("%s - Wrong number of jobs. Got %v, expected %v", tc.name, actual, tc.expected)
   522  		}
   523  		for _, j1 := range tc.expected {
   524  			found := false
   525  			for _, j2 := range actual {
   526  				if j1 == j2.Name {
   527  					found = true
   528  					break
   529  				}
   530  			}
   531  			if !found {
   532  				t.Errorf("Did not find job %s in output", j1)
   533  			}
   534  		}
   535  	}
   536  }
   537  
   538  func TestListPeriodic(t *testing.T) {
   539  	c := &Config{
   540  		JobConfig: JobConfig{
   541  			Presubmits: map[string][]Presubmit{
   542  				"r1": {{JobBase: JobBase{Name: "a"}}},
   543  			},
   544  			Postsubmits: map[string][]Postsubmit{
   545  				"r1": {{JobBase: JobBase{Name: "b"}}},
   546  			},
   547  			Periodics: []Periodic{
   548  				{
   549  					JobBase: JobBase{
   550  						Name: "c",
   551  					},
   552  					RunAfterSuccess: []Periodic{
   553  						{JobBase: JobBase{Name: "ca"}},
   554  						{JobBase: JobBase{Name: "cb"}},
   555  					},
   556  				},
   557  				{JobBase: JobBase{Name: "d"}},
   558  			},
   559  		},
   560  	}
   561  
   562  	expected := []string{"c", "ca", "cb", "d"}
   563  	actual := c.AllPeriodics()
   564  	if len(actual) != len(expected) {
   565  		t.Fatalf("Wrong number of jobs. Got %v, expected %v", actual, expected)
   566  	}
   567  	for _, j1 := range expected {
   568  		found := false
   569  		for _, j2 := range actual {
   570  			if j1 == j2.Name {
   571  				found = true
   572  				break
   573  			}
   574  		}
   575  		if !found {
   576  			t.Errorf("Did not find job %s in output", j1)
   577  		}
   578  	}
   579  }
   580  
   581  func TestRunAgainstBranch(t *testing.T) {
   582  	jobs := []Presubmit{
   583  		{
   584  			JobBase: JobBase{
   585  				Name: "a",
   586  			},
   587  			Brancher: Brancher{SkipBranches: []string{"s"}},
   588  		},
   589  		{
   590  			JobBase: JobBase{
   591  				Name: "b",
   592  			},
   593  			Brancher: Brancher{Branches: []string{"r"}},
   594  		},
   595  		{
   596  			JobBase: JobBase{
   597  				Name: "c",
   598  			},
   599  			Brancher: Brancher{
   600  				SkipBranches: []string{"s"},
   601  				Branches:     []string{"r"},
   602  			},
   603  		},
   604  		{
   605  			JobBase: JobBase{
   606  				Name: "d",
   607  			},
   608  			Brancher: Brancher{
   609  				SkipBranches: []string{"s"},
   610  				Branches:     []string{"s", "r"},
   611  			},
   612  		},
   613  		{
   614  			JobBase: JobBase{
   615  				Name: "default",
   616  			},
   617  		},
   618  	}
   619  
   620  	if err := SetPresubmitRegexes(jobs); err != nil {
   621  		t.Fatalf("could not set regexes: %v", err)
   622  	}
   623  
   624  	for _, job := range jobs {
   625  		if job.Name == "default" {
   626  			if !job.RunsAgainstBranch("s") {
   627  				t.Errorf("Job %s should run branch s", job.Name)
   628  			}
   629  		} else if job.RunsAgainstBranch("s") {
   630  			t.Errorf("Job %s should not run branch s", job.Name)
   631  		}
   632  
   633  		if !job.RunsAgainstBranch("r") {
   634  			t.Errorf("Job %s should run branch r", job.Name)
   635  		}
   636  	}
   637  }
   638  
   639  func TestValidPodNames(t *testing.T) {
   640  	for _, j := range c.AllPresubmits([]string{}) {
   641  		if !podRe.MatchString(j.Name) {
   642  			t.Errorf("Job \"%s\" must match regex \"%s\".", j.Name, podRe.String())
   643  		}
   644  	}
   645  	for _, j := range c.AllPostsubmits([]string{}) {
   646  		if !podRe.MatchString(j.Name) {
   647  			t.Errorf("Job \"%s\" must match regex \"%s\".", j.Name, podRe.String())
   648  		}
   649  	}
   650  	for _, j := range c.AllPeriodics() {
   651  		if !podRe.MatchString(j.Name) {
   652  			t.Errorf("Job \"%s\" must match regex \"%s\".", j.Name, podRe.String())
   653  		}
   654  	}
   655  }
   656  
   657  func TestNoDuplicateJobs(t *testing.T) {
   658  	// Presubmit test is covered under TestPresubmits() above
   659  
   660  	allJobs := make(map[string]bool)
   661  	for _, j := range c.AllPostsubmits([]string{}) {
   662  		if allJobs[j.Name] {
   663  			t.Errorf("Found duplicate job in postsubmit: %s.", j.Name)
   664  		}
   665  		allJobs[j.Name] = true
   666  	}
   667  
   668  	allJobs = make(map[string]bool)
   669  	for _, j := range c.AllPeriodics() {
   670  		if allJobs[j.Name] {
   671  			t.Errorf("Found duplicate job in periodic %s.", j.Name)
   672  		}
   673  		allJobs[j.Name] = true
   674  	}
   675  }
   676  
   677  func TestMergePreset(t *testing.T) {
   678  	tcs := []struct {
   679  		name      string
   680  		jobLabels map[string]string
   681  		pod       *kube.PodSpec
   682  		presets   []Preset
   683  
   684  		shouldError  bool
   685  		numEnv       int
   686  		numVol       int
   687  		numVolMounts int
   688  	}{
   689  		{
   690  			name:      "one volume",
   691  			jobLabels: map[string]string{"foo": "bar"},
   692  			pod:       &kube.PodSpec{},
   693  			presets: []Preset{
   694  				{
   695  					Labels:  map[string]string{"foo": "bar"},
   696  					Volumes: []kube.Volume{{Name: "baz"}},
   697  				},
   698  			},
   699  			numVol: 1,
   700  		},
   701  		{
   702  			name:      "wrong label",
   703  			jobLabels: map[string]string{"foo": "nope"},
   704  			pod:       &kube.PodSpec{},
   705  			presets: []Preset{
   706  				{
   707  					Labels:  map[string]string{"foo": "bar"},
   708  					Volumes: []kube.Volume{{Name: "baz"}},
   709  				},
   710  			},
   711  		},
   712  		{
   713  			name:      "conflicting volume name",
   714  			jobLabels: map[string]string{"foo": "bar"},
   715  			pod:       &kube.PodSpec{Volumes: []kube.Volume{{Name: "baz"}}},
   716  			presets: []Preset{
   717  				{
   718  					Labels:  map[string]string{"foo": "bar"},
   719  					Volumes: []kube.Volume{{Name: "baz"}},
   720  				},
   721  			},
   722  			shouldError: true,
   723  		},
   724  		{
   725  			name:      "non conflicting volume name",
   726  			jobLabels: map[string]string{"foo": "bar"},
   727  			pod:       &kube.PodSpec{Volumes: []kube.Volume{{Name: "baz"}}},
   728  			presets: []Preset{
   729  				{
   730  					Labels:  map[string]string{"foo": "bar"},
   731  					Volumes: []kube.Volume{{Name: "qux"}},
   732  				},
   733  			},
   734  			numVol: 2,
   735  		},
   736  		{
   737  			name:      "one env",
   738  			jobLabels: map[string]string{"foo": "bar"},
   739  			pod:       &kube.PodSpec{Containers: []kube.Container{{}}},
   740  			presets: []Preset{
   741  				{
   742  					Labels: map[string]string{"foo": "bar"},
   743  					Env:    []kube.EnvVar{{Name: "baz"}},
   744  				},
   745  			},
   746  			numEnv: 1,
   747  		},
   748  		{
   749  			name:      "one vm",
   750  			jobLabels: map[string]string{"foo": "bar"},
   751  			pod:       &kube.PodSpec{Containers: []kube.Container{{}}},
   752  			presets: []Preset{
   753  				{
   754  					Labels:       map[string]string{"foo": "bar"},
   755  					VolumeMounts: []kube.VolumeMount{{Name: "baz"}},
   756  				},
   757  			},
   758  			numVolMounts: 1,
   759  		},
   760  		{
   761  			name:      "one of each",
   762  			jobLabels: map[string]string{"foo": "bar"},
   763  			pod:       &kube.PodSpec{Containers: []kube.Container{{}}},
   764  			presets: []Preset{
   765  				{
   766  					Labels:       map[string]string{"foo": "bar"},
   767  					Env:          []kube.EnvVar{{Name: "baz"}},
   768  					VolumeMounts: []kube.VolumeMount{{Name: "baz"}},
   769  					Volumes:      []kube.Volume{{Name: "qux"}},
   770  				},
   771  			},
   772  			numEnv:       1,
   773  			numVol:       1,
   774  			numVolMounts: 1,
   775  		},
   776  		{
   777  			name:      "two vm",
   778  			jobLabels: map[string]string{"foo": "bar"},
   779  			pod:       &kube.PodSpec{Containers: []kube.Container{{}}},
   780  			presets: []Preset{
   781  				{
   782  					Labels:       map[string]string{"foo": "bar"},
   783  					VolumeMounts: []kube.VolumeMount{{Name: "baz"}, {Name: "foo"}},
   784  				},
   785  			},
   786  			numVolMounts: 2,
   787  		},
   788  	}
   789  	for _, tc := range tcs {
   790  		if err := resolvePresets("foo", tc.jobLabels, tc.pod, tc.presets); err == nil && tc.shouldError {
   791  			t.Errorf("For test \"%s\": expected error but got none.", tc.name)
   792  		} else if err != nil && !tc.shouldError {
   793  			t.Errorf("For test \"%s\": expected no error but got %v.", tc.name, err)
   794  		}
   795  		if tc.shouldError {
   796  			continue
   797  		}
   798  		if len(tc.pod.Volumes) != tc.numVol {
   799  			t.Errorf("For test \"%s\": wrong number of volumes. Got %d, expected %d.", tc.name, len(tc.pod.Volumes), tc.numVol)
   800  		}
   801  		for _, c := range tc.pod.Containers {
   802  			if len(c.VolumeMounts) != tc.numVolMounts {
   803  				t.Errorf("For test \"%s\": wrong number of volume mounts. Got %d, expected %d.", tc.name, len(c.VolumeMounts), tc.numVolMounts)
   804  			}
   805  			if len(c.Env) != tc.numEnv {
   806  				t.Errorf("For test \"%s\": wrong number of env vars. Got %d, expected %d.", tc.name, len(c.Env), tc.numEnv)
   807  			}
   808  		}
   809  	}
   810  }