/* * Copyright 2017 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.domain; import com.thoughtworks.go.config.*; import com.thoughtworks.go.helper.JobConfigMother; import com.thoughtworks.go.helper.PipelineConfigMother; import com.thoughtworks.go.service.TaskFactory; import com.thoughtworks.go.util.DataStructureUtils; import com.thoughtworks.go.util.ReflectionUtil; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import java.util.HashMap; import static com.thoughtworks.go.util.DataStructureUtils.a; import static com.thoughtworks.go.util.DataStructureUtils.m; import static com.thoughtworks.go.util.TestUtils.sizeIs; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; public class JobConfigTest { JobConfig config; @Before public void setup(){ config = new JobConfig(); Tasks tasks = mock(Tasks.class); config.injectTasksForTest(tasks); doNothing().when(tasks).setConfigAttributes(Matchers.<Object>anyObject(), Matchers.<TaskFactory>any()); } @Test public void shouldCopyAttributeValuesFromAttributeMap() throws Exception { config = new JobConfig();//override the setup mock TaskFactory taskFactory = mock(TaskFactory.class); ExecTask emptyExecTask = new ExecTask(); when(taskFactory.taskInstanceFor(emptyExecTask.getTaskType())).thenReturn(emptyExecTask); config.setConfigAttributes(DataStructureUtils.m(JobConfig.NAME, "foo-job", JobConfig.TASKS, DataStructureUtils.m(Tasks.TASK_OPTIONS, "exec", "exec", DataStructureUtils.m(Task.TASK_TYPE, "exec", ExecTask.COMMAND, "ls", ExecTask.ARGS, "-la", ExecTask.WORKING_DIR, "/tmp"))), taskFactory); assertThat(config.name(), is(new CaseInsensitiveString("foo-job"))); assertThat(config.getTasks().get(0), is(new ExecTask("ls", "-la", "/tmp"))); assertThat(config.getTasks().size(), is(1)); } @Test public void shouldSetTimeoutIfSpecified() throws Exception { config.setConfigAttributes( m(JobConfig.NAME, "foo-job", "timeoutType", JobConfig.OVERRIDE_TIMEOUT, JobConfig.TIMEOUT, "100", JobConfig.TASKS, m(Tasks.TASK_OPTIONS, "exec", "exec", m(Task.TASK_TYPE, "exec", ExecTask.COMMAND, "ls", ExecTask.ARGS, "-la", ExecTask.WORKING_DIR, "/tmp")))); assertThat(config.getTimeout(), is("100")); } @Test public void shouldClearTimeoutIfSubmittedWithEmptyValue() throws Exception { config.setConfigAttributes( m(JobConfig.NAME, "foo-job", "timeoutType", JobConfig.OVERRIDE_TIMEOUT, JobConfig.TIMEOUT, "", JobConfig.TASKS, m(Tasks.TASK_OPTIONS, "exec", "exec", m(Task.TASK_TYPE, "exec", ExecTask.COMMAND, "ls", ExecTask.ARGS, "-la", ExecTask.WORKING_DIR, "/tmp"))) ); assertThat(config.getTimeout(), is(nullValue())); } @Test public void shouldSetTimeoutToZeroIfSubmittedWithNever() throws Exception { config.setConfigAttributes(m(JobConfig.NAME, "foo-job", "timeoutType", JobConfig.NEVER_TIMEOUT, JobConfig.TIMEOUT, "100", JobConfig.TASKS, m(Tasks.TASK_OPTIONS, "exec", "exec", m(Task.TASK_TYPE, "exec", ExecTask.COMMAND, "ls", ExecTask.ARGS, "-la", ExecTask.WORKING_DIR, "/tmp")))); assertThat(config.getTimeout(), is("0")); } @Test public void shouldSetTimeoutToNullIfSubmittedWithDefault() throws Exception { config.setConfigAttributes(m(JobConfig.NAME, "foo-job", "timeoutType", JobConfig.DEFAULT_TIMEOUT, JobConfig.TIMEOUT, "", JobConfig.TASKS, m(Tasks.TASK_OPTIONS, "exec", "exec", m(Task.TASK_TYPE, "exec", ExecTask.COMMAND, "ls", ExecTask.ARGS, "-la", ExecTask.WORKING_DIR, "/tmp")))); assertThat(config.getTimeout(), is(nullValue())); } @Test public void shouldNotSetJobNameIfNotGiven() throws Exception { JobConfig config = new JobConfig("some-job-name"); config.setConfigAttributes(m()); assertThat(config.name(), is(new CaseInsensitiveString("some-job-name"))); config.setConfigAttributes(m(JobConfig.NAME, null)); assertThat(config.name(), is(nullValue())); } @Test public void shouldReturnAntTaskAsDefaultIfNoTasksSpecified() { JobConfig jobConfig = new JobConfig(); assertThat(jobConfig.tasks(), sizeIs(1)); Task task = jobConfig.tasks().first(); assertThat(task, instanceOf(NullTask.class)); } @Test public void shouldNotSetTasksIfNoTasksGiven() throws Exception { config = new JobConfig(); AntTask task = new AntTask(); task.setTarget("hello"); config.addTask(task); config.setConfigAttributes(m()); AntTask taskAfterUpdate = (AntTask) config.getTasks().get(0); assertThat(taskAfterUpdate.getTarget(), is("hello")); assertThat(config.getTasks().size(), is(1)); config.setConfigAttributes(m(JobConfig.TASKS, null)); assertThat(config.getTasks().size(), is(0)); } @Test public void shouldValidateTheJobName() { assertThat(createJobAndValidate(".name").errors().isEmpty(), is(true)); ConfigErrors configErrors = createJobAndValidate("name pavan").errors(); assertThat(configErrors.isEmpty(), is(false)); assertThat(configErrors.on(JobConfig.NAME), is("Invalid job name 'name pavan'. This must be alphanumeric and may contain underscores and periods. The maximum allowed length is 255 characters.")); } @Test public void shouldFailValidationWhenJobNameIsEmpty(){ ConfigErrors configErrors = createJobAndValidate(null).errors(); assertThat(configErrors.isEmpty(), is(false)); assertThat(configErrors.on(JobConfig.NAME), is("Name is a required field")); } @Test public void shouldValidateTheJobNameAgainstHaving_runOnAll() { String jobName = "a-runOnAll-1"; ConfigErrors configErrors = createJobAndValidate(jobName).errors(); assertThat(configErrors.isEmpty(), is(false)); assertThat(configErrors.on(JobConfig.NAME), is(String.format("A job cannot have 'runOnAll' in it's name: %s because it is a reserved keyword", jobName))); } @Test public void shouldValidateTheJobNameAgainstHaving_runInstance() { String jobName = "a-runInstance-1"; ConfigErrors configErrors = createJobAndValidate(jobName).errors(); assertThat(configErrors.isEmpty(), is(false)); assertThat(configErrors.on(JobConfig.NAME), is(String.format("A job cannot have 'runInstance' in it's name: %s because it is a reserved keyword", jobName))); } @Test public void shouldValidateAgainstSettingRunInstanceCountToIncorrectValue() { JobConfig jobConfig1 = new JobConfig(new CaseInsensitiveString("test")); jobConfig1.setRunInstanceCount(-1); jobConfig1.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); ConfigErrors configErrors1 = jobConfig1.errors(); assertThat(configErrors1.isEmpty(), is(false)); assertThat(configErrors1.on(JobConfig.RUN_TYPE), is("'Run Instance Count' cannot be a negative number as it represents number of instances Go needs to spawn during runtime.")); JobConfig jobConfig2 = new JobConfig(new CaseInsensitiveString("test")); ReflectionUtil.setField(jobConfig2, "runInstanceCount", "abcd"); jobConfig2.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); ConfigErrors configErrors2 = jobConfig2.errors(); assertThat(configErrors2.isEmpty(), is(false)); assertThat(configErrors2.on(JobConfig.RUN_TYPE), is("'Run Instance Count' should be a valid positive integer as it represents number of instances Go needs to spawn during runtime.")); } @Test public void shouldValidateAgainstSettingRunOnAllAgentsAndRunInstanceCountSetTogether() { JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("test")); jobConfig.setRunOnAllAgents(true); jobConfig.setRunInstanceCount(10); jobConfig.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); ConfigErrors configErrors = jobConfig.errors(); assertThat(configErrors.isEmpty(), is(false)); assertThat(configErrors.on(JobConfig.RUN_TYPE), is("Job cannot be 'run on all agents' type and 'run multiple instance' type together.")); } @Test public void shouldValidateEmptyAndNullResources() { PipelineConfig pipelineConfig=PipelineConfigMother.createPipelineConfigWithJobConfigs("pipeline1"); JobConfig jobConfig = JobConfigMother.createJobConfigWithJobNameAndEmptyResources(); ValidationContext validationContext=mock(ValidationContext.class); when(validationContext.getPipeline()).thenReturn(pipelineConfig); when(validationContext.getStage()).thenReturn(pipelineConfig.getFirstStageConfig()); jobConfig.validate(validationContext); assertThat(jobConfig.errors().isEmpty(), is(false)); assertThat(jobConfig.errors().getAll().get(0),is("Empty resource name in job \"defaultJob\" of stage \"mingle\" of pipeline \"pipeline1\". If a template is used, please ensure that the resource parameters are defined for this pipeline.")); } @Test public void shouldValidateAgainstPresenceOfBothResourcesAndElasticProfileId() { PipelineConfig pipelineConfig=PipelineConfigMother.createPipelineConfigWithJobConfigs("pipeline1"); JobConfig jobConfig = JobConfigMother.createJobConfigWithJobNameAndEmptyResources(); ValidationContext validationContext=mock(ValidationContext.class); jobConfig.setElasticProfileId("docker.unit-test"); when(validationContext.getPipeline()).thenReturn(pipelineConfig); when(validationContext.getStage()).thenReturn(pipelineConfig.getFirstStageConfig()); jobConfig.validate(validationContext); assertThat(jobConfig.errors().isEmpty(), is(false)); assertThat(jobConfig.errors().on(JobConfig.ELASTIC_PROFILE_ID), is("Job cannot have both `resource` and `elasticProfileId`")); assertThat(jobConfig.errors().on(JobConfig.RESOURCES), is("Job cannot have both `resource` and `elasticProfileId`")); } @Test public void shouldValidateElasticProfileId() { PipelineConfig pipelineConfig=PipelineConfigMother.createPipelineConfigWithJobConfigs("pipeline1"); JobConfig jobConfig = JobConfigMother.createJobConfigWithJobNameAndEmptyResources(); ValidationContext validationContext=mock(ValidationContext.class); jobConfig.setResources(new Resources()); jobConfig.setElasticProfileId("non-existent-profile-id"); when(validationContext.getPipeline()).thenReturn(pipelineConfig); when(validationContext.getStage()).thenReturn(pipelineConfig.getFirstStageConfig()); when(validationContext.isValidProfileId("non-existent-profile-id")).thenReturn(false); jobConfig.validate(validationContext); assertThat(jobConfig.errors().isEmpty(), is(false)); assertThat(jobConfig.errors().on(JobConfig.ELASTIC_PROFILE_ID), is("No profile defined corresponding to profile_id 'non-existent-profile-id'")); } @Test public void shouldErrorOutIfTwoJobsHaveSameName() { HashMap<String, JobConfig> visitedConfigs = new HashMap<>(); visitedConfigs.put("defaultJob".toLowerCase(), new JobConfig("defaultJob")); JobConfig defaultJob = new JobConfig("defaultJob"); defaultJob.validateNameUniqueness(visitedConfigs); assertThat(defaultJob.errors().isEmpty(), is(false)); assertThat(defaultJob.errors().on(JobConfig.NAME), is("You have defined multiple jobs called 'defaultJob'. Job names are case-insensitive and must be unique.")); JobConfig defaultJobAllLowerCase = new JobConfig("defaultjob"); defaultJobAllLowerCase.validateNameUniqueness(visitedConfigs); assertThat(defaultJobAllLowerCase.errors().isEmpty(), is(false)); assertThat(defaultJobAllLowerCase.errors().on(JobConfig.NAME), is("You have defined multiple jobs called 'defaultjob'. Job names are case-insensitive and must be unique.")); } @Test public void shouldNotValidateJobNameUniquenessInAbsenceOfName(){ JobConfig job = new JobConfig(); job.validateNameUniqueness(new HashMap<>()); assertTrue(job.errors().isEmpty()); } @Test public void shouldNotValidateJobNameUniquenessIfNameIsEmptyString(){ JobConfig job = new JobConfig(" "); job.validateNameUniqueness(new HashMap<>()); assertTrue(job.errors().isEmpty()); } @Test public void shouldPopulateEnvironmentVariablesFromAttributeMap() { JobConfig jobConfig = new JobConfig(); HashMap map = new HashMap(); HashMap valueHashMap = new HashMap(); valueHashMap.put("name", "FOO"); valueHashMap.put("value", "BAR"); map.put(JobConfig.ENVIRONMENT_VARIABLES, valueHashMap); EnvironmentVariablesConfig mockEnvironmentVariablesConfig = mock(EnvironmentVariablesConfig.class); jobConfig.setVariables(mockEnvironmentVariablesConfig); jobConfig.setConfigAttributes(map); verify(mockEnvironmentVariablesConfig).setConfigAttributes(valueHashMap); } @Test public void shouldPopulateResourcesFromAttributeMap() { HashMap map = new HashMap(); String value = "a, b,c ,d,e"; map.put(JobConfig.RESOURCES, value); Resources resources = new Resources(); resources.add(new Resource("z")); JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("job-name"), resources, null); jobConfig.setConfigAttributes(map); assertThat(jobConfig.resources().size(), is(5)); } @Test public void shouldPopulateTabsFromAttributeMap() { JobConfig jobConfig = new JobConfig("job-name"); jobConfig.setConfigAttributes(m(JobConfig.TABS, a(m(Tab.NAME, "tab1", Tab.PATH, "path1"), m(Tab.NAME, "tab2", Tab.PATH, "path2")))); assertThat(jobConfig.getTabs().size(), is(2)); assertThat(jobConfig.getTabs().get(0).getName(), is("tab1")); assertThat(jobConfig.getTabs().get(1).getName(), is("tab2")); assertThat(jobConfig.getTabs().get(0).getPath(), is("path1")); assertThat(jobConfig.getTabs().get(1).getPath(), is("path2")); } @Test public void shouldSetJobRunTypeCorrectly_forRails4() { // single instance HashMap map1 = new HashMap(); map1.put(JobConfig.RUN_TYPE, JobConfig.RUN_SINGLE_INSTANCE); map1.put(JobConfig.RUN_INSTANCE_COUNT, "10"); // should be ignored JobConfig jobConfig1 = new JobConfig(); jobConfig1.setConfigAttributes(map1); assertThat(jobConfig1.isRunOnAllAgents(), is(false)); assertThat(jobConfig1.isRunMultipleInstanceType(), is(false)); assertThat(jobConfig1.getRunInstanceCount(), is(nullValue())); // run on all agents HashMap map2 = new HashMap(); map2.put(JobConfig.RUN_TYPE, JobConfig.RUN_ON_ALL_AGENTS); JobConfig jobConfig2 = new JobConfig(); jobConfig2.setConfigAttributes(map2); assertThat(jobConfig2.isRunOnAllAgents(), is(true)); assertThat(jobConfig2.isRunMultipleInstanceType(), is(false)); assertThat(jobConfig2.getRunInstanceCount(), is(nullValue())); // run multiple instance HashMap map3 = new HashMap(); map3.put(JobConfig.RUN_TYPE, JobConfig.RUN_MULTIPLE_INSTANCE); map3.put(JobConfig.RUN_INSTANCE_COUNT, "10"); JobConfig jobConfig3 = new JobConfig(); jobConfig3.setConfigAttributes(map3); assertThat(jobConfig3.isRunMultipleInstanceType(), is(true)); assertThat(jobConfig3.getRunInstanceCountValue(), is(10)); assertThat(jobConfig3.isRunOnAllAgents(), is(false)); HashMap map4 = new HashMap(); map4.put(JobConfig.RUN_TYPE, JobConfig.RUN_MULTIPLE_INSTANCE); map4.put(JobConfig.RUN_INSTANCE_COUNT, ""); JobConfig jobConfig4 = new JobConfig(); jobConfig4.setConfigAttributes(map4); assertThat(jobConfig4.isRunMultipleInstanceType(), is(false)); assertThat(jobConfig4.getRunInstanceCount(), is(nullValue())); assertThat(jobConfig4.isRunOnAllAgents(), is(false)); } @Test public void shouldResetJobRunTypeCorrectly() { HashMap map1 = new HashMap(); map1.put(JobConfig.RUN_TYPE, JobConfig.RUN_MULTIPLE_INSTANCE); map1.put(JobConfig.RUN_INSTANCE_COUNT, "10"); JobConfig jobConfig = new JobConfig(); jobConfig.setConfigAttributes(map1); assertThat(jobConfig.getRunInstanceCountValue(), is(10)); assertThat(jobConfig.isRunMultipleInstanceType(), is(true)); assertThat(jobConfig.isRunOnAllAgents(), is(false)); // should not reset value when correct key not present HashMap map2 = new HashMap(); jobConfig.setConfigAttributes(map2); assertThat(jobConfig.getRunInstanceCountValue(), is(10)); assertThat(jobConfig.isRunMultipleInstanceType(), is(true)); assertThat(jobConfig.isRunOnAllAgents(), is(false)); // reset value for same job config HashMap map3 = new HashMap(); map3.put(JobConfig.RUN_TYPE, JobConfig.RUN_SINGLE_INSTANCE); jobConfig.setConfigAttributes(map3); assertThat(jobConfig.isRunMultipleInstanceType(), is(false)); assertThat(jobConfig.getRunInstanceCount(), is(nullValue())); assertThat(jobConfig.isRunOnAllAgents(), is(false)); } @Test public void shouldPopulateArtifactPlansFromAttributeMap() { HashMap map = new HashMap(); HashMap valueHashMap = new HashMap(); valueHashMap.put("src", "dest"); valueHashMap.put("src1", "dest1"); map.put(JobConfig.ARTIFACT_PLANS, valueHashMap); ArtifactPlans mockArtifactPlans = mock(ArtifactPlans.class); JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("job-name"), new Resources(), mockArtifactPlans); jobConfig.setConfigAttributes(map); verify(mockArtifactPlans).setConfigAttributes(valueHashMap); } @Test public void shouldValidateThatTheTimeoutIsAValidNumber() { JobConfig job = new JobConfig("job"); job.setTimeout("5.5"); job.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); assertThat(job.errors().isEmpty(), is(true)); } @Test public void shouldMarkJobInvalidIfTimeoutIsNotAValidNumber() { JobConfig job = new JobConfig("job"); job.setTimeout("5.5MN"); job.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); assertThat(job.errors().isEmpty(), is(false)); assertThat(job.errors().on(JobConfig.TIMEOUT), is("Timeout should be a valid number as it represents number of minutes")); } @Test public void shouldReturnTimeoutType() { JobConfig job = new JobConfig("job"); assertThat(job.getTimeoutType(), is(JobConfig.DEFAULT_TIMEOUT)); job.setTimeout("0"); assertThat(job.getTimeoutType(), is(JobConfig.NEVER_TIMEOUT)); job.setTimeout("10"); assertThat(job.getTimeoutType(), is(JobConfig.OVERRIDE_TIMEOUT)); } @Test public void shouldReturnRunTypeCorrectly() { JobConfig job = new JobConfig("job"); assertThat(job.getRunType(), is(JobConfig.RUN_SINGLE_INSTANCE)); job.setRunOnAllAgents(true); assertThat(job.getRunType(), is(JobConfig.RUN_ON_ALL_AGENTS)); job.setRunOnAllAgents(false); job.setRunInstanceCount(10); assertThat(job.getRunType(), is(JobConfig.RUN_MULTIPLE_INSTANCE)); } @Test public void shouldErrorOutWhenTimeoutIsANegativeNumber() { JobConfig jobConfig = new JobConfig("job"); jobConfig.setTimeout("-1"); jobConfig.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); assertThat(jobConfig.errors().isEmpty(), is(false)); assertThat(jobConfig.errors().on(JobConfig.TIMEOUT), is("Timeout cannot be a negative number as it represents number of minutes")); } @Test public void shouldValidateTree(){ Resources resources = mock(Resources.class); when(resources.iterator()).thenReturn(new Resources().iterator()); ArtifactPlans artifactPlans = mock(ArtifactPlans.class); ArtifactPropertiesGenerators properties = mock(ArtifactPropertiesGenerators.class); Tasks tasks = mock(Tasks.class); Tabs tabs = mock(Tabs.class); EnvironmentVariablesConfig variables = mock(EnvironmentVariablesConfig.class); when(tasks.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(true); when(resources.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(true); when(properties.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(true); when(artifactPlans.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(true); when(tabs.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(true); when(variables.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(true); JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("job"), resources, artifactPlans, tasks); jobConfig.setTabs(tabs); jobConfig.setProperties(properties); jobConfig.setVariables(variables); PipelineConfigSaveValidationContext context = PipelineConfigSaveValidationContext.forChain(true, "group", new PipelineConfig(), new StageConfig(), jobConfig); assertThat(jobConfig.validateTree(context), is(true)); ArgumentCaptor<PipelineConfigSaveValidationContext> captor = ArgumentCaptor.forClass(PipelineConfigSaveValidationContext.class); verify(tasks).validateTree(captor.capture()); PipelineConfigSaveValidationContext childContext = captor.getValue(); assertThat(childContext.getParent(), is(jobConfig)); verify(resources).validateTree(childContext); verify(properties).validateTree(childContext); verify(artifactPlans).validateTree(childContext); verify(tabs).validateTree(childContext); verify(variables).validateTree(childContext); } @Test public void shouldFailValidationIfAnyDescendentIsInvalid(){ Resources resources = mock(Resources.class); when(resources.iterator()).thenReturn(new Resources().iterator()); ArtifactPlans artifactPlans = mock(ArtifactPlans.class); ArtifactPropertiesGenerators properties = mock(ArtifactPropertiesGenerators.class); Tasks tasks = mock(Tasks.class); Tabs tabs = mock(Tabs.class); EnvironmentVariablesConfig variables = mock(EnvironmentVariablesConfig.class); when(tasks.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(false); when(resources.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(false); when(properties.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(false); when(artifactPlans.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(false); when(tabs.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(false); when(variables.validateTree(Matchers.<PipelineConfigSaveValidationContext>any())).thenReturn(false); JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("job"), resources, artifactPlans, tasks); jobConfig.setTabs(tabs); jobConfig.setProperties(properties); jobConfig.setVariables(variables); PipelineConfigSaveValidationContext context = PipelineConfigSaveValidationContext.forChain(true, "group", new PipelineConfig(), new StageConfig(), jobConfig); assertThat(jobConfig.validateTree(context), is(false)); ArgumentCaptor<PipelineConfigSaveValidationContext> captor = ArgumentCaptor.forClass(PipelineConfigSaveValidationContext.class); verify(tasks).validateTree(captor.capture()); PipelineConfigSaveValidationContext childContext = captor.getValue(); assertThat(childContext.getParent(), is(jobConfig)); verify(resources).validateTree(childContext); verify(properties).validateTree(childContext); verify(artifactPlans).validateTree(childContext); verify(tabs).validateTree(childContext); verify(variables).validateTree(childContext); } @Test public void shouldValidateAgainstSettingRunOnAllAgentsForAJobAssignedToElasticAgent() { JobConfig jobConfig = new JobConfig(new CaseInsensitiveString("test")); jobConfig.setRunOnAllAgents(true); jobConfig.setElasticProfileId("ubuntu-dev"); jobConfig.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); ConfigErrors configErrors = jobConfig.errors(); assertThat(configErrors.isEmpty(), is(false)); assertThat(configErrors.on(JobConfig.RUN_TYPE), is("Job cannot be set to 'run on all agents' when assigned to an elastic agent")); } private JobConfig createJobAndValidate(final String name) { JobConfig jobConfig = new JobConfig(name); jobConfig.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig())); return jobConfig; } }