private void validateElasticProfileId(JobConfig jobConfig, PipelineConfigSaveValidationContext preprocessedConfig) { String elasticProfileId = jobConfig.getElasticProfileId(); if (elasticProfileId != null && !preprocessedConfig.isValidProfileId(elasticProfileId)) { String message = String.format("No profile defined corresponding to profile_id '%s'", elasticProfileId); jobConfig.addError("elasticProfileId", message); this.errors().addAll(jobConfig.errors()); } }
@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 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 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 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
@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 shouldValidateElasticProfileId() { PipelineConfig pipelineConfig=PipelineConfigMother.createPipelineConfigWithJobConfigs("pipeline1"); JobConfig jobConfig = JobConfigMother.createJobConfigWithJobNameAndEmptyResources(); ValidationContext validationContext=mock(ValidationContext.class); jobConfig.setResourceConfigs(new ResourceConfigs()); 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 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 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 shouldNotValidateJobNameUniquenessIfNameIsEmptyString(){ JobConfig job = new JobConfig(" "); job.validateNameUniqueness(new HashMap<>()); assertTrue(job.errors().isEmpty()); }
@Test public void shouldNotValidateJobNameUniquenessInAbsenceOfName(){ JobConfig job = new JobConfig(); job.validateNameUniqueness(new HashMap<>()); assertTrue(job.errors().isEmpty()); }
@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 shouldValidateTree() throws Exception{ PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfig("pipeline"); JobConfigs jobs = pipelineConfig.get(0).getJobs(); jobs.add(new JobConfig("quux")); jobs.setConfigAttributes(a(m(JobConfig.NAME, "foo"), m(JobConfig.NAME, "foo"))); assertThat(jobs.size(), is(2)); JobConfig firstFoo = jobs.get(0); JobConfig secondFoo = jobs.get(1); assertThat(firstFoo.name(), is(new CaseInsensitiveString("foo"))); assertThat(secondFoo.name(), is(new CaseInsensitiveString("foo"))); assertThat(firstFoo.errors().isEmpty(), is(true)); assertThat(secondFoo.errors().isEmpty(), is(true)); jobs.validate(PipelineConfigSaveValidationContext.forChain(true, "group", pipelineConfig, pipelineConfig.get(0), jobs)); assertThat(firstFoo.errors().on(JobConfig.NAME), is("You have defined multiple jobs called 'foo'. Job names are case-insensitive and must be unique.")); assertThat(secondFoo.errors().on(JobConfig.NAME), is("You have defined multiple jobs called 'foo'. Job names are case-insensitive and must be unique.")); }
@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 shouldNotFailForRepeatedJobNames_shouldInsteedSetErrorsOnValidation() throws Exception{ CruiseConfig config = new BasicCruiseConfig(); PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfig("pipeline"); config.addPipeline("grp", pipelineConfig); JobConfigs jobs = pipelineConfig.get(0).getJobs(); jobs.add(new JobConfig("quux")); jobs.setConfigAttributes(a(m(JobConfig.NAME, "foo"), m(JobConfig.NAME, "foo"))); assertThat(jobs.size(), is(2)); JobConfig firstFoo = jobs.get(0); JobConfig secondFoo = jobs.get(1); assertThat(firstFoo.name(), is(new CaseInsensitiveString("foo"))); assertThat(secondFoo.name(), is(new CaseInsensitiveString("foo"))); assertThat(firstFoo.errors().isEmpty(), is(true)); assertThat(secondFoo.errors().isEmpty(), is(true)); jobs.validate(ConfigSaveValidationContext.forChain(config, config.getGroups(), config.getGroups().get(0), pipelineConfig, pipelineConfig.get(0), jobs)); assertThat(firstFoo.errors().on(JobConfig.NAME), is("You have defined multiple jobs called 'foo'. Job names are case-insensitive and must be unique.")); assertThat(secondFoo.errors().on(JobConfig.NAME), is("You have defined multiple jobs called 'foo'. Job names are case-insensitive and must be unique.")); }
@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 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")); }
@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 shouldCopyErrorsForFieldsOnPipelineConfig(){ PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfig("pipeline", MaterialConfigsMother.defaultMaterialConfigs(), new JobConfigs(JobConfigMother.createJobConfigWithJobNameAndEmptyResources())); pipelineConfig.setVariables(new EnvironmentVariablesConfig(asList(new EnvironmentVariableConfig("name", "value")))); PipelineConfig pipelineWithErrors = new Cloner().deepClone(pipelineConfig); pipelineWithErrors.getVariables().get(0).addError("name", "error on environment variable"); pipelineWithErrors.first().addError("name", "error on stage"); pipelineWithErrors.first().getJobs().first().addError("name", "error on job"); BasicCruiseConfig.copyErrors(pipelineWithErrors, pipelineConfig); assertThat(pipelineConfig.getVariables().get(0).errors().on("name"), is("error on environment variable")); assertThat(pipelineConfig.first().errors().on("name"), is("error on stage")); assertThat(pipelineConfig.first().getJobs().first().errors().on("name"), is("error on job")); }