/*
* 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.serialization;
import com.thoughtworks.go.config.*;
import com.thoughtworks.go.config.materials.AbstractMaterialConfig;
import com.thoughtworks.go.config.materials.MaterialConfigs;
import com.thoughtworks.go.config.materials.dependency.DependencyMaterialConfig;
import com.thoughtworks.go.config.materials.perforce.P4MaterialConfig;
import com.thoughtworks.go.config.remote.FileConfigOrigin;
import com.thoughtworks.go.domain.ConfigErrors;
import com.thoughtworks.go.domain.materials.dependency.NewGoConfigMother;
import com.thoughtworks.go.helper.GoConfigMother;
import com.thoughtworks.go.util.ConfigElementImplementationRegistryMother;
import com.thoughtworks.go.util.FileUtil;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
public class DependencyMaterialConfigTest {
private MagicalGoConfigXmlWriter writer;
private MagicalGoConfigXmlLoader loader;
private CruiseConfig config;
private PipelineConfig pipelineConfig;
@Before
public void setUp() throws Exception {
writer = new MagicalGoConfigXmlWriter(new ConfigCache(), ConfigElementImplementationRegistryMother.withNoPlugins());
loader = new MagicalGoConfigXmlLoader(new ConfigCache(), ConfigElementImplementationRegistryMother.withNoPlugins());
config = GoConfigMother.configWithPipelines("pipeline1", "pipeline2", "pipeline3", "go");
pipelineConfig = config.getAllPipelineConfigs().get(0);
}
@Test
public void shouldBeAbleToLoadADependencyMaterialFromConfig() throws Exception {
String xml = "<pipeline pipelineName=\"pipeline-name\" stageName=\"stage-name\" />";
DependencyMaterialConfig material = loader.fromXmlPartial(xml, DependencyMaterialConfig.class);
assertThat(material.getPipelineName(), is(new CaseInsensitiveString("pipeline-name")));
assertThat(material.getStageName(), is(new CaseInsensitiveString("stage-name")));
assertThat(writer.toXmlPartial(material), is(xml));
}
@Test
public void shouldBeAbleToSaveADependencyMaterialToConfig() throws Exception {
DependencyMaterialConfig originalMaterial = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name"));
NewGoConfigMother mother = new NewGoConfigMother();
mother.addPipeline("pipeline-name", "stage-name", "job-name");
mother.addPipeline("dependent", "stage-name", "job-name").addMaterialConfig(originalMaterial);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.write(mother.cruiseConfig(), buffer, false);
final ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer.toByteArray());
CruiseConfig config = loader.loadConfigHolder(FileUtil.readToEnd(inputStream)).config;
DependencyMaterialConfig material = (DependencyMaterialConfig) config.pipelineConfigByName(new CaseInsensitiveString("dependent")).materialConfigs().get(1);
assertThat(material, is(originalMaterial));
assertThat(material.getPipelineName(), is(new CaseInsensitiveString("pipeline-name")));
assertThat(material.getStageName(), is(new CaseInsensitiveString("stage-name")));
}
@Test
public void shouldBeAbleToHaveADependencyAndOneOtherMaterial() throws Exception {
NewGoConfigMother mother = new NewGoConfigMother();
mother.addPipeline("pipeline-name", "stage-name", "job-name");
PipelineConfig pipelineConfig = mother.addPipeline("dependent", "stage-name", "job-name",
new DependencyMaterialConfig(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")));
pipelineConfig.addMaterialConfig(new P4MaterialConfig("localhost:1666", "foo"));
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
CruiseConfig cruiseConfig = mother.cruiseConfig();
writer.write(cruiseConfig, buffer, false);
final ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer.toByteArray());
CruiseConfig config = loader.loadConfigHolder(FileUtil.readToEnd(inputStream)).config;
MaterialConfigs materialConfigs = config.pipelineConfigByName(new CaseInsensitiveString("dependent")).materialConfigs();
assertThat(materialConfigs.get(0), is(instanceOf(DependencyMaterialConfig.class)));
assertThat(materialConfigs.get(1), is(instanceOf(P4MaterialConfig.class)));
}
@Test
public void shouldAddErrorForInvalidMaterialName() {
DependencyMaterialConfig materialConfig = new DependencyMaterialConfig(new CaseInsensitiveString("wrong name"), new CaseInsensitiveString("pipeline-foo"), new CaseInsensitiveString("stage-bar"));
materialConfig.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig(), pipelineConfig));
assertThat(materialConfig.errors().on(AbstractMaterialConfig.MATERIAL_NAME), is("Invalid material name 'wrong name'. This must be alphanumeric and can contain underscores and periods (however, it cannot start with a period). The maximum allowed length is 255 characters."));
}
@Test
public void shouldAddErrorWhenInvalidPipelineNameStage() {
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig();
Map<String, String> configMap = new HashMap<>();
configMap.put(DependencyMaterialConfig.PIPELINE_STAGE_NAME, "invalid pipeline stage");
dependencyMaterialConfig.setConfigAttributes(configMap);
assertThat(dependencyMaterialConfig.getPipelineStageName(), is("invalid pipeline stage"));
assertThat(dependencyMaterialConfig.errors().isEmpty(), is(false));
assertThat(dependencyMaterialConfig.errors().on(DependencyMaterialConfig.PIPELINE_STAGE_NAME), is("'invalid pipeline stage' should conform to the pattern 'pipeline [stage]'"));
}
@Test
public void shouldNotBombValidationWhenMaterialNameIsNotSet() {
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline-foo"), new CaseInsensitiveString("stage-bar"));
dependencyMaterialConfig.validate(ConfigSaveValidationContext.forChain(new BasicCruiseConfig(), pipelineConfig));
assertThat(dependencyMaterialConfig.errors().on(AbstractMaterialConfig.MATERIAL_NAME), is(nullValue()));
}
@Test
public void shouldNOTBeValidIfThePipelineExistsButTheStageDoesNot() throws Exception {
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline2"), new CaseInsensitiveString("stage-not-existing does not exist!"));
dependencyMaterialConfig.validate(ConfigSaveValidationContext.forChain(config, pipelineConfig));
ConfigErrors configErrors = dependencyMaterialConfig.errors();
assertThat(configErrors.isEmpty(), is(false));
assertThat(configErrors.on(DependencyMaterialConfig.PIPELINE_STAGE_NAME), containsString("Stage with name 'stage-not-existing does not exist!' does not exist on pipeline 'pipeline2'"));
}
@Test
public void shouldNOTBeValidIfTheReferencedPipelineDoesNotExist() throws Exception {
CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1", "pipeline2", "pipeline3", "go");
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig(new CaseInsensitiveString("pipeline-not-exist"), new CaseInsensitiveString("stage"));
dependencyMaterialConfig.validate(ConfigSaveValidationContext.forChain(config, pipelineConfig));
ConfigErrors configErrors = dependencyMaterialConfig.errors();
assertThat(configErrors.isEmpty(), is(false));
assertThat(configErrors.on(DependencyMaterialConfig.PIPELINE_STAGE_NAME), containsString("Pipeline with name 'pipeline-not-exist' does not exist"));
}
@Test
public void setConfigAttributes_shouldPopulateFromConfigAttributes() {
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig(new CaseInsensitiveString(""), new CaseInsensitiveString(""));
assertThat(dependencyMaterialConfig.getPipelineStageName(), is(nullValue()));
HashMap<String, String> configMap = new HashMap<>();
configMap.put(AbstractMaterialConfig.MATERIAL_NAME, "name1");
configMap.put(DependencyMaterialConfig.PIPELINE_STAGE_NAME, "pipeline-1 [stage-1]");
dependencyMaterialConfig.setConfigAttributes(configMap);
assertThat(dependencyMaterialConfig.getMaterialName(), is(new CaseInsensitiveString("name1")));
assertThat(dependencyMaterialConfig.getPipelineName(), is(new CaseInsensitiveString("pipeline-1")));
assertThat(dependencyMaterialConfig.getStageName(), is(new CaseInsensitiveString("stage-1")));
assertThat(dependencyMaterialConfig.getPipelineStageName(), is("pipeline-1 [stage-1]"));
}
@Test
public void setConfigAttributes_shouldNotPopulateNameFromConfigAttributesIfNameIsEmptyOrNull() {
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig(new CaseInsensitiveString("name2"), new CaseInsensitiveString("pipeline"), new CaseInsensitiveString("stage"));
HashMap<String, String> configMap = new HashMap<>();
configMap.put(AbstractMaterialConfig.MATERIAL_NAME, "");
dependencyMaterialConfig.setConfigAttributes(configMap);
assertThat(dependencyMaterialConfig.getMaterialName(), is(nullValue()));
}
@Test
public void shouldValidateTree(){
DependencyMaterialConfig dependencyMaterialConfig = new DependencyMaterialConfig(new CaseInsensitiveString("upstream_stage"), new CaseInsensitiveString("upstream_pipeline"), new CaseInsensitiveString("stage"));
PipelineConfig pipeline = new PipelineConfig(new CaseInsensitiveString("p"), new MaterialConfigs());
pipeline.setOrigin(new FileConfigOrigin());
dependencyMaterialConfig.validateTree(PipelineConfigSaveValidationContext.forChain(true, "group", config, pipeline));
assertThat(dependencyMaterialConfig.errors().on(DependencyMaterialConfig.PIPELINE_STAGE_NAME), is("Pipeline with name 'upstream_pipeline' does not exist, it is defined as a dependency for pipeline 'p' (cruise-config.xml)"));
}
}