public boolean validateTree(PipelineConfigSaveValidationContext validationContext) { if (isEmpty()) { errors().add("materials", "A pipeline must have at least one material"); } validate(validationContext); boolean isValid = errors().isEmpty(); for (MaterialConfig materialConfig : this) { isValid = materialConfig.validateTree(validationContext) && isValid; } return isValid; }
@Test public void shouldReturnValidWhenThereIsNoCycle() throws Exception { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipeline1 = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); PipelineConfig pipeline2 = goConfigMother.addPipeline(cruiseConfig, "pipeline2", "stage", "build"); goConfigMother.setDependencyOn(cruiseConfig, pipeline2, "pipeline1", "stage"); pipeline1.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig)); assertThat(pipeline1.materialConfigs().errors().isEmpty(), is(true)); pipeline2.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig)); assertThat(pipeline2.materialConfigs().errors().isEmpty(), is(true)); } @Test
@Test public void shouldReturnTrueWhenNoDependencyDefined() throws Exception { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipelineConfig = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); goConfigMother.addPipeline(cruiseConfig, "pipeline2", "stage", "build"); pipelineConfig.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig)); assertThat(pipelineConfig.materialConfigs().errors().isEmpty(), is(true)); }
@Test public void shouldShowAutoUpdateMismatchErrorTwiceWhenMaterialIsAddedToSamePipeline() throws Exception { HgMaterialConfig materialOne = new HgMaterialConfig("http://url1", null); materialOne.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "some-folder")); materialOne.setAutoUpdate(true); HgMaterialConfig materialTwo = new HgMaterialConfig("http://url1", null); materialTwo.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "some-folder-2")); materialTwo.setAutoUpdate(false); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(materialOne, materialTwo)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(pipelineOne.materialConfigs().get(0).errors().getAll().size(), is(1)); assertThat(pipelineOne.materialConfigs().get(1).errors().getAll().size(), is(1)); }
@Test public void shouldReturnTrueWhenDependencyPipelineDoesNotExist() throws Exception { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipelineConfig = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); goConfigMother.setDependencyOn(cruiseConfig, pipelineConfig, "pipeline2", "stage"); pipelineConfig.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipelineConfig)); assertThat(pipelineConfig.materialConfigs().errors().isEmpty(), is(true)); }
@Test public void shouldNotRunMultipleMaterialsValidationIfPipelineContainsOnlyOneMaterial() { CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); SvnMaterialConfig svnMaterialConfig = MaterialConfigsMother.svnMaterialConfig(); svnMaterialConfig.setFolder(null); pipelineOne.setMaterialConfigs(new MaterialConfigs(svnMaterialConfig)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(svnMaterialConfig.errors().toString(), svnMaterialConfig.errors().getAll().size(), is(0)); }
@Test public void shouldNotFailIfAllScmMaterialsInAPipelineHaveDifferentFolders() { HgMaterialConfig materialOne = new HgMaterialConfig("http://url1", null); materialOne.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder1")); HgMaterialConfig materialTwo = new HgMaterialConfig("http://url2", null); materialTwo.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder2")); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(materialOne, materialTwo)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(pipelineOne.materialConfigs().get(0).errors().isEmpty(), is(true)); assertThat(pipelineOne.materialConfigs().get(1).errors().isEmpty(), is(true)); }
@Test public void shouldNotFailIfMultipleMaterialsHaveUniqueDestinationFolderSet() { HgMaterialConfig materialOne = new HgMaterialConfig("http://url1", null); materialOne.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder")); HgMaterialConfig materialTwo = new HgMaterialConfig("http://url2", null); materialTwo.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder2")); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(materialOne, materialTwo)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(pipelineOne.materialConfigs().get(0).errors().isEmpty(), is(true)); assertThat(pipelineOne.materialConfigs().get(1).errors().isEmpty(), is(true)); }
@Test public void shouldAllowToDependOnPipelineDefinedInFile_WhenInFile() throws Exception { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipeline1 = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); PipelineConfig pipeline2 = goConfigMother.addPipeline(cruiseConfig, "pipeline2", "stage", "build"); goConfigMother.setDependencyOn(cruiseConfig, pipeline2, "pipeline1", "stage"); pipeline1.setOrigin(new FileConfigOrigin()); pipeline2.setOrigin(new FileConfigOrigin()); pipeline1.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipeline1)); assertThat(pipeline1.materialConfigs().errors().isEmpty(), is(true)); pipeline2.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipeline2)); DependencyMaterialConfig dep = pipeline2.materialConfigs().findDependencyMaterial(new CaseInsensitiveString("pipeline1")); assertThat(dep.errors().isEmpty(), is(true)); }
@Test public void shouldNotAllowAnEmptyDepMaterialWhenOtherMaterialsUseThatPipelineName() throws Exception { CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1", "pipeline2", "pipeline3", "go"); SvnMaterialConfig one = new SvnMaterialConfig("svn://abc", "", "", false); one.setName(new CaseInsensitiveString("pipeline2")); DependencyMaterialConfig invalidOne = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline2"), new CaseInsensitiveString("stage")); MaterialConfigs materials = new MaterialConfigs(one, invalidOne); ValidationContext validationContext = ConfigSaveValidationContext.forChain(config); materials.validate(validationContext); assertThat(invalidOne.errors().isEmpty(), is(false)); assertThat(invalidOne.errors().on("materialName"), is("You have defined multiple materials called 'pipeline2'." + " Material names are case-insensitive and must be unique. Note that for dependency materials the default materialName is the name of the upstream pipeline. " + "You can override this by setting the materialName explicitly for the upstream pipeline.")); }
@Test public void shouldNotAllowMultipleDependenciesForTheSamePipelines() throws Exception { CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1", "pipeline2", "pipeline3", "go"); DependencyMaterialConfig dependencyMaterial = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline2"), new CaseInsensitiveString("stage")); DependencyMaterialConfig duplicateDependencyMaterial = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline2"), new CaseInsensitiveString("stage")); MaterialConfigs materialConfigs = new MaterialConfigs(dependencyMaterial, duplicateDependencyMaterial); ValidationContext validationContext = ConfigSaveValidationContext.forChain(config); materialConfigs.validate(validationContext); ConfigErrors errors = duplicateDependencyMaterial.errors(); assertThat(errors.isEmpty(), is(false)); assertThat(errors.on("pipelineStageName"), is("A pipeline can depend on each upstream pipeline only once. Remove one of the occurrences of 'pipeline2' from the current pipeline dependencies.")); }
@Test public void shouldFailIfAllScmMaterialsInAPipelineHaveSameFolders() throws IOException { HgMaterialConfig materialOne = new HgMaterialConfig("http://url1", null); materialOne.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder1")); HgMaterialConfig materialTwo = new HgMaterialConfig("http://url2", null); materialTwo.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder1")); PluggableSCMMaterialConfig materialThree = new PluggableSCMMaterialConfig(null, SCMMother.create("scm-id"), "folder1", null); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(materialOne, materialTwo, materialThree)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); String conflictingDirMessage = "Invalid Destination Directory. Every material needs a different destination directory and the directories should not be nested."; assertThat(pipelineOne.materialConfigs().get(0).errors().on(ScmMaterialConfig.FOLDER), is(conflictingDirMessage)); assertThat(pipelineOne.materialConfigs().get(1).errors().on(ScmMaterialConfig.FOLDER), is(conflictingDirMessage)); assertThat(pipelineOne.materialConfigs().get(2).errors().on(PluggableSCMMaterialConfig.FOLDER), is(conflictingDirMessage)); }
@Test public void shouldFailIfMultipleMaterialsDoNotHaveDestinationFolderSet() { HgMaterialConfig materialConfigOne = new HgMaterialConfig("http://url1", null); materialConfigOne.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder")); HgMaterialConfig materialConfigTwo = new HgMaterialConfig("http://url2", null); PluggableSCMMaterialConfig materialConfigThree = new PluggableSCMMaterialConfig(null, SCMMother.create("scm-id"), null, null); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs((new MaterialConfigs(materialConfigOne, materialConfigTwo, materialConfigThree))); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(pipelineOne.materialConfigs().get(0).errors().isEmpty(), is(true)); assertThat(pipelineOne.materialConfigs().get(1).errors().on(ScmMaterialConfig.FOLDER), is("Destination directory is required when specifying multiple scm materials")); assertThat(pipelineOne.materialConfigs().get(2).errors().on(PluggableSCMMaterialConfig.FOLDER), is("Destination directory is required when specifying multiple scm materials")); }
@Test public void shouldNotAllowMoreThanOneDependencyWithSameName() throws Exception { CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1", "pipeline2", "pipeline3", "go"); DependencyMaterialConfig one = new DependencyMaterialConfig(new CaseInsensitiveString("sameName"), new CaseInsensitiveString("pipeline2"), new CaseInsensitiveString("stage")); DependencyMaterialConfig another = new DependencyMaterialConfig(new CaseInsensitiveString("sameName"), new CaseInsensitiveString("pipeline3"), new CaseInsensitiveString("stage")); MaterialConfigs materialConfigs = new MaterialConfigs(one, another); ValidationContext validationContext = ConfigSaveValidationContext.forChain(config); materialConfigs.validate(validationContext); assertThat(one.errors().isEmpty(), is(false)); assertThat(one.errors().on("materialName"), containsString("You have defined multiple materials called 'sameName'. Material names are case-insensitive and must be unique.")); assertThat(another.errors().isEmpty(), is(false)); assertThat(another.errors().on("materialName"), containsString("You have defined multiple materials called 'sameName'. Material names are case-insensitive and must be unique.")); }
@Test public void shouldNotAllowToDependOnPipelineDefinedInConfigRepository_WhenDownstreamInFile() throws Exception { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipeline1 = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); PipelineConfig pipeline2 = goConfigMother.addPipeline(cruiseConfig, "pipeline2", "stage", "build"); goConfigMother.setDependencyOn(cruiseConfig, pipeline2, "pipeline1", "stage"); pipeline1.setOrigin(new RepoConfigOrigin()); pipeline2.setOrigin(new FileConfigOrigin()); pipeline1.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipeline1)); assertThat(pipeline1.materialConfigs().errors().isEmpty(), is(true)); pipeline2.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipeline2)); DependencyMaterialConfig invalidDependency = pipeline2.materialConfigs().findDependencyMaterial(new CaseInsensitiveString("pipeline1")); assertThat(invalidDependency.errors().isEmpty(), is(false)); assertThat(invalidDependency.errors().on(DependencyMaterialConfig.ORIGIN),startsWith("Dependency from pipeline defined in")); } @Test
@Test public void shouldIgnorePipelineWithEmptyNameInUniquenessCheck() throws Exception { CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1", "pipeline2", "pipeline3", "go"); DependencyMaterialConfig one = new DependencyMaterialConfig(new CaseInsensitiveString(""), new CaseInsensitiveString("pipeline2"), new CaseInsensitiveString("stage")); DependencyMaterialConfig another = new DependencyMaterialConfig(new CaseInsensitiveString(""), new CaseInsensitiveString("pipeline3"), new CaseInsensitiveString("stage")); MaterialConfigs materials = new MaterialConfigs(one, another); ValidationContext validationContext = ConfigSaveValidationContext.forChain(config); materials.validate(validationContext); assertThat(one.errors().isEmpty(), is(true)); assertThat(another.errors().isEmpty(), is(true)); }
@Test public void shouldAllowToDependOnPipelineDefinedInConfigRepository_WhenInConfigRepository() throws Exception { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipeline1 = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); PipelineConfig pipeline2 = goConfigMother.addPipeline(cruiseConfig, "pipeline2", "stage", "build"); goConfigMother.setDependencyOn(cruiseConfig, pipeline2, "pipeline1", "stage"); pipeline1.setOrigin(new RepoConfigOrigin(new ConfigRepoConfig(new SvnMaterialConfig("http://mysvn", false), "myplugin"), "123")); pipeline2.setOrigin(new RepoConfigOrigin(new ConfigRepoConfig(new SvnMaterialConfig("http://othersvn", false), "myplugin"), "2222")); pipeline1.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipeline1)); assertThat(pipeline1.materialConfigs().errors().isEmpty(), is(true)); pipeline2.materialConfigs().validate(ConfigSaveValidationContext.forChain(cruiseConfig, new BasicPipelineConfigs(), pipeline2)); DependencyMaterialConfig dep = pipeline2.materialConfigs().findDependencyMaterial(new CaseInsensitiveString("pipeline1")); assertThat(dep.errors().isEmpty(), is(true)); } @Test
@Test public void shouldNotThrowUpOnMaterialIfAutoUpdateValuesAreCorrect() throws Exception { HgMaterialConfig materialOne = new HgMaterialConfig("http://url1", null); materialOne.setAutoUpdate(true); HgMaterialConfig materialTwo = new HgMaterialConfig("http://url1", null); materialTwo.setAutoUpdate(true); CruiseConfig config = GoConfigMother.configWithPipelines("one", "two", "three"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(materialOne)); PipelineConfig pipelineTwo = config.pipelineConfigByName(new CaseInsensitiveString("two")); pipelineTwo.setMaterialConfigs(new MaterialConfigs(materialTwo)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(pipelineOne.materialConfigs().get(0).errors().isEmpty(), is(true)); assertThat(pipelineTwo.materialConfigs().get(0).errors().isEmpty(), is(true)); }
@Test public void shouldAddErrorOnMaterialIfAutoUpdateDoesNotMatchAcrossFingerPrint() throws Exception { HgMaterialConfig materialOne = new HgMaterialConfig("http://url1", null); materialOne.setAutoUpdate(false); HgMaterialConfig materialTwo = new HgMaterialConfig("http://url1", null); materialTwo.setAutoUpdate(true); CruiseConfig config = GoConfigMother.configWithPipelines("one", "two"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(materialOne)); PipelineConfig pipelineTwo = config.pipelineConfigByName(new CaseInsensitiveString("two")); pipelineTwo.setMaterialConfigs(new MaterialConfigs(materialTwo)); pipelineOne.materialConfigs().validate(ConfigSaveValidationContext.forChain(config)); assertThat(pipelineOne.materialConfigs().get(0).errors().on(ScmMaterialConfig.AUTO_UPDATE), is("Material of type Mercurial (http://url1) is specified more than once in the configuration with different values for the autoUpdate attribute. All copies of this material must have the same value for this attribute.")); }
@Test public void shouldAllowModifyingTheAutoUpdateFieldOfMaterials() throws Exception { GitMaterialConfig gitMaterial = new GitMaterialConfig("https://url", "master"); gitMaterial.setAutoUpdate(true); GitMaterialConfig modifiedGitMaterial = new GitMaterialConfig("https://url", "master"); modifiedGitMaterial.setAutoUpdate(false); MaterialConfigs configs = new MaterialConfigs(); configs.add(gitMaterial); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs(new MaterialConfigs(modifiedGitMaterial)); configs.validate(ConfigSaveValidationContext.forChain(config)); assertTrue(gitMaterial.errors().isEmpty()); }