@Override public boolean isValid(CruiseConfig preprocessedConfig) { preprocessedPipelineConfig = preprocessedConfig.getPipelineConfigByName(pipelineConfig.name()); PipelineConfigSaveValidationContext validationContext = PipelineConfigSaveValidationContext.forChain(true, groupName, preprocessedConfig, preprocessedPipelineConfig); validatePublishAndFetchExternalConfigs(preprocessedPipelineConfig, preprocessedConfig); boolean isValid = preprocessedPipelineConfig.validateTree(validationContext) && preprocessedPipelineConfig.getAllErrors().isEmpty(); if (!isValid) { copyErrors(preprocessedPipelineConfig, pipelineConfig); } return isValid; }
@Override public boolean isValid(CruiseConfig preprocessedConfig) { preprocessedPipelineConfig = preprocessedConfig.getPipelineConfigByName(pipelineConfig.name()); PipelineConfigSaveValidationContext validationContext = PipelineConfigSaveValidationContext.forChain(false, getPipelineGroup(), preprocessedConfig, preprocessedPipelineConfig); validatePublishAndFetchExternalConfigs(preprocessedPipelineConfig, preprocessedConfig); boolean isValid = preprocessedPipelineConfig.validateTree(validationContext) && preprocessedPipelineConfig.getAllErrors().isEmpty(); if (!isValid) { copyErrors(preprocessedPipelineConfig, pipelineConfig); } return isValid; }
pipelineConfig.setTimer(timerConfig); boolean isValid = pipelineConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs("group", new Authorization())), pipelineConfig)); assertTrue(isValid); verify(stageConfig).validateTree(any(PipelineConfigSaveValidationContext.class));
pipelineConfig.setTimer(timerConfig); boolean isValid = pipelineConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs("group", new Authorization())), pipelineConfig)); assertFalse(isValid); verify(stageConfig).validateTree(any(PipelineConfigSaveValidationContext.class));
@Test public void shouldCheckForPipelineNameUniqueness() { BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("p1"); String group = "group"; cruiseConfig.getGroups().add(new BasicPipelineConfigs(group, new Authorization())); PipelineConfig p1Duplicate = GoConfigMother.createPipelineConfigWithMaterialConfig("p1", new GitMaterialConfig("url")); cruiseConfig.addPipeline(group, p1Duplicate); PipelineConfigSaveValidationContext context = PipelineConfigSaveValidationContext.forChain(true, group, cruiseConfig, p1Duplicate); p1Duplicate.validateTree(context); assertThat(p1Duplicate.errors().on(PipelineConfig.NAME), is(String.format("You have defined multiple pipelines named '%s'. Pipeline names must be unique. Source(s): [cruise-config.xml]", p1Duplicate.name()))); }
@Test public void shouldNotAddValidationErrorWhenAssociatedTemplateExists() { PipelineConfig pipelineConfig = new PipelineConfig(new CaseInsensitiveString("wunderbar"), new MaterialConfigs()); config.addPipeline("group", pipelineConfig); config.addTemplate(new PipelineTemplateConfig(new CaseInsensitiveString("t1"))); pipelineConfig.setTemplateName(new CaseInsensitiveString("t1")); pipelineConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", config, pipelineConfig)); assertThat(pipelineConfig.errors().getAllOn("template"), is(nullValue())); }
@Test public void shouldFailValidateWhenUpstreamPipelineForDependencyMaterialDoesNotExist() { String upstreamPipeline = "non-existant"; PipelineConfig pipelineConfig = GoConfigMother.createPipelineConfigWithMaterialConfig( new DependencyMaterialConfig(new CaseInsensitiveString(upstreamPipeline), new CaseInsensitiveString("non-existant"))); BasicCruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs(pipelineConfig)); boolean isValid = pipelineConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, cruiseConfig.getGroups().first().getGroup(), cruiseConfig, pipelineConfig)); assertThat(isValid, is(false)); ConfigErrors materialErrors = pipelineConfig.materialConfigs().first().errors(); assertThat(materialErrors.isEmpty(), is(false)); assertThat(materialErrors.firstError(), is("Pipeline with name 'non-existant' does not exist, it is defined as a dependency for pipeline 'pipeline' (cruise-config.xml)")); }
@Test public void shouldValidateAPipelineHasAtleastOneStage() { PipelineConfig pipelineConfig = new PipelineConfig(new CaseInsensitiveString("p"), new MaterialConfigs()); pipelineConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs("group", new Authorization())), pipelineConfig)); assertThat(pipelineConfig.errors().on("pipeline"), is("Pipeline 'p' does not have any stages configured. A pipeline must have at least one stage.")); }
@Test public void shouldFailValidateWhenUpstreamStageForDependencyMaterialDoesNotExist() { String upstreamPipeline = "upstream"; String upstreamStage = "non-existant"; PipelineConfig upstream = GoConfigMother.createPipelineConfigWithMaterialConfig(upstreamPipeline, new GitMaterialConfig("url")); PipelineConfig pipelineConfig = GoConfigMother.createPipelineConfigWithMaterialConfig("downstream", new DependencyMaterialConfig(new CaseInsensitiveString(upstreamPipeline), new CaseInsensitiveString(upstreamStage))); BasicCruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs(pipelineConfig, upstream)); boolean isValid = pipelineConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, cruiseConfig.getGroups().first().getGroup(), cruiseConfig, pipelineConfig)); assertThat(isValid, is(false)); ConfigErrors materialErrors = pipelineConfig.materialConfigs().first().errors(); assertThat(materialErrors.isEmpty(), is(false)); assertThat(materialErrors.firstError(), is("Stage with name 'non-existant' does not exist on pipeline 'upstream', it is being referred to from pipeline 'downstream' (cruise-config.xml)")); }
@Test public void shouldValidateGroupNameWhenPipelineIsBeingCreatedUnderANonExistantGroup() { BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("p1"); PipelineConfig p1 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p1")); String groupName = "%$-with-invalid-characters"; cruiseConfig.addPipeline(groupName, p1); p1.validateTree(PipelineConfigSaveValidationContext.forChain(true, groupName, cruiseConfig, p1)); assertFalse(p1.errors().isEmpty()); assertThat(p1.errors().on(PipelineConfigs.GROUP), contains("Invalid group name '%$-with-invalid-characters'")); }
@Test public void shouldValidateAndUpdatePipelineConfig() { PipelineConfig pipeline = new PipelineConfig(); pipeline.setName("validPipeline"); pipeline.setMaterialConfigs(new MaterialConfigs(MaterialConfigsMother.gitMaterialConfig(), MaterialConfigsMother.svnMaterialConfig())); StageConfig stage1 = getStageConfig("stage1", "s1j1"); StageConfig stage2 = getStageConfig("stage2", "s2j1"); pipeline.getStages().add(stage1); pipeline.getStages().add(stage2); BasicCruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs("group", new Authorization(), pipeline)); boolean isValid = pipeline.validateTree(PipelineConfigSaveValidationContext.forChain(true, cruiseConfig.getGroups().first().getGroup(), cruiseConfig, pipeline)); assertThat(isValid, is(true)); assertThat(pipeline.materialConfigs().errors().isEmpty(), is(true)); assertThat(pipeline.materialConfigs().get(0).errors().isEmpty(), is(true)); assertThat(pipeline.materialConfigs().get(1).errors().isEmpty(), is(true)); assertThat(pipeline.errors().getAll().isEmpty(), is(true)); }
@Test public void shouldValidateTree() { PipelineConfig pipeline = new PipelineConfig(); pipeline.setName("pipeline"); pipeline.addEnvironmentVariable("", ""); pipeline.addParam(new ParamConfig("", "")); pipeline.setMaterialConfigs(new MaterialConfigs(MaterialConfigsMother.gitMaterialConfig(), MaterialConfigsMother.svnMaterialConfig())); StageConfig stage1 = getStageConfig("stage1", "s1j1"); StageConfig stage2 = getStageConfig("stage2", "s2j1"); pipeline.getStages().add(stage1); pipeline.getStages().add(stage2); BasicCruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs("group", new Authorization(), pipeline)); boolean isValid = pipeline.validateTree(PipelineConfigSaveValidationContext.forChain(true, cruiseConfig.getGroups().first().getGroup(), cruiseConfig, pipeline)); assertThat(isValid, is(false)); assertThat(pipeline.getVariables().get(0).errors().firstError(), is("Environment Variable cannot have an empty name for pipeline 'pipeline'.")); assertThat(pipeline.getParams().get(0).errors().firstError(), is("Parameter cannot have an empty name for pipeline 'pipeline'.")); assertThat(pipeline.materialConfigs().errors().isEmpty(), is(true)); assertThat(pipeline.materialConfigs().get(0).errors().isEmpty(), is(true)); assertThat(pipeline.materialConfigs().get(1).errors().isEmpty(), is(true)); assertThat(pipeline.errors().getAll().isEmpty(), is(true)); }
@Test public void shouldDetectCyclicDependencies() { String pipelineName = "p1"; BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines(pipelineName, "p2", "p3"); PipelineConfig p2 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p2")); p2.addMaterialConfig(new DependencyMaterialConfig(new CaseInsensitiveString(pipelineName), new CaseInsensitiveString("stage"))); PipelineConfig p3 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p3")); p3.addMaterialConfig(new DependencyMaterialConfig(new CaseInsensitiveString("p2"), new CaseInsensitiveString("stage"))); PipelineConfig p1 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString(pipelineName)); p1 = new Cloner().deepClone(p1); // Do not remove cloning else it changes the underlying cache object defeating the purpose of the test. p1.addMaterialConfig(new DependencyMaterialConfig(new CaseInsensitiveString("p3"), new CaseInsensitiveString("stage"))); p1.validateTree(PipelineConfigSaveValidationContext.forChain(true, cruiseConfig.getGroups().first().getGroup(), cruiseConfig, p1)); assertThat(p1.materialConfigs().errors().isEmpty(), is(false)); assertThat(p1.materialConfigs().errors().on("base"), is("Circular dependency: p1 <- p2 <- p3 <- p1")); }
@Test public void shouldFailValidationIfAStageIsDeletedWhileItsStillReferredToByADownstreamPipeline() { BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("p1", "p2"); PipelineConfig p1 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p1")); PipelineConfig p2 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p2")); p2.addMaterialConfig(new DependencyMaterialConfig(p1.name(), p1.first().name())); String group = cruiseConfig.getGroups().first().getGroup(); StageConfig stageConfig = new StageConfig(new CaseInsensitiveString("s1"), new JobConfigs(new JobConfig(new CaseInsensitiveString("j1")))); PipelineConfig pipelineConfig = new PipelineConfig(p1.name(), new MaterialConfigs(), stageConfig); cruiseConfig.update(group, pipelineConfig.name().toString(), pipelineConfig); PipelineConfigSaveValidationContext validationContext = PipelineConfigSaveValidationContext.forChain(false, group, cruiseConfig, pipelineConfig); pipelineConfig.validateTree(validationContext); assertThat(pipelineConfig.errors().on("base"), is("Stage with name 'stage' does not exist on pipeline 'p1', it is being referred to from pipeline 'p2' (cruise-config.xml)")); }
@Test public void shouldAddValidationErrorsFromStagesOntoPipelineIfPipelineIsAssociatedToATemplate() { BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("p1", "p2", "p3"); PipelineConfig p1 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p1")); PipelineConfig p2 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p2")); PipelineConfig p3 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p3")); p2.addMaterialConfig(new DependencyMaterialConfig(p1.name(), p1.first().name())); p3.addMaterialConfig(new DependencyMaterialConfig(p2.name(), p2.first().name())); p3.first().getJobs().first().addTask(new FetchTask(new CaseInsensitiveString("p1/p2"), p1.first().name(), p1.first().getJobs().first().name(), "src", "dest")); StageConfig stageConfig = new StageConfig(new CaseInsensitiveString("stage"), new JobConfigs(new JobConfig(new CaseInsensitiveString("new-job")))); PipelineConfig pipelineConfig = new PipelineConfig(p1.name(), new MaterialConfigs(), stageConfig); String group = cruiseConfig.getGroups().first().getGroup(); cruiseConfig.update(group, pipelineConfig.name().toString(), pipelineConfig); PipelineConfigSaveValidationContext validationContext = PipelineConfigSaveValidationContext.forChain(false, group, cruiseConfig, pipelineConfig); pipelineConfig.validateTree(validationContext); assertThat(pipelineConfig.errors().on("base"), is("\"p3 :: stage :: job\" tries to fetch artifact from job \"p1 :: stage :: job\" which does not exist.")); }
@Test public void shouldFailValidationIfAJobIsDeletedWhileItsStillReferredToByADescendentPipelineThroughFetchArtifact() { BasicCruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("p1", "p2", "p3"); PipelineConfig p1 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p1")); PipelineConfig p2 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p2")); PipelineConfig p3 = cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("p3")); p2.addMaterialConfig(new DependencyMaterialConfig(p1.name(), p1.first().name())); JobConfig p2S2J2 = new JobConfig(new CaseInsensitiveString("j2")); p2S2J2.addTask(fetchTaskFromSamePipeline(p2)); p2.add(new StageConfig(new CaseInsensitiveString("stage2"), new JobConfigs(p2S2J2))); p3.addMaterialConfig(new DependencyMaterialConfig(p2.name(), p2.first().name())); p3.first().getJobs().first().addTask(new FetchTask(new CaseInsensitiveString("p1/p2"), p1.first().name(), p1.first().getJobs().first().name(), "src", "dest")); StageConfig stageConfig = new StageConfig(new CaseInsensitiveString("stage"), new JobConfigs(new JobConfig(new CaseInsensitiveString("new-job")))); PipelineConfig pipelineConfig = new PipelineConfig(p1.name(), new MaterialConfigs(), stageConfig); String group = cruiseConfig.getGroups().first().getGroup(); cruiseConfig.update(group, pipelineConfig.name().toString(), pipelineConfig); PipelineConfigSaveValidationContext validationContext = PipelineConfigSaveValidationContext.forChain(false, group, cruiseConfig, pipelineConfig); pipelineConfig.validateTree(validationContext); assertThat(pipelineConfig.errors().on("base"), is("\"p3 :: stage :: job\" tries to fetch artifact from job \"p1 :: stage :: job\" which does not exist.")); }