/*
* Copyright 2016 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;
import com.thoughtworks.go.config.exceptions.GoConfigInvalidException;
import com.thoughtworks.go.config.materials.MaterialConfigs;
import com.thoughtworks.go.config.materials.PackageMaterialConfig;
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.PartialConfig;
import com.thoughtworks.go.config.remote.RepoConfigOrigin;
import com.thoughtworks.go.config.server.security.ldap.BaseConfig;
import com.thoughtworks.go.config.server.security.ldap.BasesConfig;
import com.thoughtworks.go.domain.RunIfConfigs;
import com.thoughtworks.go.domain.config.*;
import com.thoughtworks.go.domain.packagerepository.PackageDefinition;
import com.thoughtworks.go.domain.packagerepository.PackageRepositories;
import com.thoughtworks.go.domain.packagerepository.PackageRepository;
import com.thoughtworks.go.domain.packagerepository.Packages;
import com.thoughtworks.go.helper.ConfigFileFixture;
import com.thoughtworks.go.helper.GoConfigMother;
import com.thoughtworks.go.helper.PartialConfigMother;
import com.thoughtworks.go.helper.PipelineConfigMother;
import com.thoughtworks.go.security.CipherProviderHelper;
import com.thoughtworks.go.security.GoCipher;
import com.thoughtworks.go.util.*;
import com.thoughtworks.go.util.command.UrlArgument;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.hamcrest.core.Is;
import org.jdom2.input.JDOMParseException;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import static com.thoughtworks.go.util.DataStructureUtils.m;
import static com.thoughtworks.go.util.GoConstants.CONFIG_SCHEMA_VERSION;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class MagicalGoConfigXmlWriterTest {
private ByteArrayOutputStream output;
private MagicalGoConfigXmlWriter xmlWriter;
public SystemEnvironment systemEnvironment;
private MagicalGoConfigXmlLoader xmlLoader;
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setup() {
output = new ByteArrayOutputStream();
ConfigCache configCache = new ConfigCache();
xmlWriter = new MagicalGoConfigXmlWriter(configCache, ConfigElementImplementationRegistryMother.withNoPlugins());
xmlLoader = new MagicalGoConfigXmlLoader(configCache, ConfigElementImplementationRegistryMother.withNoPlugins());
}
@Test
public void shouldBeAbleToAssociateMingleConfigWithAPipeline() throws Exception {
CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1");
config.setServerConfig(new ServerConfig("foo", new SecurityConfig()));
config.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).setMingleConfig(new MingleConfig("https://foo.bar/baz", "go-upstream", "foo = bar"));
output = new ByteArrayOutputStream();
xmlWriter.write(config, output, false);
assertThat(output.toString().replaceAll(">\\s+<", "><"),
containsString("<mingle baseUrl=\"https://foo.bar/baz\" projectIdentifier=\"go-upstream\"><mqlGroupingConditions>foo = bar</mqlGroupingConditions></mingle>"));
config.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).setMingleConfig(new MingleConfig("https://foo.bar/baz", "go-upstream"));
output = new ByteArrayOutputStream();
xmlWriter.write(config, output, false);
assertThat(output.toString().replaceAll(">\\s+<", "><"), containsString("<mingle baseUrl=\"https://foo.bar/baz\" projectIdentifier=\"go-upstream\" />"));
config.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).setMingleConfig(new MingleConfig("https://foo.bar/baz", "go-upstream", ""));
output = new ByteArrayOutputStream();
xmlWriter.write(config, output, false);
assertThat(output.toString().replaceAll(">\\s+<", "><"), containsString("<mingle baseUrl=\"https://foo.bar/baz\" projectIdentifier=\"go-upstream\"><mqlGroupingConditions /></mingle>"));
}
@Test
public void shouldBeAbleToExplicitlyLockAPipeline() throws Exception {
CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1");
config.setServerConfig(new ServerConfig("foo", new SecurityConfig()));
config.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).lockExplicitly();
xmlWriter.write(config, output, false);
assertThat(output.toString(), containsString("isLocked=\"true"));
}
@Test
public void shouldBeAbleToExplicitlyUnlockAPipeline() throws Exception {
CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1");
config.setServerConfig(new ServerConfig("foo", new SecurityConfig()));
config.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).unlockExplicitly();
xmlWriter.write(config, output, false);
assertThat(output.toString(), containsString("isLocked=\"false"));
}
@Test
public void shouldBeAbleToRemoveAnExplicitLockOnAPipeline() throws Exception {
CruiseConfig config = GoConfigMother.configWithPipelines("pipeline1");
config.setServerConfig(new ServerConfig("foo", new SecurityConfig()));
config.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).removeExplicitLocks();
xmlWriter.write(config, output, false);
assertThat(output.toString(), not(containsString("isLocked=")));
}
@Test
public void shouldWriteServerConfig() throws Exception {
String xml = ConfigFileFixture.SERVER_WITH_ARTIFACTS_DIR;
CruiseConfig cruiseConfig = xmlLoader.loadConfigHolder(FileUtil.readToEnd(IOUtils.toInputStream(xml))).config;
xmlWriter.write(cruiseConfig, output, false);
assertXmlEquals(xml, output.toString());
}
@Test
public void shouldThrowInvalidConfigWhenAttemptedToSaveMergedConfig() throws Exception {
String xml = ConfigFileFixture.TWO_PIPELINES;
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml)).config;
PartialConfig remotePart = PartialConfigMother.withPipeline("some-pipe");
remotePart.setOrigin(new RepoConfigOrigin());
BasicCruiseConfig merged = new BasicCruiseConfig((BasicCruiseConfig)cruiseConfig,remotePart);
try {
xmlWriter.write(merged, output, true);
}
catch(GoConfigInvalidException ex) {
// ok
assertThat(ex.getMessage(),is("Attempted to save merged configuration with patials"));
return;
}
fail("should have thrown when saving merged configuration");
}
@Test
public void shouldWritePipelines() throws Exception {
String xml = ConfigFileFixture.TWO_PIPELINES;
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml)).config;
xmlWriter.write(cruiseConfig, output, false);
assertXmlEquals(xml, output.toString());
}
@Test
public void shouldNotWriteDuplicatedPipelines() throws Exception {
String xml = ConfigFileFixture.TWO_PIPELINES;
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml)).config;
cruiseConfig.addPipeline("someGroup", PipelineConfigMother.pipelineConfig("pipeline1"));
try {
xmlWriter.write(cruiseConfig, output, false);
fail("Should not be able to save config when there are 2 pipelines with same name");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("You have defined multiple pipelines named 'pipeline1'. Pipeline names must be unique. Source(s): [cruise-config.xml]"));
}
}
@Test
public void shouldNotDeleteServerTag() throws Exception {
CruiseConfig config = ConfigMigrator.load(ConfigFileFixture.SERVER_TAG_WITH_DEFAULTS_PLUS_LICENSE_TAG);
xmlWriter.write(config, output, false);
assertThat(output.toString(), containsString("<server"));
}
@Test
public void shouldWriteConfigRepos() throws Exception {
CruiseConfig config = GoConfigMother.configWithConfigRepo();
xmlWriter.write(config, output, false);
assertThat(output.toString(), containsString("<config-repo plugin=\"myplugin\">"));
assertThat(output.toString(), containsString("<git url=\"https://github.com/tomzo/gocd-indep-config-part.git\" />"));
}
@Test
public void shouldNotWriteDependenciesIfEmptyDependencies() throws Exception {
String xml = ConfigFileFixture.EMPTY_DEPENDENCIES;
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml)).config;
xmlWriter.write(cruiseConfig, output, false);
assertThat(output.toString().replaceAll(">\\s+<", ""), not(containsString("dependencies")));
}
@Test
public void shouldNotWriteWhenEnvironmentNameIsNotSet() throws Exception {
String xml = ConfigFileFixture.CONFIG_WITH_NANT_AND_EXEC_BUILDER;
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml)).config;
cruiseConfig.addEnvironment(new BasicEnvironmentConfig());
try {
xmlWriter.write(cruiseConfig, output, false);
fail("Should not be able to save config when the environment name is not set");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("\"Name\" is required for Environment"));
}
}
@Test
public void shouldValidateThatEnvironmentsAreSameEvenNamesAreOfDifferentCase() throws Exception {
String xml = ConfigFileFixture.WITH_DUPLICATE_ENVIRONMENTS;
try {
ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml));
fail("Should not be able to save config when 2 environments have the same name with different case");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Environment with name 'FOO' already exists."));
}
}
@Test
public void shouldWriteConfigWithTemplates() throws Exception {
String content = "<cruise schemaVersion='" + CONFIG_SCHEMA_VERSION + "'>\n"
+ "<server artifactsdir='artifactsDir' >"
+ "</server>"
+ "<pipelines>\n"
+ "<pipeline name='pipeline1' template='abc'>\n"
+ " <materials>\n"
+ " <svn url =\"svnurl\"/>"
+ " </materials>\n"
+ "</pipeline>\n"
+ "<pipeline name='pipeline2'>\n"
+ " <materials>\n"
+ " <pipeline pipelineName='pipeline1' stageName='stage1'/>"
+ " </materials>\n"
+ " <stage name='badstage'>"
+ " <jobs>"
+ " <job name='job1' />"
+ " </jobs>"
+ " </stage>"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "<templates>\n"
+ " <pipeline name='abc'>\n"
+ " <stage name='stage1'>"
+ " <jobs>"
+ " <job name='job1' />"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>\n"
+ "</templates>\n"
+ "</cruise>";
CruiseConfig config = ConfigMigrator.loadWithMigration(content).configForEdit;
xmlWriter.write(config, output, false);
assertThat(output.toString().replaceAll("\\s+", " "), containsString(
"<pipeline name=\"pipeline1\" template=\"abc\">"
+ " <materials>"
+ " <svn url=\"svnurl\" />"
+ " </materials>"
+ " </pipeline>"));
}
@Test
public void shouldWriteObjectToXmlPartial() throws Exception {
String xml = ConfigFileFixture.ONE_PIPELINE;
CruiseConfig cruiseConfig = ConfigMigrator.load(xml);
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1"));
StageConfig stageConfig = pipelineConfig.findBy(new CaseInsensitiveString("stage"));
JobConfig build = stageConfig.jobConfigByInstanceName("functional", true);
assertThat(xmlWriter.toXmlPartial(pipelineConfig), is(
"<pipeline name=\"pipeline1\">\n"
+ " <materials>\n"
+ " <svn url=\"foobar\" checkexternals=\"true\" />\n"
+ " </materials>\n"
+ " <stage name=\"stage\">\n"
+ " <jobs>\n"
+ " <job name=\"functional\">\n"
+ " <artifacts>\n"
+ " <artifact src=\"artifact1.xml\" dest=\"cruise-output\" />\n"
+ " </artifacts>\n"
+ " </job>\n"
+ " </jobs>\n"
+ " </stage>\n"
+ "</pipeline>"
));
assertThat(xmlWriter.toXmlPartial(stageConfig), is(
"<stage name=\"stage\">\n"
+ " <jobs>\n"
+ " <job name=\"functional\">\n"
+ " <artifacts>\n"
+ " <artifact src=\"artifact1.xml\" dest=\"cruise-output\" />\n"
+ " </artifacts>\n"
+ " </job>\n"
+ " </jobs>\n"
+ "</stage>"
));
assertThat(xmlWriter.toXmlPartial(build), is(
"<job name=\"functional\">\n"
+ " <artifacts>\n"
+ " <artifact src=\"artifact1.xml\" dest=\"cruise-output\" />\n"
+ " </artifacts>\n"
+ "</job>"
));
}
@Test
public void shouldWriteEmptyOnCancelTaskWhenDefined() throws Exception {
String partial = "<job name=\"functional\">\n"
+ " <tasks>\n"
+ " <exec command=\"echo\">\n"
+ " <oncancel />\n"
+ " </exec>\n"
+ " </tasks>\n"
+ "</job>";
JobConfig jobConfig = xmlLoader.fromXmlPartial(partial, JobConfig.class);
assertThat(xmlWriter.toXmlPartial(jobConfig), is(partial));
}
@Test
public void shouldNotWriteMoreThanOneOnCancelTaskWhenDefined() throws Exception {
String xml = "<cruise schemaVersion='76'>\n"
+ "<server artifactsdir='artifactsDir' >"
+ "</server>"
+ "<pipelines>\n"
+ "<pipeline name='pipeline1' template='abc'>\n"
+ " <materials>\n"
+ " <svn url ='svnurl' username='foo' password='password'/>"
+ " </materials>\n"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "<templates>\n"
+ " <pipeline name='abc'>\n"
+ " <stage name='stage1'>"
+ " <jobs>"
+ " <job name='job1'>"
+ " <tasks>"
+ " <exec command=\"rake\">\n"
+ " <arg>all_test</arg>\n"
+ " <oncancel>\n"
+ " <ant target='kill' />\n"
+ " <ant target='kill' />\n"
+ " </oncancel>\n"
+ " </exec>"
+ " </tasks>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>\n"
+ "</templates>\n"
+ "</cruise>";
thrown.expectMessage("Invalid content was found starting with element 'ant'. No child element is expected at this point.");
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(IOUtils.toInputStream(xml)).config;
xmlWriter.write(cruiseConfig, output, false);
}
@Test
public void shouldBeAValidXSD() throws Exception {
SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
factory.newSchema(new StreamSource(getClass().getResourceAsStream("/cruise-config.xsd")));
}
@Test
public void shouldFailWhenWritingObjectToXmlPartialWithNoConfigTag() throws Exception {
Object badObject = "foo";
try {
xmlWriter.toXmlPartial(badObject);
fail("Should not be able to write a non ConfigTag enabled object");
} catch (RuntimeException expected) {
assertThat(expected.getMessage(), is("Object " + badObject + " does not have a ConfigTag"));
}
}
@Test
public void shouldNotSaveUserNameAndPasswordWhenBothAreEmpty() throws Exception {
MailHost mailHost = new MailHost("hostname", 24, "", "", null, true, false, "from@te.com", "to@te.com", new GoCipher());
mailHost.ensureEncrypted();
String s = xmlWriter.toXmlPartial(mailHost);
assertThat(s, is(
"<mailhost hostname=\"hostname\" port=\"24\" tls=\"false\" "
+ "from=\"from@te.com\" admin=\"to@te.com\" />"));
}
@Test
public void shouldEncryptPasswordBeforeWriting() throws Exception {
CipherProviderHelper.clearCachedCipher();
File cipherFile = new SystemEnvironment().getCipherFile();
FileUtils.deleteQuietly(cipherFile);
FileUtils.writeStringToFile(cipherFile, "269298bc31c44620");
String content = "<cruise schemaVersion='" + CONFIG_SCHEMA_VERSION + "'>\n"
+ "<server artifactsdir='artifactsDir' >"
+ "<mailhost hostname=\"10.18.3.171\" port=\"25\" username=\"cruise2\" password=\"password\" tls=\"false\" from=\"cruise2@cruise.com\" admin=\"ps@somewhere.com\" />"
+ "<security>"
+ "<ldap uri=\"ldap://blah.blah.somewhere.com\" managerDn=\"cn=Active Directory Ldap User,ou=SomeSystems,ou=Accounts,ou=Principal,dc=corp,dc=somecompany,dc=com\" "
+ "managerPassword=\"password\" searchFilter=\"(sAMAccountName={0})\">"
+ "<bases><base value=\"ou=Employees,ou=Company,ou=Principal,dc=corp,dc=somecompany,dc=com\"/></bases>"
+ "</ldap>"
+ "</security>"
+ "</server>"
+ "<pipelines>\n"
+ "<pipeline name='pipeline1' template='abc'>\n"
+ " <materials>\n"
+ " <svn url ='svnurl' username='foo' password='password'/>"
+ " </materials>\n"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "<templates>\n"
+ " <pipeline name='abc'>\n"
+ " <stage name='stage1'>"
+ " <jobs>"
+ " <job name='job1' />"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>\n"
+ "</templates>\n"
+ "</cruise>";
CruiseConfig config = ConfigMigrator.loadWithMigration(content).configForEdit;
xmlWriter.write(config, output, false);
assertThat(output.toString().replaceAll("\\s+", " "), containsString(
"<svn url=\"svnurl\" username=\"foo\" encryptedPassword=\"pVyuW5ny9I6YT4Ou+KLZhQ==\" />"));
assertThat(output.toString().replaceAll("\\s+", " "), containsString(
"<mailhost hostname=\"10.18.3.171\" port=\"25\" username=\"cruise2\" encryptedPassword=\"pVyuW5ny9I6YT4Ou+KLZhQ==\" tls=\"false\" from=\"cruise2@cruise.com\" admin=\"ps@somewhere.com\" />"));
String expectedLdapConfig = "<ldap uri=\"ldap://blah.blah.somewhere.com\" managerDn=\"cn=Active Directory Ldap User,ou=SomeSystems,ou=Accounts,ou=Principal,dc=corp,dc=somecompany,dc=com\" "
+ "encryptedManagerPassword=\"pVyuW5ny9I6YT4Ou+KLZhQ==\" searchFilter=\"(sAMAccountName={0})\"> "
+ "<bases> <base value=\"ou=Employees,ou=Company,ou=Principal,dc=corp,dc=somecompany,dc=com\" /> </bases> </ldap>";
assertThat(output.toString().replaceAll("\\s+", " "), containsString(
expectedLdapConfig));
}
@Test
public void shouldWriteP4MaterialToXmlPartial() throws Exception {
String encryptedPassword = new GoCipher().encrypt("password");
P4MaterialConfig p4MaterialConfig = com.thoughtworks.go.helper.MaterialConfigsMother.p4MaterialConfig();
p4MaterialConfig.setPassword("password");
p4MaterialConfig.setConfigAttributes(m(
P4MaterialConfig.SERVER_AND_PORT, "localhost:1666",
P4MaterialConfig.USERNAME, "cruise",
P4MaterialConfig.VIEW, "//depot/dir1/... //lumberjack/...",
P4MaterialConfig.AUTO_UPDATE, "true"));
assertThat(xmlWriter.toXmlPartial(p4MaterialConfig), is(
"<p4 port=\"localhost:1666\" username=\"cruise\" encryptedPassword=\"" + encryptedPassword + "\">\n"
+ " <view><![CDATA["
+ "//depot/dir1/... //lumberjack/..."
+ "]]></view>\n"
+ "</p4>"));
}
@Test
public void shouldWriteSvnMaterialToXmlPartial() throws Exception {
String encryptedPassword = new GoCipher().encrypt("password");
SvnMaterialConfig material = com.thoughtworks.go.helper.MaterialConfigsMother.svnMaterialConfig("http://user:pass@svn", null, "cruise", "password", false, null);
assertThat(xmlWriter.toXmlPartial(material), is(
"<svn url=\"http://user:pass@svn\" username=\"cruise\" encryptedPassword=\"" + encryptedPassword + "\" materialName=\"http___user_pass@svn\" />"));
}
@Test
public void shouldWriteHgMaterialToXmlPartial() throws Exception {
HgMaterialConfig material = com.thoughtworks.go.helper.MaterialConfigsMother.hgMaterialConfig();
material.setConfigAttributes(m(HgMaterialConfig.URL, "http://user:pass@hg", HgMaterialConfig.AUTO_UPDATE, "true"));
assertThat(xmlWriter.toXmlPartial(material), is("<hg url=\"http://user:pass@hg\" />"));
}
@Test
public void shouldWriteGitMaterialToXmlPartial() throws Exception {
GitMaterialConfig gitMaterial = new GitMaterialConfig("gitUrl");
assertThat(xmlWriter.toXmlPartial(gitMaterial), is("<git url=\"gitUrl\" />"));
}
@Test
public void shouldWritePipelineGroupAdmins() throws Exception {
String content = ConfigFileFixture.configWithPipelines("<pipelines group=\"first\">\n"
+ "<authorization>"
+ " <admins>\n"
+ " <user>foo</user>\n"
+ " </admins>"
+ "</authorization>"
+ "<pipeline name='pipeline1'>\n"
+ " <materials>\n"
+ " <svn url =\"svnurl\"/>"
+ " </materials>\n<stage name='stage'><jobs><job name='job'></job></jobs></stage>"
+ "</pipeline>\n"
+ "</pipelines>\n", CONFIG_SCHEMA_VERSION);
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(content).config;
ByteArrayOutputStream out = new ByteArrayOutputStream();
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), containsString("<admins>"));
assertThat(out.toString(), containsString("<user>foo</user>"));
}
@Test
public void shouldWriteAllowOnlyKnownUsersFlag() throws Exception {
String content = ConfigFileFixture.configwithSecurity(
" <security allowOnlyKnownUsersToLogin='false'>\n"
+ " <passwordFile path=\"/home/cruise/projects/cruise_qa/cruise-twist-new/src/config/password.properties\" />\n"
+ " </security>");
ByteArrayOutputStream out = new ByteArrayOutputStream();
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(content).config;
SecurityConfig securityConfig = cruiseConfig.server().security();
assertThat(securityConfig.isAllowOnlyKnownUsersToLogin(), is(false));
securityConfig.setAllowOnlyKnownUsersToLogin(true);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), containsString("allowOnlyKnownUsersToLogin=\"true\""));
}
@Test
public void shouldAllowParamsInsidePipeline() throws Exception {
String content = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<cruise xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ " xsi:noNamespaceSchemaLocation=\"cruise-config.xsd\" schemaVersion='" + CONFIG_SCHEMA_VERSION + "'>\n"
+ "<server artifactsdir='artifactsDir' />"
+ "<pipelines>\n"
+ "<pipeline name='framework'>\n"
+ " <params>\n"
+ " <param name='first'>foo</param>\n"
+ " <param name='second'>bar</param>\n"
+ " </params>"
+ " <materials>\n"
+ " <svn url =\"svnurl\"/>"
+ " </materials>\n"
+ " <stage name='dist' fetchMaterials='true'>\n"
+ " <jobs>\n"
+ " <job name='package' />\n"
+ " </jobs>\n"
+ " </stage>\n"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "</cruise>";
ByteArrayOutputStream out = new ByteArrayOutputStream();
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(content).config;
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("framework"));
ParamsConfig params = pipelineConfig.getParams();
assertThat(params.getParamNamed("first"), is(new ParamConfig("first", "foo")));
assertThat(params.getParamNamed("second"), is(new ParamConfig("second", "bar")));
assertThat(params.getParamNamed("third"), is(nullValue()));
params.remove(0);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), not(containsString("<param name=\"first\">foo</param>")));
assertThat(out.toString(), containsString("<param name=\"second\">bar</param>"));
}
@Test
public void shouldWriteFetchMaterialsFlagToStage() throws Exception {
String content = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<cruise xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ " xsi:noNamespaceSchemaLocation=\"cruise-config.xsd\" schemaVersion='" + CONFIG_SCHEMA_VERSION + "'>\n"
+ "<server artifactsdir='artifactsDir' />"
+ "<pipelines>\n"
+ "<pipeline name='framework'>\n"
+ " <materials>\n"
+ " <svn url =\"svnurl\"/>"
+ " </materials>\n"
+ " <stage name='dist' fetchMaterials='true'>\n"
+ " <jobs>\n"
+ " <job name='package' />\n"
+ " </jobs>\n"
+ " </stage>\n"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "</cruise>";
ByteArrayOutputStream out = new ByteArrayOutputStream();
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(content).config;
StageConfig stageConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("framework")).get(0);
assertThat(stageConfig.isFetchMaterials(), is(true));
stageConfig.setFetchMaterials(false);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), containsString("fetchMaterials=\"false\""));
}
@Test
public void shouldWriteCleanWorkingDirFlagToStage() throws Exception {
String content = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<cruise xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ " xsi:noNamespaceSchemaLocation=\"cruise-config.xsd\" schemaVersion='" + CONFIG_SCHEMA_VERSION + "'>\n"
+ "<server artifactsdir='artifactsDir' />"
+ "<pipelines>\n"
+ "<pipeline name='framework'>\n"
+ " <materials>\n"
+ " <svn url =\"svnurl\"/>"
+ " </materials>\n"
+ " <stage name='dist' cleanWorkingDir='false'>\n"
+ " <jobs>\n"
+ " <job name='package' />\n"
+ " </jobs>\n"
+ " </stage>\n"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "</cruise>";
ByteArrayOutputStream out = new ByteArrayOutputStream();
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(content).config;
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), not(containsString("cleanWorkingDir")));
StageConfig stageConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("framework")).get(0);
stageConfig.setCleanWorkingDir(true);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), containsString("cleanWorkingDir=\"true\""));
}
@Test
public void shouldWriteArtifactPurgeSettings() throws Exception {
String content = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<cruise xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"cruise-config.xsd\" schemaVersion='" + CONFIG_SCHEMA_VERSION + "'>\n"
+ "<server artifactsdir='artifactsDir'/>"
+ "<pipelines>\n"
+ "<pipeline name='framework'>\n"
+ " <materials>\n"
+ " <svn url =\"svnurl\"/>"
+ " </materials>\n"
+ " <stage name='dist'>\n"
+ " <jobs>\n"
+ " <job name='package' />\n"
+ " </jobs>\n"
+ " </stage>\n"
+ "</pipeline>\n"
+ "</pipelines>\n"
+ "</cruise>";
ByteArrayOutputStream out = new ByteArrayOutputStream();
CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(content).config;
StageConfig stageConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("framework")).get(0);
ReflectionUtil.setField(stageConfig, "artifactCleanupProhibited", false);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), not(containsString("artifactCleanupProhibited=\"true\"")));
ReflectionUtil.setField(stageConfig, "artifactCleanupProhibited", true);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), containsString("artifactCleanupProhibited=\"true\""));
assertThat(out.toString(), not(containsString("purgeStart=\"10.0\"")));
assertThat(out.toString(), not(containsString("purgeUpto=\"20.0\"")));
cruiseConfig.server().setPurgeLimits(10.0, 20.0);
xmlWriter.write(cruiseConfig, out, false);
assertThat(out.toString(), containsString("purgeStart=\"10.0\""));
assertThat(out.toString(), containsString("purgeUpto=\"20.0\""));
}
@Test
public void shouldRemoveDuplicatedIgnoreTag() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.TWO_DUPLICATED_FILTER);
int size = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).materialConfigs().first().filter().size();
assertThat(size, is(1));
}
@Test
public void shouldNotAllowEmptyAuthInApproval() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.ONE_PIPELINE);
StageConfig stageConfig = com.thoughtworks.go.helper.StageConfigMother.custom("newStage", new AuthConfig());
cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1")).add(stageConfig);
try {
xmlWriter.write(cruiseConfig, output, false);
assertThat("Should not allow approval with empty auth", output.toString().contains("<auth"), is(false));
} catch (JDOMParseException expected) {
assertThat(expected.getMessage(), containsString("The content of element 'auth' is not complete"));
}
}
@Test
public void shouldNotWriteTrackingToolIfItIsNotDefined() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.ONE_PIPELINE);
xmlWriter.write(cruiseConfig, output, false);
assertThat("should not write empty trackingtool to config when it is not defined",
output.toString(), not(containsString("<trackingtool")));
}
@Test
public void shouldNotDefineATrackingToolWithoutALink() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.ONE_PIPELINE);
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1"));
pipelineConfig.setTrackingTool(new TrackingTool("", "regex"));
try {
xmlWriter.write(cruiseConfig, output, false);
fail("should not save a trackingtool without a link");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Link should be populated"));
}
}
@Test
public void shouldSkipValidationIfExplicitlyToldWhileWritingConfig() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.ONE_PIPELINE);
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1"));
pipelineConfig.addEnvironmentVariable("name1", "value1");
pipelineConfig.addEnvironmentVariable("name1", "value1");
xmlWriter.write(cruiseConfig, output, true);
assertThat(cruiseConfig.errors().isEmpty(), is(true));
}
@Test
public void shouldNotDefineATrackingToolWithoutARegex() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.ONE_PIPELINE);
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1"));
pipelineConfig.setTrackingTool(new TrackingTool("link", ""));
try {
xmlWriter.write(cruiseConfig, output, false);
fail("should not save a trackingtool without a regex");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Regex should be populated"));
}
}
@Test
public void shouldWriteConfigWithMultipleGroups() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.PIPELINE_GROUPS);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
xmlWriter.write(cruiseConfig, buffer, false);
final ByteArrayInputStream inputStream = new ByteArrayInputStream(buffer.toByteArray());
CruiseConfig config = xmlLoader.loadConfigHolder(FileUtil.readToEnd(inputStream)).config;
assertThat(config.getGroups().size(), is(2));
assertThat(config.getGroups().first().getGroup(), is("studios"));
}
@Test
public void shouldWriteConfigWithTaskExecutionConditions() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.TASKS_WITH_CONDITION);
xmlWriter.write(cruiseConfig, output, false);
final ByteArrayInputStream inputStream = new ByteArrayInputStream(output.toByteArray());
CruiseConfig config = xmlLoader.loadConfigHolder(FileUtil.readToEnd(inputStream)).config;
JobConfig job = config.jobConfigByName("pipeline1", "mingle", "cardlist", true);
assertThat(job.tasks().size(), Is.is(2));
assertThat(job.tasks().findFirstByType(AntTask.class).getConditions().get(0), Is.is(new RunIfConfig("failed")));
RunIfConfigs conditions = job.tasks().findFirstByType(NantTask.class).getConditions();
assertThat(conditions.get(0), Is.is(new RunIfConfig("failed")));
assertThat(conditions.get(1), Is.is(new RunIfConfig("any")));
assertThat(conditions.get(2), Is.is(new RunIfConfig("passed")));
}
@Test
// #3098
public void shouldAlwaysWriteArtifactsDir() throws Exception {
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.DEFAULT_XML_WITH_2_AGENTS);
xmlWriter.write(cruiseConfig, output, false);
assertThat(xmlWriter.toXmlPartial(cruiseConfig.server()), containsString("<server artifactsdir=\"artifactsDir\" "));
}
@Test
public void shouldThrowExceptionWhenPersisInvalidDom() throws Exception {
//simulate the xml partial saving logic
CruiseConfig cruiseConfig = ConfigMigrator.load(ConfigFileFixture.CONTAINS_MULTI_DIFFERENT_STATUS_RUN_IF);
StageConfig stage = xmlLoader.fromXmlPartial(ConfigFileFixture.SAME_STATUS_RUN_IF_PARTIAL, StageConfig.class);
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("test"));
pipelineConfig.set(0, stage);
try {
xmlWriter.write(cruiseConfig, output, false);
fail();
} catch (Exception e) {
assertThat(e.getMessage(), is("Duplicate unique value [passed] declared for identity constraint \"uniqueRunIfTypeForExec\" of element \"exec\"."));
}
}
@Test
public void shouldNotThrowUpWhenTfsWorkspaceIsNotSpecified() {
CruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("tfs_pipeline");
PipelineConfig tfs_pipeline = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("tfs_pipeline"));
tfs_pipeline.materialConfigs().clear();
tfs_pipeline.addMaterialConfig(new TfsMaterialConfig(new GoCipher(), new UrlArgument("http://tfs.com"), "username", "CORPORATE", "password", "$/project_path"));
try {
xmlWriter.write(cruiseConfig, output, false);
} catch (Exception e) {
fail("should not fail as workspace name is not mandatory anymore " + e);
}
}
@Test
public void shouldSerialize_CaseInsensitiveString_whenUsedInConfigAttributeValue() {//for instance FetchTask uses PathFromAncestor which has CaseInsensitiveString
CruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("uppest", "upper", "downer", "downest");
setDepedencyOn(cruiseConfig, "upper", "uppest", "stage");
setDepedencyOn(cruiseConfig, "downer", "upper", "stage");
setDepedencyOn(cruiseConfig, "downest", "downer", "stage");
PipelineConfig downest = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("downest"));
FetchTask fetchTask = new FetchTask(new CaseInsensitiveString("uppest/upper/downer"), new CaseInsensitiveString("stage"), new CaseInsensitiveString("job"), "src", "dest");
downest.add(com.thoughtworks.go.helper.StageConfigMother.stageConfig("stage-2", new JobConfigs(new JobConfig(new CaseInsensitiveString("downloader"), new Resources(), new ArtifactPlans(), new Tasks(fetchTask)))));
try {
xmlWriter.write(cruiseConfig, output, false);
} catch (Exception e) {
fail("should not fail as workspace name is not mandatory anymore " + e);
}
assertThat(new String(output.toByteArray()), containsString("<fetchartifact pipeline=\"uppest/upper/downer\" stage=\"stage\" job=\"job\" srcfile=\"src\" dest=\"dest\" />"));
}
@Test
public void shouldWriteMultipleSearchBases() throws Exception {
BaseConfig base1 = new BaseConfig("base1");
BaseConfig base2 = new BaseConfig("base2");
BasesConfig basesConfig = new BasesConfig(base1, base2);
LdapConfig ldapConfig = new LdapConfig("url", "managerDn", "managerPassword", "managerPassword", false, basesConfig, "filter");
SecurityConfig securityConfig = new SecurityConfig(ldapConfig, new PasswordFileConfig("some_path"), false);
ServerConfig serverConfig = new ServerConfig(securityConfig, new MailHost(new GoCipher()));
CruiseConfig cruiseConfig = new BasicCruiseConfig();
cruiseConfig.setServerConfig(serverConfig);
xmlWriter.write(cruiseConfig, output, false);
GoConfigHolder holder = xmlLoader.loadConfigHolder(output.toString());
BasesConfig actualBasesConfig = holder.config.server().security().ldapConfig().getBasesConfig();
assertThat(actualBasesConfig.size(), is(2));
assertThat(actualBasesConfig, hasItems(base1, base2));
}
@Test
public void shouldWriteRepositoryConfigurationWithPackages() throws Exception {
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = new PackageRepository();
packageRepository.setId("id");
packageRepository.setName("name");
packageRepository.setPluginConfiguration(new PluginConfiguration("plugin-id", "version"));
packageRepository.setConfiguration(new Configuration(getConfigurationProperty("url", false, "http://go"), getConfigurationProperty("secure", true, "secure")));
PackageDefinition packageDefinition = new PackageDefinition("id", "name", new Configuration(getConfigurationProperty("name", false, "go-agent")));
packageDefinition.setRepository(packageRepository);
packageRepository.getPackages().add(packageDefinition);
configToSave.getPackageRepositories().add(packageRepository);
xmlWriter.write(configToSave, output, false);
GoConfigHolder goConfigHolder = xmlLoader.loadConfigHolder(output.toString());
PackageRepositories packageRepositories = goConfigHolder.config.getPackageRepositories();
assertThat(packageRepositories, is(configToSave.getPackageRepositories()));
assertThat(packageRepositories.get(0).getConfiguration().first().getConfigurationValue().getValue(), is("http://go"));
assertThat(packageRepositories.get(0).getConfiguration().first().getEncryptedConfigurationValue(), is(nullValue()));
assertThat(packageRepositories.get(0).getConfiguration().last().getEncryptedValue(), is(new GoCipher().encrypt("secure")));
assertThat(packageRepositories.get(0).getConfiguration().last().getConfigurationValue(), is(nullValue()));
assertThat(packageRepositories.get(0).getPackages().get(0), is(packageDefinition));
assertThat(packageRepositories.get(0).getPackages().get(0).getConfiguration().first().getConfigurationValue().getValue(), is("go-agent"));
assertThat(packageRepositories.get(0).getPackages().get(0).getConfiguration().first().getEncryptedConfigurationValue(), is(nullValue()));
}
@Test
public void shouldWriteRepositoryConfigurationWithPackagesWhenNoRepoAndPkgIdIsProvided() throws Exception {
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = new PackageRepository();
packageRepository.setName("name");
packageRepository.setPluginConfiguration(new PluginConfiguration("plugin-id", "version"));
packageRepository.setConfiguration(new Configuration(getConfigurationProperty("url", false, "http://go"), getConfigurationProperty("secure", true, "secure")));
PackageDefinition packageDefinition = new PackageDefinition(null, "name", new Configuration(getConfigurationProperty("name", false, "go-agent")));
packageDefinition.setRepository(packageRepository);
packageRepository.getPackages().add(packageDefinition);
configToSave.getPackageRepositories().add(packageRepository);
xmlWriter.write(configToSave, output, false);
GoConfigHolder goConfigHolder = xmlLoader.loadConfigHolder(output.toString());
PackageRepositories packageRepositories = goConfigHolder.config.getPackageRepositories();
assertThat(packageRepositories.size(), is(configToSave.getPackageRepositories().size()));
assertThat(packageRepositories.get(0).getId(), is(notNullValue()));
assertThat(packageRepositories.get(0).getPackages().size(), is(1));
assertThat(packageRepositories.get(0).getPackages().get(0).getId(), is(notNullValue()));
}
@Test
public void shouldNotAllowMultipleRepositoriesWithSameId() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id-1", "version", "id", "name1", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name", packageConfiguration)));
PackageRepository anotherPackageRepository = createPackageRepository("plugin-id-2", "version", "id", "name2", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository, anotherPackageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (XsdValidationException e) {
assertThat(e.getMessage(), is("Duplicate unique value [id] declared for identity constraint \"uniqueRepositoryId\" of element \"repositories\"."));
}
}
@Test
public void shouldNotAllowMultiplePackagesWithSameId() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id-1", "version", "id1", "name1", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name", packageConfiguration)));
PackageRepository anotherPackageRepository = createPackageRepository("plugin-id-2", "version", "id2", "name2", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository, anotherPackageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two package repositories with same id");
} catch (XsdValidationException e) {
assertThat(e.getMessage(), is("Duplicate unique value [id] declared for identity constraint \"uniquePackageId\" of element \"cruise\"."));
}
}
@Test
public void shouldAllowPackageTypeMaterialForPipeline() throws Exception {
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = new PackageRepository();
packageRepository.setId("id");
packageRepository.setName("name");
packageRepository.setPluginConfiguration(new PluginConfiguration("plugin-id", "version"));
packageRepository.setConfiguration(new Configuration(getConfigurationProperty("url", false, "http://go")));
String packageId = "id";
PackageDefinition expectedPackageDefinition = new PackageDefinition(packageId, "name", new Configuration(getConfigurationProperty("name", false, "go-agent")));
expectedPackageDefinition.setRepository(packageRepository);
packageRepository.getPackages().add(expectedPackageDefinition);
configToSave.getPackageRepositories().add(packageRepository);
PackageMaterialConfig packageMaterialConfig = new PackageMaterialConfig(packageId);
packageMaterialConfig.setPackageDefinition(expectedPackageDefinition);
configToSave.addPipeline("default", com.thoughtworks.go.helper.PipelineConfigMother.pipelineConfig("test", new MaterialConfigs(packageMaterialConfig), new JobConfigs(new JobConfig("ls"))));
xmlWriter.write(configToSave, output, false);
GoConfigHolder goConfigHolder = xmlLoader.loadConfigHolder(output.toString());
PipelineConfig pipelineConfig = goConfigHolder.config.pipelineConfigByName(new CaseInsensitiveString("test"));
assertThat(pipelineConfig.materialConfigs().get(0) instanceof PackageMaterialConfig, is(true));
assertThat(((PackageMaterialConfig) pipelineConfig.materialConfigs().get(0)).getPackageId(), is(packageId));
PackageDefinition packageDefinition = goConfigHolder.config.getPackageRepositories().first().getPackages().first();
assertThat(((PackageMaterialConfig) pipelineConfig.materialConfigs().get(0)).getPackageDefinition(), is(packageDefinition));
}
@Test
public void shouldFailValidationIfPackageTypeMaterialForPipelineHasARefToNonExistantPackage() throws Exception {
CruiseConfig configToSave = new BasicCruiseConfig();
String packageId = "does-not-exist";
PackageMaterialConfig packageMaterialConfig = new PackageMaterialConfig(packageId);
PackageRepository repository = com.thoughtworks.go.domain.packagerepository.PackageRepositoryMother.create("repo-id", "repo-name", "pluginid", "version", new Configuration(com.thoughtworks.go.domain.packagerepository.ConfigurationPropertyMother.create("k1", false, "v1")));
packageMaterialConfig.setPackageDefinition(
com.thoughtworks.go.domain.packagerepository.PackageDefinitionMother.create("does-not-exist", "package-name", new Configuration(com.thoughtworks.go.domain.packagerepository.ConfigurationPropertyMother.create("k2", false, "v2")), repository));
configToSave.addPipeline("default", com.thoughtworks.go.helper.PipelineConfigMother.pipelineConfig("test", new MaterialConfigs(packageMaterialConfig), new JobConfigs(new JobConfig("ls"))));
try {
xmlWriter.write(configToSave, output, false);
fail("should not allow this");
} catch (XsdValidationException exception) {
assertThat(exception.getMessage(), is("Key 'packageIdReferredByMaterial' with value 'does-not-exist' not found for identity constraint of element 'cruise'."));
}
}
@Test
public void shouldNotAllowMultipleRepositoriesWithSameName() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id", "version", "id1", "name", repositoryConfiguration,
new Packages(new PackageDefinition("id1", "name1", packageConfiguration)));
PackageRepository anotherPackageRepository = createPackageRepository("plugin-id", "version", "id2", "name", repositoryConfiguration,
new Packages(new PackageDefinition("id2", "name2", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository, anotherPackageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (GoConfigInvalidException e) {
assertThat(e.getMessage(), is("You have defined multiple repositories called 'name'. Repository names are case-insensitive and must be unique."));
}
}
@Test
public void shouldNotAllowMultiplePackagesWithSameNameWithinARepo() throws Exception {
Configuration packageConfiguration1 = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration packageConfiguration2 = new Configuration(getConfigurationProperty("name2", false, "go-server"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id", "version", "id", "name", repositoryConfiguration,
new Packages(new PackageDefinition("id1", "name", packageConfiguration1), new PackageDefinition("id2", "name", packageConfiguration2)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (GoConfigInvalidException e) {
assertThat(e.getMessage(), is("You have defined multiple packages called 'name'. Package names are case-insensitive and must be unique within a repository."));
}
}
@Test
public void shouldNotAllowPackagesRepositoryWithInvalidId() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id", "version", "id wth space", "name", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (XsdValidationException e) {
assertThat(e.getMessage(), is("Repo id is invalid. \"id wth space\" should conform to the pattern - [a-zA-Z0-9_\\-]{1}[a-zA-Z0-9_\\-.]*"));
}
}
@Test
public void shouldNotAllowPackagesRepositoryWithInvalidName() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id", "version", "id", "name with space", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (GoConfigInvalidException e) {
assertThat(e.getMessage(),
is("Invalid PackageRepository name 'name with space'. 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 shouldNotAllowPackagesWithInvalidId() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id", "version", "id", "name", repositoryConfiguration,
new Packages(new PackageDefinition("id with space", "name", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (XsdValidationException e) {
assertThat(e.getMessage(), is("Package id is invalid. \"id with space\" should conform to the pattern - [a-zA-Z0-9_\\-]{1}[a-zA-Z0-9_\\-.]*"));
}
}
@Test
public void shouldNotWriteToFileWithDefaultValueOfTrueForPackageDefinitionAutoUpdateWhenTrue() throws Exception {
Configuration configuration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig cruiseConfig = new BasicCruiseConfig();
Packages packages = new Packages();
PackageRepository repository = createPackageRepository("plugin-id", "version", "id", "name", configuration, packages);
PackageDefinition aPackage = new PackageDefinition("package-id", "package-name", configuration);
aPackage.setAutoUpdate(true);
packages.add(aPackage);
aPackage.setRepository(repository);
cruiseConfig.setPackageRepositories(new PackageRepositories(repository));
xmlWriter.write(cruiseConfig, output, false);
assertThat(output.toString().contains("autoUpdate=\"true\""), is(false));
}
@Test
public void shouldWriteToFileWithValueOfFalseForPackageDefinitionAutoUpdateWhenFalse() throws Exception {
Configuration configuration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig cruiseConfig = new BasicCruiseConfig();
Packages packages = new Packages();
PackageDefinition aPackage = new PackageDefinition("package-id", "package-name", configuration);
aPackage.setAutoUpdate(false);
packages.add(aPackage);
PackageRepository repository = createPackageRepository("plugin-id", "version", "id", "name", configuration, packages);
cruiseConfig.setPackageRepositories(new PackageRepositories(repository));
xmlWriter.write(cruiseConfig, output, false);
assertThat(output.toString().contains("autoUpdate=\"false\""), is(true));
}
@Test
public void shouldNotAllowPackagesWithInvalidName() throws Exception {
Configuration packageConfiguration = new Configuration(getConfigurationProperty("name", false, "go-agent"));
Configuration repositoryConfiguration = new Configuration(getConfigurationProperty("url", false, "http://go"));
CruiseConfig configToSave = new BasicCruiseConfig();
PackageRepository packageRepository = createPackageRepository("plugin-id", "version", "id", "name", repositoryConfiguration,
new Packages(new PackageDefinition("id", "name with space", packageConfiguration)));
configToSave.setPackageRepositories(new PackageRepositories(packageRepository));
try {
xmlWriter.write(configToSave, output, false);
fail("should not have allowed two repositories with same id");
} catch (GoConfigInvalidException e) {
assertThat(e.getMessage(),
is("Invalid Package name 'name with space'. 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 shouldNotWriteEmptyAuthorizationUnderEachTemplateTagOntoConfigFile() throws Exception {
CruiseConfig cruiseConfig = new BasicCruiseConfig();
PipelineTemplateConfig template = com.thoughtworks.go.helper.PipelineTemplateConfigMother.createTemplate("template-name", new Authorization(new AdminsConfig()), com.thoughtworks.go.helper.StageConfigMother.manualStage("stage-name"));
cruiseConfig.addTemplate(template);
xmlWriter.write(cruiseConfig, output, false);
String writtenConfigXml = this.output.toString();
assertThat(writtenConfigXml, not(containsString("<authorization>")));
}
@Test
public void shouldDisplayTheFlagInXmlIfTemplateAuthorizationDoesNotAllowGroupAdmins() throws Exception {
CruiseConfig cruiseConfig = new BasicCruiseConfig();
PipelineTemplateConfig template = com.thoughtworks.go.helper.PipelineTemplateConfigMother.createTemplate("template-name", new Authorization(new AdminsConfig()), com.thoughtworks.go.helper.StageConfigMother.manualStage("stage-name"));
template.getAuthorization().setAllowGroupAdmins(false);
cruiseConfig.addTemplate(template);
xmlWriter.write(cruiseConfig, output, false);
String writtenConfigXml = this.output.toString();
assertThat(writtenConfigXml, containsString("allGroupAdminsAreViewers"));
}
@Test
public void shouldNotDisplayTheOptionIfTemplateAllowsGroupAdminsToBeViewers() throws Exception {
CruiseConfig cruiseConfig = new BasicCruiseConfig();
PipelineTemplateConfig template = com.thoughtworks.go.helper.PipelineTemplateConfigMother.createTemplate("template-name", new Authorization(new AdminsConfig()), com.thoughtworks.go.helper.StageConfigMother.manualStage("stage-name"));
cruiseConfig.addTemplate(template);
xmlWriter.write(cruiseConfig, output, false);
String writtenConfigXml = this.output.toString();
assertThat(writtenConfigXml, not(containsString("allGroupAdminsAreViewers")));
}
private ConfigurationProperty getConfigurationProperty(String key, boolean isSecure, String value) {
ConfigurationProperty property = new ConfigurationProperty(new ConfigurationKey(key), new ConfigurationValue(value), null, new GoCipher());
property.handleSecureValueConfiguration(isSecure);
return property;
}
private void setDepedencyOn(CruiseConfig cruiseConfig, String toPipeline, String upstreamPipeline, String upstreamStage) {
PipelineConfig targetPipeline = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString(toPipeline));
targetPipeline.materialConfigs().clear();
targetPipeline.addMaterialConfig(new DependencyMaterialConfig(new CaseInsensitiveString(upstreamPipeline), new CaseInsensitiveString(upstreamStage)));
}
private PackageRepository createPackageRepository(String pluginId, String version, String id, String name, Configuration configuration, Packages packages) {
PackageRepository packageRepository = new PackageRepository();
packageRepository.setConfiguration(configuration);
packageRepository.setPackages(packages);
packageRepository.setPluginConfiguration(new PluginConfiguration(pluginId, version));
packageRepository.setId(id);
packageRepository.setName(name);
for (PackageDefinition aPackage : packages) {
aPackage.setRepository(packageRepository);
}
return packageRepository;
}
public static void assertXmlEquals(String expected, String actual) {
assertThat(actual.replaceAll(">\\s+<", ""), is(expected.replaceAll(">\\s+<", "")));
}
}