/* * 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.config.materials; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.materials.dependency.DependencyMaterialConfig; import com.thoughtworks.go.config.materials.git.GitMaterialConfig; import com.thoughtworks.go.config.materials.mercurial.HgMaterialConfig; import com.thoughtworks.go.config.materials.perforce.P4MaterialConfig; import com.thoughtworks.go.config.materials.svn.SvnMaterialConfig; import com.thoughtworks.go.config.materials.tfs.TfsMaterialConfig; import com.thoughtworks.go.config.remote.ConfigRepoConfig; import com.thoughtworks.go.config.remote.FileConfigOrigin; import com.thoughtworks.go.config.remote.RepoConfigOrigin; import com.thoughtworks.go.domain.ConfigErrors; import com.thoughtworks.go.domain.materials.MaterialConfig; import com.thoughtworks.go.domain.packagerepository.PackageDefinitionMother; import com.thoughtworks.go.domain.scm.SCMMother; import com.thoughtworks.go.helper.GoConfigMother; import com.thoughtworks.go.helper.MaterialConfigsMother; import com.thoughtworks.go.security.GoCipher; import com.thoughtworks.go.util.command.UrlArgument; import org.junit.Before; import org.junit.Test; import static com.thoughtworks.go.util.TestUtils.contains; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; public class MaterialConfigsTest { private GoConfigMother goConfigMother; @Before public void setUp() throws Exception { goConfigMother = new GoConfigMother(); } @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.")); } /* Name Pipeline X - Material1 - pipeline1 - Material2 - someSvn - DepMaterial1 - "" dependant on a pipeline named "pipeline1" Above scenario allowed */ @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 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 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 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 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 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 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 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 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 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 shouldReturnNullWhenMaterialNotFoundForTheGivenFingerPrint() { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipeline = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); assertThat(pipeline.materialConfigs().getByFingerPrint("invalid"), is(nullValue())); } @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 shouldAddErrorWhenMatchingScmConfigDoesNotExist(){ PluggableSCMMaterialConfig scmMaterialConfig = new PluggableSCMMaterialConfig(null, SCMMother.create("scm-id"), null, null); PackageMaterialConfig packageMaterialConfig = new PackageMaterialConfig(new CaseInsensitiveString("package-name"), "package-id", PackageDefinitionMother.create("package-id")); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineConfig = config.pipelineConfigByName(new CaseInsensitiveString("one")); MaterialConfigs materialConfigs = new MaterialConfigs(scmMaterialConfig,packageMaterialConfig); pipelineConfig.setMaterialConfigs(materialConfigs); materialConfigs.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", config)); assertThat(pipelineConfig.materialConfigs().get(0).errors().on(scmMaterialConfig.SCM_ID), is("Could not find SCM for given scm-id: [scm-id].")); } @Test public void shouldAddErrorWhenMatchingPackageIDDoesNotExist(){ PackageMaterialConfig packageMaterialConfig = new PackageMaterialConfig(new CaseInsensitiveString("package-name"), "package-id", PackageDefinitionMother.create("package-id")); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineConfig = config.pipelineConfigByName(new CaseInsensitiveString("one")); MaterialConfigs materialConfigs = new MaterialConfigs(packageMaterialConfig); pipelineConfig.setMaterialConfigs(materialConfigs); materialConfigs.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", config)); assertThat(pipelineConfig.materialConfigs().get(0).errors().on(packageMaterialConfig.PACKAGE_ID), is("Could not find repository for given package id:[package-id]")); } @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 shouldCheckSCMMaterialsHaveDestinationCorrectly() { HgMaterialConfig materialConfigOne = new HgMaterialConfig("http://url1", null); materialConfigOne.setConfigAttributes(Collections.singletonMap(ScmMaterialConfig.FOLDER, "folder")); CruiseConfig config = GoConfigMother.configWithPipelines("one"); PipelineConfig pipelineOne = config.pipelineConfigByName(new CaseInsensitiveString("one")); pipelineOne.setMaterialConfigs((new MaterialConfigs(materialConfigOne))); assertThat(pipelineOne.materialConfigs().scmMaterialsHaveDestination(), is(true)); PluggableSCMMaterialConfig materialConfigTwo = new PluggableSCMMaterialConfig(null, SCMMother.create("scm-id"), null, null); pipelineOne.materialConfigs().add(materialConfigTwo); assertThat(pipelineOne.materialConfigs().scmMaterialsHaveDestination(), is(false)); } @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 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 shouldReturnMaterialBasedOnPiplineUniqueFingerPrint() { CruiseConfig cruiseConfig = new BasicCruiseConfig(); PipelineConfig pipeline1 = goConfigMother.addPipeline(cruiseConfig, "pipeline1", "stage", "build"); HgMaterialConfig expectedMaterial = MaterialConfigsMother.hgMaterialConfig(); pipeline1.addMaterialConfig(expectedMaterial); pipeline1.addMaterialConfig(MaterialConfigsMother.gitMaterialConfig("url")); pipeline1.addMaterialConfig(MaterialConfigsMother.svnMaterialConfig("url", "folder")); MaterialConfig actualMaterialConfig = pipeline1.materialConfigs().getByFingerPrint(expectedMaterial.getPipelineUniqueFingerprint()); assertThat(actualMaterialConfig, is(expectedMaterial)); } @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 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()); } @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 shouldSetSvnConfigAttributesForMaterial() { MaterialConfigs materialConfigs = new MaterialConfigs(); Map<String, Object> svnAttrMap = new HashMap<>(); svnAttrMap.put(SvnMaterialConfig.URL, "foo"); svnAttrMap.put(SvnMaterialConfig.USERNAME, "bar"); svnAttrMap.put(SvnMaterialConfig.PASSWORD, "baz"); svnAttrMap.put(SvnMaterialConfig.CHECK_EXTERNALS, false); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, SvnMaterialConfig.TYPE); attributeMap.put(SvnMaterialConfig.TYPE, svnAttrMap); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.first(), is(new SvnMaterialConfig("foo", "bar", "baz", false))); } @Test public void shouldSetTfsConfigAttributesForMaterial() { MaterialConfigs materialConfigs = new MaterialConfigs(); Map<String, String> tfsAttrMap = new HashMap<>(); tfsAttrMap.put(TfsMaterialConfig.URL, "foo"); tfsAttrMap.put(TfsMaterialConfig.USERNAME, "bar"); tfsAttrMap.put(TfsMaterialConfig.PASSWORD, "baz"); tfsAttrMap.put(TfsMaterialConfig.PROJECT_PATH, "to_hell"); tfsAttrMap.put(TfsMaterialConfig.MATERIAL_NAME, "crapy_material"); tfsAttrMap.put(TfsMaterialConfig.DOMAIN, "CORPORATE"); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, TfsMaterialConfig.TYPE); attributeMap.put(TfsMaterialConfig.TYPE, tfsAttrMap); materialConfigs.setConfigAttributes(attributeMap); TfsMaterialConfig tfsMaterialConfig = new TfsMaterialConfig(new GoCipher(), new UrlArgument("foo"), "bar", "CORPORATE", "baz", "to_hell"); tfsMaterialConfig.setName(new CaseInsensitiveString("crapy_material")); assertThat(materialConfigs.first(), is(tfsMaterialConfig)); assertThat(tfsMaterialConfig.getPassword(), is("baz")); } @Test public void shouldClearExistingAndSetHgConfigAttributesForMaterial() { MaterialConfigs materialConfigs = new MaterialConfigs(); materialConfigs.add(new HgMaterialConfig("", null)); materialConfigs.add(new SvnMaterialConfig("", "", "", false)); Map<String, String> hashMap = new HashMap<>(); hashMap.put(HgMaterialConfig.URL, "foo"); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, HgMaterialConfig.TYPE); attributeMap.put(HgMaterialConfig.TYPE, hashMap); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.size(), is(1)); assertThat(materialConfigs.first(), is(new HgMaterialConfig("foo", null))); } @Test public void shouldSetGitConfigAttributesForMaterial() { MaterialConfigs materialConfigs = new MaterialConfigs(); Map<String, String> hashMap = new HashMap<>(); hashMap.put(GitMaterialConfig.URL, "foo"); hashMap.put(GitMaterialConfig.BRANCH, "master"); HashMap<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, GitMaterialConfig.TYPE); attributeMap.put(GitMaterialConfig.TYPE, hashMap); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.size(), is(1)); GitMaterialConfig expected = new GitMaterialConfig("foo"); expected.setConfigAttributes(Collections.singletonMap(GitMaterialConfig.BRANCH, "master")); assertThat(materialConfigs.first(), is(expected)); } @Test public void shouldSetP4ConfigAttributesForMaterial() { MaterialConfigs materialConfigs = new MaterialConfigs(); Map<String, String> hashMap = new HashMap<>(); hashMap.put(P4MaterialConfig.SERVER_AND_PORT, "localhost:1666"); hashMap.put(P4MaterialConfig.USERNAME, "username"); hashMap.put(P4MaterialConfig.PASSWORD, "password"); hashMap.put(P4MaterialConfig.VIEW, "foo"); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, P4MaterialConfig.TYPE); attributeMap.put(P4MaterialConfig.TYPE, hashMap); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.size(), is(1)); P4MaterialConfig expected = new P4MaterialConfig("localhost:1666", "foo", "username"); expected.setPassword("password"); assertThat(materialConfigs.first(), is(expected)); } @Test public void shouldSetDependencyMaterialConfigAttributesForMaterial() { MaterialConfigs materialConfigs = new MaterialConfigs(); Map<String, String> hashMap = new HashMap<>(); hashMap.put(DependencyMaterialConfig.PIPELINE_STAGE_NAME, "blah [foo]"); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, DependencyMaterialConfig.TYPE); attributeMap.put(DependencyMaterialConfig.TYPE, hashMap); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.size(), is(1)); DependencyMaterialConfig expected = new DependencyMaterialConfig(new CaseInsensitiveString("blah"), new CaseInsensitiveString("foo")); assertThat(materialConfigs.first(), is(expected)); } @Test public void shouldSetPackageMaterialConfigAttributesForMaterial() { Map<String, String> hashMap = new HashMap<>(); String packageId = "some-id"; hashMap.put(PackageMaterialConfig.PACKAGE_ID, packageId); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, PackageMaterialConfig.TYPE); attributeMap.put(PackageMaterialConfig.TYPE, hashMap); MaterialConfigs materialConfigs = new MaterialConfigs(); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.size(), is(1)); assertThat(((PackageMaterialConfig) materialConfigs.first()).getPackageId(), is(packageId)); } @Test public void shouldGetExistingOrDefaultMaterialCorrectly() { SvnMaterialConfig svn = new SvnMaterialConfig("http://test.com", false); PackageMaterialConfig p1 = new PackageMaterialConfig("p1"); PackageMaterialConfig p2 = new PackageMaterialConfig("p2"); assertThat(new MaterialConfigs(svn, p2).getExistingOrDefaultMaterial(p1).getPackageId(), is("p2")); assertThat(new MaterialConfigs(svn).getExistingOrDefaultMaterial(p1).getPackageId(), is("p1")); } @Test public void shouldSetPluggableSCMMaterialConfigAttributesForMaterial() { String scmId = "scm-id"; Map<String, String> hashMap = new HashMap<>(); hashMap.put(PluggableSCMMaterialConfig.SCM_ID, scmId); Map<String, Object> attributeMap = new HashMap<>(); attributeMap.put(AbstractMaterialConfig.MATERIAL_TYPE, PluggableSCMMaterialConfig.TYPE); attributeMap.put(PluggableSCMMaterialConfig.TYPE, hashMap); MaterialConfigs materialConfigs = new MaterialConfigs(); materialConfigs.setConfigAttributes(attributeMap); assertThat(materialConfigs.size(), is(1)); assertThat(((PluggableSCMMaterialConfig) materialConfigs.first()).getScmId(), is(scmId)); } @Test public void shouldGetExistingOrDefaultPluggableSCMMaterialCorrectly() { SvnMaterialConfig svn = new SvnMaterialConfig("http://test.com", false); PluggableSCMMaterialConfig pluggableSCMMaterialOne = new PluggableSCMMaterialConfig("scm-id-1"); PluggableSCMMaterialConfig pluggableSCMMaterialTwo = new PluggableSCMMaterialConfig("scm-id-2"); assertThat(new MaterialConfigs(svn, pluggableSCMMaterialTwo).getExistingOrDefaultMaterial(pluggableSCMMaterialOne).getScmId(), is("scm-id-2")); assertThat(new MaterialConfigs(svn).getExistingOrDefaultMaterial(pluggableSCMMaterialOne).getScmId(), is("scm-id-1")); } @Test public void shouldValidateTree(){ GitMaterialConfig git = new GitMaterialConfig(); git.setName(new CaseInsensitiveString("mat-name")); SvnMaterialConfig svn = new SvnMaterialConfig("url", true); svn.setName(new CaseInsensitiveString("mat-name")); P4MaterialConfig p4 = new P4MaterialConfig(); TfsMaterialConfig tfs = new TfsMaterialConfig(); HgMaterialConfig hg = new HgMaterialConfig(); MaterialConfigs materialConfigs = new MaterialConfigs(git, svn, p4, tfs, hg); PipelineConfig pipelineConfig = new PipelineConfig(new CaseInsensitiveString("p1"), new MaterialConfigs(svn)); materialConfigs.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new BasicCruiseConfig(new BasicPipelineConfigs(pipelineConfig)), pipelineConfig)); assertThat(git.errors().on(GitMaterialConfig.MATERIAL_NAME), contains("You have defined multiple materials called 'mat-name'")); assertThat(git.errors().on(GitMaterialConfig.URL), is("URL cannot be blank")); assertThat(svn.errors().on(SvnMaterialConfig.MATERIAL_NAME), contains("You have defined multiple materials called 'mat-name'")); assertThat(p4.errors().on(P4MaterialConfig.VIEW), contains("P4 view cannot be empty.")); assertThat(tfs.errors().on(TfsMaterialConfig.URL), contains("URL cannot be blank")); assertThat(hg.errors().on(HgMaterialConfig.URL), is("URL cannot be blank")); } @Test public void shouldFailValidationInNoMaterialPresent(){ MaterialConfigs materialConfigs = new MaterialConfigs(); assertThat(materialConfigs.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", new PipelineConfig())), is(false)); assertThat(materialConfigs.errors().firstError(), is("A pipeline must have at least one material")); } @Test public void shouldTellWhetherItHasDependencyOnSpecifiedPipeline() 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"); assertTrue(pipeline2.materialConfigs().hasDependencyMaterial(pipeline1)); assertFalse(pipeline1.materialConfigs().hasDependencyMaterial(pipeline2)); } }