/*
* 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;
import com.thoughtworks.go.config.elastic.ElasticProfile;
import com.thoughtworks.go.config.elastic.ElasticProfiles;
import com.thoughtworks.go.config.materials.dependency.DependencyMaterialConfig;
import com.thoughtworks.go.config.materials.mercurial.HgMaterialConfig;
import com.thoughtworks.go.config.pluggabletask.PluggableTask;
import com.thoughtworks.go.config.registry.ConfigElementImplementationRegistry;
import com.thoughtworks.go.config.validation.GoConfigValidity;
import com.thoughtworks.go.domain.GoConfigRevision;
import com.thoughtworks.go.domain.Task;
import com.thoughtworks.go.domain.config.*;
import com.thoughtworks.go.domain.materials.MaterialConfig;
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.helper.ConfigFileFixture;
import com.thoughtworks.go.security.GoCipher;
import com.thoughtworks.go.server.service.GoConfigService;
import com.thoughtworks.go.server.util.ServerVersion;
import com.thoughtworks.go.serverhealth.*;
import com.thoughtworks.go.service.ConfigRepository;
import com.thoughtworks.go.util.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.jdom2.Document;
import org.jdom2.filter.ElementFilter;
import org.jdom2.input.SAXBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static com.thoughtworks.go.domain.packagerepository.ConfigurationPropertyMother.create;
import static com.thoughtworks.go.util.ExceptionUtils.bomb;
import static com.thoughtworks.go.util.FileUtil.readToEnd;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:WEB-INF/applicationContext-global.xml",
"classpath:WEB-INF/applicationContext-dataLocalAccess.xml",
"classpath:WEB-INF/applicationContext-acegi-security.xml"
})
public class GoConfigMigrationIntegrationTest {
private File configFile;
ConfigRepository configRepository;
@Autowired private SystemEnvironment systemEnvironment;
@Autowired private ConfigCache configCache;
@Autowired private ServerVersion serverVersion;
@Autowired private ConfigElementImplementationRegistry registry;
@Autowired private GoConfigService goConfigService;
@Autowired private ServerHealthService serverHealthService;
@Autowired private CachedGoPartials cachedGoPartials;
private String currentGoServerVersion;
private MagicalGoConfigXmlLoader loader;
private String password;
private String encryptedPassword;
@Before
public void setUp() throws Exception {
configFile = TestFileUtil.createTempFileInSubfolder("cruise-config.xml");
new SystemEnvironment().setProperty(SystemEnvironment.CONFIG_FILE_PROPERTY, configFile.getAbsolutePath());
GoConfigFileHelper.clearConfigVersions();
configRepository = new ConfigRepository(systemEnvironment);
configRepository.initialize();
serverHealthService.removeAllLogs();
currentGoServerVersion = serverVersion.version();
loader = new MagicalGoConfigXmlLoader(new ConfigCache(), ConfigElementImplementationRegistryMother.withNoPlugins());
password = UUID.randomUUID().toString();
encryptedPassword = new GoCipher().encrypt(password);
}
@After
public void tearDown() throws Exception {
GoConfigFileHelper.clearConfigVersions();
configFile.delete();
serverHealthService.removeAllLogs();
}
@Test
public void shouldNotUpgradeCruiseConfigFileIfVersionMatches() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.MINIMAL);
assertThat(cruiseConfig.schemaVersion(), is(GoConstants.CONFIG_SCHEMA_VERSION));
assertThat(configRepository.getRevision(ConfigRepository.CURRENT).getUsername(), is(not("Upgrade")));
}
@Test
public void shouldValidateCruiseConfigFileIrrespectiveOfUpgrade() throws Exception {
String configString = ConfigFileFixture.configWithEnvironments("<environments>"
+ " <environment name='foo'>"
+ "<pipelines>"
+ " <pipeline name='does_not_exist'/>"
+ "</pipelines>"
+ "</environment>"
+ "</environments>");
try {
loadConfigFileWithContent(configString);
fail("Should not upgrade invalid config file");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Environment 'foo' refers to an unknown pipeline 'does_not_exist'"));
}
}
@Test
public void shouldUpgradeCruiseConfigFileIfVersionDoesNotMatch() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.OLD);
assertThat(cruiseConfig.schemaVersion(), is(GoConstants.CONFIG_SCHEMA_VERSION));
}
@Test
public void shouldMigrateConfigContentAsAString() throws Exception {
String newContent = new GoConfigMigration(configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins())
.upgradeIfNecessary(ConfigFileFixture.VERSION_0);
assertThat(newContent, containsString("schemaVersion=\"" + GoConfigSchema.currentSchemaVersion() + "\""));
}
@Test
public void shouldNotMigrateConfigContentAsAStringWhenAlreadyUpToDate() throws Exception {
GoConfigMigration configMigration = new GoConfigMigration(configRepository, new TimeProvider(), configCache,
ConfigElementImplementationRegistryMother.withNoPlugins());
String newContent = configMigration.upgradeIfNecessary(ConfigFileFixture.VERSION_0);
assertThat(newContent, is(configMigration.upgradeIfNecessary(newContent)));
}
@Test
public void shouldNotUpgradeInvalidConfigFileWhenThereIsNoValidConfigVersioned() throws Exception {
try {
assertThat(configRepository.getRevision(ConfigRepository.CURRENT), is(nullValue()));
loadConfigFileWithContent("<cruise></cruise>");
fail("Should not upgrade invalid config file");
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Cruise config file with version 0 is invalid. Unable to upgrade."));
}
}
@Test
public void shouldRevertConfigToTheLatestValidConfigVersionFromGitIfCurrentConfigIsInvalid() throws IOException {
try {
loadConfigFileWithContent(ConfigFileFixture.MINIMAL);
loadConfigFileWithContent("<cruise></cruise>");
ServerHealthStates states = serverHealthService.getAllLogs();
assertThat(states.size(), is(1));
assertThat(states.get(0).getDescription(), containsString("Go encountered an invalid configuration file while starting up. The invalid configuration file has been renamed to ‘"));
assertThat(states.get(0).getDescription(), containsString("’ and a new configuration file has been automatically created using the last good configuration."));
assertThat(states.get(0).getMessage(), containsString("Invalid Configuration"));
assertThat(states.get(0).getType(), is(HealthStateType.general(HealthStateScope.forInvalidConfig())));
assertThat(states.get(0).getLogLevel(), is(HealthStateLevel.WARNING));
} catch (Exception e) {
fail("Should not Throw an exception, should revert to the last valid file versioned in config.git");
}
}
@Test
public void shouldTryToRevertConfigToTheLatestValidConfigVersionOnlyOnce() throws IOException {
try {
configRepository.checkin(new GoConfigRevision("<cruise></cruise>", "md5", "ps", "123", new TimeProvider()));
loadConfigFileWithContent("<cruise></cruise>");
ServerHealthStates states = serverHealthService.getAllLogs();
assertThat(states.size(), is(1));
assertThat(states.get(0).getDescription(), containsString("Go encountered an invalid configuration file while starting up. The invalid configuration file has been renamed to ‘"));
assertThat(states.get(0).getDescription(), containsString("’ and a new configuration file has been automatically created using the last good configuration."));
assertThat(states.get(0).getMessage(), containsString("Invalid Configuration"));
assertThat(states.get(0).getType(), is(HealthStateType.general(HealthStateScope.forInvalidConfig())));
assertThat(states.get(0).getLogLevel(), is(HealthStateLevel.WARNING));
} catch (Exception e) {
assertThat(e.getMessage(), containsString("Cruise config file with version 0 is invalid. Unable to upgrade."));
}
}
@Test
public void shouldMoveApprovalFromAPreviousStageToTheBeginningOfASecondStage() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.VERSION_0);
PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline"));
StageConfig firstStage = pipelineConfig.get(0);
StageConfig secondStage = pipelineConfig.get(1);
assertThat(firstStage.requiresApproval(), is(Boolean.FALSE));
assertThat(secondStage.requiresApproval(), is(Boolean.TRUE));
}
@Test
public void shouldMigrateApprovalsCorrectlyBug2112() throws Exception {
File bjcruise = new File("../common/test-resources/unit/data/bjcruise-cruise-config-1.0.xml");
assertThat(bjcruise.exists(), is(true));
String xml = readToEnd(bjcruise);
CruiseConfig cruiseConfig = loadConfigFileWithContent(xml);
PipelineConfig pipeline = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("evolve"));
StageConfig dbStage = pipeline.findBy(new CaseInsensitiveString("db"));
assertThat(dbStage.requiresApproval(), is(false));
StageConfig installStage = pipeline.findBy(new CaseInsensitiveString("install"));
assertThat(installStage.requiresApproval(), is(true));
}
@Test
public void shouldBackupOldConfigFileBeforeUpgrade() throws Exception {
assertThat(configFiles().length, is(0));
loadConfigFileWithContent(ConfigFileFixture.OLD);
assertThat(configFiles().length, is(1));
}
@Test
public void shouldMigrateMaterialFolderAttributeToDest() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.VERSION_2);
MaterialConfig actual = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("multiple")).materialConfigs().first();
assertThat(actual.getFolder(), is("part1"));
}
@Test
public void shouldMigrateRevision5ToTheLatest() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.VERSION_5);
assertThat(cruiseConfig.schemaVersion(), is(GoConstants.CONFIG_SCHEMA_VERSION));
}
@Test
public void shouldMigrateRevision7To8() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.VERSION_7);
HgMaterialConfig hgConfig = (HgMaterialConfig) cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("framework")).materialConfigs().first();
assertThat(hgConfig.getFolder(), is(nullValue()));
assertThat(hgConfig.filter(), is(notNullValue()));
}
@Test
public void shouldMigrateToRevision17() throws Exception {
CruiseConfig cruiseConfig = loadConfigFileWithContent(ConfigFileFixture.WITH_3_AGENT_CONFIG);
assertThat(cruiseConfig.agents().size(), is(3));
assertThat(cruiseConfig.agents().getAgentByUuid("2").isDisabled(), is(true));
assertThat(cruiseConfig.agents().getAgentByUuid("1").isDisabled(), is(false));
}
@Test
public void shouldMigrateDependsOnTagToBeADependencyMaterial() throws Exception {
String content = FileUtils.readFileToString(
new File("../common/test-resources/unit/data/config/version4/cruise-config-dependency-migration.xml"));
CruiseConfig cruiseConfig = loadConfigFileWithContent(content);
MaterialConfig actual = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("depends")).materialConfigs().first();
assertThat(actual, instanceOf(DependencyMaterialConfig.class));
DependencyMaterialConfig depends = (DependencyMaterialConfig) actual;
assertThat(depends.getPipelineName(), is(new CaseInsensitiveString("multiple")));
assertThat(depends.getStageName(), is(new CaseInsensitiveString("helloworld-part2")));
}
@Test
public void shouldFailIfJobsWithSameNameButDifferentCasesExistInConfig() throws IOException {
final List<Exception> exs = new ArrayList<>();
GoConfigMigration upgrader = new GoConfigMigration(
new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
exs.add(e);
}
}, configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins());
FileUtils.writeStringToFile(configFile, ConfigFileFixture.JOBS_WITH_DIFFERNT_CASE);
upgrader.upgradeIfNecessary(configFile, currentGoServerVersion);
assertThat(exs.size(), is(1));
assertThat(exs.get(0).getMessage(), containsString("You have defined multiple Jobs called 'Test'"));
}
@Test
public void shouldVersionControlAnUpgradedConfigIfItIsValid() throws Exception {
GoConfigMigration upgrader = new GoConfigMigration(
new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
throw new AssertionError("upgrade failed!!!!!");
}
}, configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins());
FileUtils.writeStringToFile(configFile, ConfigFileFixture.DEFAULT_XML_WITH_2_AGENTS);
configRepository.checkin(new GoConfigRevision("dummy-content", "some-md5", "loser", "100.3.1", new TimeProvider()));
upgrader.upgradeIfNecessary(configFile, currentGoServerVersion);
GoConfigRevision latest = configRepository.getRevision(ConfigRepository.CURRENT);
assertThat(latest.getUsername(), is("Upgrade"));
String contents = FileUtils.readFileToString(configFile);
assertThat(latest.getContent(), is(contents));
assertThat(latest.getMd5(), is(DigestUtils.md5Hex(contents)));
}
@Test
public void shouldMigrateToRevision22() throws Exception {
final String content = FileUtil.readToEnd(getClass().getResourceAsStream("cruise-config-escaping-migration-test-fixture.xml"));
String migratedContent = migrateXmlString(content, 21, 22);
String expected = content.replaceAll("(?<!do_not_sub_)#", "##").replace("<cruise schemaVersion=\"21\">", "<cruise schemaVersion=\"22\">");
assertStringsIgnoringCarriageReturnAreEqual(expected, migratedContent);
}
@Test
public void shouldMigrateToRevision28() throws Exception {
final String content = FileUtil.readToEnd(getClass().getResourceAsStream("no-tracking-tool-group-holder-config.xml"));
String migratedContent = migrateXmlString(content, 27);
assertThat(migratedContent, containsString("\"http://foo.bar/baz/${ID}\""));
assertThat(migratedContent, containsString("\"http://hello.world/${ID}/hello\""));
}
@Test
public void shouldMigrateToRevision34() throws Exception {
final String content = FileUtil.readToEnd(getClass().getResourceAsStream("svn-p4-with-parameterized-passwords.xml"));
String migratedContent = migrateXmlString(content, 22);
String expected = content.replaceAll("#\\{jez_passwd\\}", "badger")
.replace("<cruise schemaVersion=\"22\">", "<cruise schemaVersion=\"" + GoConstants.CONFIG_SCHEMA_VERSION + "\">")
.replaceAll("##", "#");
assertStringsIgnoringCarriageReturnAreEqual(expected, migratedContent);
}
@Test
public void shouldMigrateToRevision35_escapeHash() throws Exception {
final String content = FileUtil.readToEnd(getClass().getResourceAsStream("escape_param_for_nant_p4.xml"));
String migratedContent = migrateXmlString(content, 22);
String expected = content.replace("<cruise schemaVersion=\"22\">", "<cruise schemaVersion=\"" + GoConstants.CONFIG_SCHEMA_VERSION + "\">")
.replace("<view>##foo#</view>", "<view>####foo##</view>").replace("nantpath=\"#foo##\"", "nantpath=\"##foo####\"");
assertStringsIgnoringCarriageReturnAreEqual(expected, migratedContent);
}
@Test
public void shouldMigrateToRevision58_deleteVMMS() throws Exception {
String migratedContent = migrateXmlString(ConfigFileFixture.WITH_VMMS_CONFIG, 50, 58);
assertFalse(migratedContent.contains("vmms"));
}
@Test
public void shouldMigrateToRevision59_convertLogTypeToArtifact() throws Exception {
String migratedContent = migrateXmlString(ConfigFileFixture.WITH_LOG_ARTIFACT_CONFIG, 50, 59);
CruiseConfig cruiseConfig = loadConfigFileWithContent(migratedContent);
ArtifactPlans artifactPlans = cruiseConfig.getAllPipelineConfigs().get(0).getStage(new CaseInsensitiveString("mingle")).getJobs().getJob(
new CaseInsensitiveString("bluemonkeybutt")).artifactPlans();
assertEquals("from1", artifactPlans.get(0).getSrc());
assertEquals(artifactPlans.get(0).getDest(), "");
assertEquals("from2", artifactPlans.get(1).getSrc());
assertEquals("to2", artifactPlans.get(1).getDest());
assertEquals("from3", artifactPlans.get(2).getSrc());
assertEquals(artifactPlans.get(2).getDest(), "");
assertEquals("from4", artifactPlans.get(3).getSrc());
assertEquals("to4", artifactPlans.get(3).getDest());
}
@Test
public void shouldMigrateExecTaskArgValueToTextNode() throws Exception {
String migratedContent = migrateXmlString(ConfigFileFixture.VALID_XML_3169, 14);
assertThat(migratedContent, containsString("<arg>test</arg>"));
}
@Test
public void shouldMigrateToRevision23_IsLockedIsFalseByDefault() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
final String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<cruise schemaVersion=\"22\">\n"
+ " <server artifactsdir=\"artifacts\"/>\n"
+ " <pipelines>"
+ " <pipeline name=\"in_env\">"
+ " <materials> "
+ " <hg url=\"blah\"/>"
+ " </materials> "
+ " <stage name=\"some_stage\">"
+ " <jobs>"
+ " <job name=\"some_job\">"
+ " <tasks>"
+ " <exec command=\"ls\"/>"
+ " </tasks>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " <pipeline name=\"not_in_env\">"
+ " <materials> "
+ " <hg url=\"blah\"/>"
+ " </materials> "
+ " <stage name=\"some_stage\">"
+ " <jobs>"
+ " <job name=\"some_job\">"
+ " <tasks>"
+ " <exec command=\"ls\"/>"
+ " </tasks>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " <pipeline name=\"in_env_unLocked\" isLocked=\"false\">"
+ " <materials> "
+ " <hg url=\"blah\"/>"
+ " </materials> "
+ " <stage name=\"some_stage\">"
+ " <jobs>"
+ " <job name=\"some_job\">"
+ " <tasks>"
+ " <exec command=\"ls\"/>"
+ " </tasks>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " </pipelines>"
+ " <environments>"
+ " <environment name=\"some_env\">"
+ " <pipelines>"
+ " <pipeline name=\"in_env\"/>"
+ " <pipeline name=\"in_env_unLocked\"/>"
+ " </pipelines>"
+ " </environment>"
+ " </environments>"
+ " </cruise>";
String migratedContent = migrateXmlString(content, 22);
assertThat(migratedContent, containsString("<pipeline isLocked=\"true\" name=\"in_env\">"));
assertThat(migratedContent, containsString("<pipeline isLocked=\"false\" name=\"in_env_unLocked\">"));
assertThat(migratedContent, containsString("<pipeline name=\"not_in_env\">"));
}
@Test
public void shouldEncryptPasswordsOnUpgradeIfNecessary() throws IOException {
final List<Exception> exs = new ArrayList<>();
GoConfigMigration upgrader = new GoConfigMigration(
new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
exs.add(e);
}
}, configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins());
String configContent = ConfigFileFixture.configWithPipeline(String.format(
"<pipeline name='pipeline1'>"
+ " <materials>"
+ " <svn url='svnurl' username='admin' password='%s'/>"
+ " </materials>"
+ " <stage name='mingle'>"
+ " <jobs>"
+ " <job name='do-something'>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ "</pipeline>", "hello"), 32);
FileUtils.writeStringToFile(configFile, configContent);
upgrader.upgradeIfNecessary(configFile, currentGoServerVersion);
assertThat(FileUtils.readFileToString(configFile), containsString("encryptedPassword="));
assertThat(FileUtils.readFileToString(configFile), not(containsString("password=")));
}
@Test
public void shouldMergeRolesWithMatchingCaseInsensitiveNames() throws Exception {
final String configContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<cruise schemaVersion=\"39\">\n"
+ " <server artifactsdir=\"artifacts\">\n"
+ " <security>\n"
+ " <roles>\n"
+ " <role name=\"bAr\">\n"
+ " <user>quux</user>\n"
+ " <user>bang</user>\n"
+ " <user>LoSeR</user>\n"
+ " </role>\n"
+ " <role name=\"Foo\">\n"
+ " <user>foo</user>\n"
+ " <user>LoSeR</user>\n"
+ " <user>bar</user>\n"
+ " <user>LOsER</user>\n"
+ " </role>\n"
+ " <role name=\"BaR\">\n"
+ " <user>baz</user>\n"
+ " <user>bang</user>\n"
+ " <user>lOsEr</user>\n"
+ " </role>\n"
+ " </roles>\n"
+ " </security>"
+ " </server>"
+ " </cruise>";
File configFile = new File(systemEnvironment.getCruiseConfigFile());
FileUtils.writeStringToFile(configFile, configContent);
CruiseConfig cruiseConfig = loadWithMigration(configFile).config;
RolesConfig roles = cruiseConfig.server().security().getRoles();
assertThat(roles.size(), is(2));
assertThat(roles.get(0), is(new RoleConfig(new CaseInsensitiveString("bAr"),
new RoleUser(new CaseInsensitiveString("quux")),
new RoleUser(new CaseInsensitiveString("bang")),
new RoleUser(new CaseInsensitiveString("LoSeR")),
new RoleUser(new CaseInsensitiveString("baz")))));
assertThat(roles.get(1), is(new RoleConfig(new CaseInsensitiveString("Foo"),
new RoleUser(new CaseInsensitiveString("foo")),
new RoleUser(new CaseInsensitiveString("LoSeR")),
new RoleUser(new CaseInsensitiveString("bar")))));
}
@Test
public void shouldAllowParamsInP4ServerAndPortField() throws IOException {
final List<Exception> exs = new ArrayList<>();
GoConfigMigration upgrader = new GoConfigMigration(
new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
exs.add(e);
}
}, configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins()
);
String configContent = ConfigFileFixture.configWithPipeline(String.format(
"<pipeline name='pipeline1'>"
+ "<params>"
+ " <param name='param_foo'>a:3</param>"
+ " </params>"
+ " <materials>"
+ "<p4 port='#{param_foo}' username='' dest='blah' materialName='boo'>"
+ "<view><![CDATA[blah]]></view>"
+ "<filter>"
+ "<ignore pattern='' />"
+ "</filter>"
+ "</p4>"
+ " </materials>"
+ " <stage name='mingle'>"
+ " <jobs>"
+ " <job name='do-something'>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ "</pipeline>", "hello"), 32);
FileUtils.writeStringToFile(configFile, configContent);
upgrader.upgradeIfNecessary(configFile, currentGoServerVersion);
assertThat(FileUtils.readFileToString(configFile), containsString("port='#{param_foo}'"));
}
@Test
public void shouldIntroduceAWrapperTagForUsersOfRole() throws Exception {
final List<Exception> exs = new ArrayList<>();
GoConfigMigration upgrader = new GoConfigMigration(
new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
exs.add(e);
}
}, configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins());
String content = "<cruise schemaVersion='" + 47 + "'>\n"
+ "<server artifactsdir=\"logs\" siteUrl=\"http://go-server-site-url:8153\" secureSiteUrl=\"https://go-server-site-url:8154\" jobTimeout=\"60\">\n"
+ " <security>\n"
+ " <roles>\n"
+ " <role name=\"admins\">\n"
+ " <user>admin_one</user>\n"
+ " <user>admin_two</user>\n"
+ " </role>\n"
+ " <role name=\"devs\">\n"
+ " <user>dev_one</user>\n"
+ " <user>dev_two</user>\n"
+ " <user>dev_three</user>\n"
+ " </role>\n"
+ " </roles>\n"
+ " <admins>\n"
+ " <role>admins</role>\n"
+ " </admins>\n"
+ " </security>\n"
+ " </server>"
+ "</cruise>";
FileUtils.writeStringToFile(configFile, content);
upgrader.upgradeIfNecessary(configFile, currentGoServerVersion);
String configXml = FileUtils.readFileToString(configFile);
MagicalGoConfigXmlLoader loader = new MagicalGoConfigXmlLoader(new ConfigCache(), ConfigElementImplementationRegistryMother.withNoPlugins());
GoConfigHolder configHolder = loader.loadConfigHolder(configXml);
CruiseConfig config = configHolder.config;
ServerConfig server = config.server();
RolesConfig roles = server.security().getRoles();
assertThat(roles,
hasItem(new RoleConfig(new CaseInsensitiveString("admins"), new RoleUser(new CaseInsensitiveString("admin_one")), new RoleUser(new CaseInsensitiveString("admin_two")))));
assertThat(roles, hasItem(new RoleConfig(new CaseInsensitiveString("devs"), new RoleUser(new CaseInsensitiveString("dev_one")), new RoleUser(new CaseInsensitiveString("dev_two")),
new RoleUser(new CaseInsensitiveString("dev_three")))));
}
@Test
public void shouldSetServerId_toARandomUUID_ifServerTagDoesntExist() {
GoConfigService.XmlPartialSaver fileSaver = goConfigService.fileSaver(true);
GoConfigValidity configValidity = fileSaver.saveXml("<cruise schemaVersion='" + 53 + "'>\n"
+ "</cruise>", goConfigService.configFileMd5());
assertThat("Has error: " + configValidity.errorMessage(), configValidity.isValid(), is(true));
CruiseConfig config = goConfigService.getCurrentConfig();
ServerConfig server = config.server();
assertThat(server.getServerId().matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"), is(true));
}
@Test
public void shouldSetServerId_toARandomUUID_ifOneDoesntExist() {
GoConfigService.XmlPartialSaver fileSaver = goConfigService.fileSaver(true);
GoConfigValidity configValidity = fileSaver.saveXml("<cruise schemaVersion='" + 55 + "'>\n"
+ "<server artifactsdir=\"logs\" siteUrl=\"http://go-server-site-url:8153\" secureSiteUrl=\"https://go-server-site-url:8154\" jobTimeout=\"60\">\n"
+ " </server>"
+ "</cruise>", goConfigService.configFileMd5());
assertThat("Has error: " + configValidity.errorMessage(), configValidity.isValid(), is(true));
CruiseConfig config = goConfigService.getCurrentConfig();
ServerConfig server = config.server();
assertThat(server.getServerId().matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"), is(true));
}
@Test
public void shouldLoadServerId_ifOneExists() {
GoConfigService.XmlPartialSaver fileSaver = goConfigService.fileSaver(true);
GoConfigValidity configValidity = fileSaver.saveXml("<cruise schemaVersion='" + 55 + "'>\n"
+ "<server artifactsdir=\"logs\" siteUrl=\"http://go-server-site-url:8153\" secureSiteUrl=\"https://go-server-site-url:8154\" jobTimeout=\"60\" serverId=\"foo\">\n"
+ " </server>"
+ "</cruise>", goConfigService.configFileMd5());
assertThat("Has error: " + configValidity.errorMessage(), configValidity.isValid(), is(true));
CruiseConfig config = goConfigService.getCurrentConfig();
ServerConfig server = config.server();
assertThat(server.getServerId(), is("foo"));
}
@Test
public void shouldMigrateFrom61_MigrateSearchBaseIntoAnElement() throws Exception {
final String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<cruise schemaVersion=\"61\">\n"
+ " <server artifactsdir=\"artifacts\">\n"
+ " <security>"
+ " <ldap uri='some_url' managerDn='some_manager_dn' managerPassword='foo' searchBase='ou=Enterprise,ou=Principal,dc=corporate,dc=thoughtworks,dc=com' searchFilter='(sAMAccountName={0})' />"
+ " </security>"
+ " </server>"
+ " </cruise>";
CruiseConfig config = migrateConfigAndLoadTheNewConfig(content, 61);
LdapConfig ldapConfig = config.server().security().ldapConfig();
assertThat(ldapConfig.isEnabled(), is(false));
SecurityAuthConfig migratedLdapConfig = config.server().security().securityAuthConfigs().get(0);
assertThat(migratedLdapConfig.getId(), is(not(nullValue())));
assertThat(migratedLdapConfig.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(migratedLdapConfig.getProperty("Url").getValue(), is("some_url"));
assertThat(migratedLdapConfig.getProperty("ManagerDN").getValue(), is("some_manager_dn"));
assertThat(migratedLdapConfig.getProperty("Password").getValue(), is("foo"));
assertThat(migratedLdapConfig.getProperty("SearchBases").getValue(), is("ou=Enterprise,ou=Principal,dc=corporate,dc=thoughtworks,dc=com\n"));
assertThat(migratedLdapConfig.getProperty("UserLoginFilter").getValue(), is("(sAMAccountName={0})"));
}
@Test
public void shouldMigrateFrom61_MigrateSearchBaseIntoAnElementAndOnlyOtherNecessaryFields() throws Exception {
final String content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<cruise schemaVersion=\"61\">\n"
+ " <server artifactsdir=\"artifacts\">\n"
+ " <security>"
+ " <ldap uri='some_url' searchBase='ou=Enterprise,ou=Principal,dc=corporate,dc=thoughtworks,dc=com'/>"
+ " </security>"
+ " </server>"
+ " </cruise>";
CruiseConfig config = migrateConfigAndLoadTheNewConfig(content, 61);
LdapConfig ldapConfig = config.server().security().ldapConfig();
assertThat(ldapConfig.isEnabled(), is(false));
SecurityAuthConfig migratedLdapConfig = config.server().security().securityAuthConfigs().get(0);
assertThat(migratedLdapConfig.getId(), is(not(nullValue())));
assertThat(migratedLdapConfig.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(migratedLdapConfig.getProperty("Url").getValue(), is("some_url"));
assertThat(migratedLdapConfig.getProperty("ManagerDN").getValue(), is(""));
assertThat(migratedLdapConfig.getProperty("Password").getValue(), is(""));
assertThat(migratedLdapConfig.getProperty("SearchBases").getValue(), is("ou=Enterprise,ou=Principal,dc=corporate,dc=thoughtworks,dc=com\n"));
assertThat(migratedLdapConfig.getProperty("UserLoginFilter").getValue(), is(""));
}
@Test
public void shouldMigrateFrom62_ToAddOnChangesAttributeToTimerWithDefaultValueOff() throws Exception {
final String oldContent = ConfigFileFixture.configWithPipeline("<pipeline name='old-timer'>"
+ " <timer>0 0 1 * * ?</timer>"
+ " <materials>"
+ " <git url='/tmp/git' />"
+ " </materials>"
+ " <stage name='dist'>"
+ " <jobs>"
+ " <job name='test' />"
+ " </jobs>"
+ " </stage>"
+ "</pipeline>", 62);
CruiseConfig configAfterMigration = migrateConfigAndLoadTheNewConfig(oldContent, 62);
String currentContent = FileUtils.readFileToString(new File(goConfigService.fileLocation()));
PipelineConfig pipelineConfig = configAfterMigration.pipelineConfigByName(new CaseInsensitiveString("old-timer"));
TimerConfig timer = pipelineConfig.getTimer();
assertThat(configAfterMigration.schemaVersion(), is(greaterThan(62)));
assertThat(timer.shouldTriggerOnlyOnChanges(), is(false));
assertThat("Should not have added onChanges since its default value is false.", currentContent, not(containsString("onChanges")));
}
@Test
public void forVersion63_shouldUseOnChangesWhileCreatingTimerConfigWhenItIsTrue() throws Exception {
TimerConfig timer = createTimerConfigWithAttribute("onlyOnChanges='true'");
assertThat(timer.shouldTriggerOnlyOnChanges(), is(true));
}
@Test
public void forVersion63_shouldUseOnChangesWhileCreatingTimerConfigWhenItIsFalse() throws Exception {
TimerConfig timer = createTimerConfigWithAttribute("onlyOnChanges='false'");
assertThat(timer.shouldTriggerOnlyOnChanges(), is(false));
}
@Test
public void forVersion63_shouldSetOnChangesToFalseWhileCreatingTimerConfigWhenTheWholeAttributeIsNotPresent() throws Exception {
TimerConfig timer = createTimerConfigWithAttribute("");
assertThat(timer.shouldTriggerOnlyOnChanges(), is(false));
}
@Test
public void forVersion63_shouldFailWhenOnChangesValueIsEmpty() throws Exception {
try {
createTimerConfigWithAttribute("onlyOnChanges=''");
fail("Didn't get the exception");
} catch (Exception e) {
assertThat(e.getCause().getCause().getMessage(), containsString("'' is not a valid value for 'boolean'"));
}
}
@Test
public void forVersion63_shouldFailWhenOnChangesValueIsNotAValidBooleanValue() throws Exception {
try {
createTimerConfigWithAttribute("onlyOnChanges='junk-non-boolean'");
fail("Didn't get the exception");
} catch (Exception e) {
assertThat(e.getCause().getCause().getMessage(), containsString("'junk-non-boolean' is not a valid value for 'boolean'"));
}
}
@Test
public void shouldValidatePackageRepositoriesConfiguration() throws Exception {
String configString =
"<cruise schemaVersion='66'>"
+ "<repositories>"
+ "<repository id='go-repo' name='go-repo'>"
+ " <pluginConfiguration id='plugin-id' version='1.0'/>"
+ " <configuration>"
+ " <property><key>url</key><value>http://fake-yum-repo</value></property>"
+ " <property><key>username</key><value>godev</value></property>"
+ " <property><key>password</key><value>password</value></property>"
+ " </configuration>"
+ " <packages>"
+ " <package id='go-server' name='go-server'>"
+ " <configuration>"
+ " <property><key>name</key><value>go-server-13.2.0-1-i386</value></property>"
+ " </configuration>"
+ " </package>"
+ " </packages>"
+ "</repository>"
+ "</repositories>"
+ "</cruise>";
CruiseConfig cruiseConfig = migrateConfigAndLoadTheNewConfig(configString, 66);
PackageRepositories packageRepositories = cruiseConfig.getPackageRepositories();
assertThat(packageRepositories.size(), is(1));
assertThat(packageRepositories.get(0).getId(), is("go-repo"));
assertThat(packageRepositories.get(0).getName(), is("go-repo"));
assertThat(packageRepositories.get(0).getPluginConfiguration().getId(), is("plugin-id"));
assertThat(packageRepositories.get(0).getPluginConfiguration().getVersion(), is("1.0"));
assertThat(packageRepositories.get(0).getConfiguration(), is(notNullValue()));
assertThat(packageRepositories.get(0).getPackages().size(), is(1));
assertConfiguration(packageRepositories.get(0).getConfiguration(),
asList(new List[]{asList("url", Boolean.FALSE, "http://fake-yum-repo"), asList("username", Boolean.FALSE, "godev"), asList("password", Boolean.FALSE, "password")}));
assertThat(packageRepositories.get(0).getPackages().get(0).getId(), is("go-server"));
assertThat(packageRepositories.get(0).getPackages().get(0).getName(), is("go-server"));
assertConfiguration(packageRepositories.get(0).getPackages().get(0).getConfiguration(),
asList(new List[]{asList("name", Boolean.FALSE, "go-server-13.2.0-1-i386")}));
}
@Test
public void shouldAllowOnlyRepositoryConfiguration() throws Exception {
String configString =
"<cruise schemaVersion='66'>"
+ "<repositories>"
+ "<repository id='go-repo' name='go-repo'>"
+ " <pluginConfiguration id='plugin-id' version='1.0'/>"
+ " <configuration>"
+ " <property><key>url</key><value>http://fake-yum-repo</value></property>"
+ " <property><key>username</key><value>godev</value></property>"
+ " <property><key>password</key><value>password</value></property>"
+ " </configuration>"
+ "</repository>"
+ "</repositories>"
+ "</cruise>";
CruiseConfig cruiseConfig = loadConfigFileWithContent(configString);
PackageRepositories packageRepositories = cruiseConfig.getPackageRepositories();
assertThat(packageRepositories.size(), is(1));
assertThat(packageRepositories.get(0).getId(), is("go-repo"));
assertThat(packageRepositories.get(0).getName(), is("go-repo"));
assertThat(packageRepositories.get(0).getPluginConfiguration().getId(), is("plugin-id"));
assertThat(packageRepositories.get(0).getPluginConfiguration().getVersion(), is("1.0"));
assertThat(packageRepositories.get(0).getConfiguration(), is(notNullValue()));
assertThat(packageRepositories.get(0).getPackages().size(), is(0));
assertConfiguration(packageRepositories.get(0).getConfiguration(),
asList(new List[]{asList("url", Boolean.FALSE, "http://fake-yum-repo"), asList("username", Boolean.FALSE, "godev"), asList("password", Boolean.FALSE, "password")}));
}
@Test
public void shouldRemoveAllLuauConfigurationFromConfig() throws Exception {
String configString =
"<cruise schemaVersion='66'>"
+ "<server siteUrl='https://hostname'>"
+ "<security>"
+ " <luau url='https://luau.url.com' clientKey='0d010cf97ec505ee3788a9b5b8cf71d482c394ae88d32f0333' authState='authorized' />"
+ " <ldap uri='ldap' managerDn='managerDn' encryptedManagerPassword='+XhtUNvVAxJdHGF4qQGnWw==' searchFilter='(sAMAccountName={0})'>"
+ " <bases>"
+ " <base value='ou=Enterprise,ou=Principal,dc=corporate,dc=thoughtworks,dc=com' />"
+ " </bases>"
+ " </ldap>"
+ " <roles>"
+ " <role name='luau-role'><groups><luauGroup>luau-group</luauGroup></groups></role>"
+ " <role name='ldap-role'><users><user>some-user</user></users></role>"
+ "</roles>"
+ "</security>"
+ "</server>"
+ "</cruise>";
String migratedContent = migrateXmlString(configString, 66);
Document document = new SAXBuilder().build(new StringReader(migratedContent));
assertThat(document.getDescendants(new ElementFilter("luau")).hasNext(), is(false));
assertThat(document.getDescendants(new ElementFilter("groups")).hasNext(), is(false));
}
@Test
public void shouldAddAttributeAutoUpdateOnPackage_AsPartOfMigration68() throws Exception {
String configString =
"<cruise schemaVersion='67'>" +
"<repositories>" +
" <repository id='2ef830d7-dd66-42d6-b393-64a84646e557' name='GoYumRepo'>" +
" <pluginConfiguration id='yum' version='1' />" +
" <configuration>" +
" <property>" +
" <key>REPO_URL</key>" +
" <value>http://random-yum-repo/go/yum/no-arch</value>" +
" </property>" +
" </configuration>" +
" <packages>" +
" <package id='88a3beca-cbe2-4c4d-9744-aa0cda3f371c' name='1'>" +
" <configuration>" +
" <property>" +
" <key>REPO_URL</key>" +
" <value>http://random-yum-repo/go/yum/no-arch</value>" +
" </property>" +
" </configuration>" +
" </package>" +
" </packages>" +
" </repository>" +
"</repositories>" +
"</cruise>";
String migratedContent = migrateXmlString(configString, 67);
GoConfigHolder holder = loader.loadConfigHolder(migratedContent);
PackageRepository packageRepository = holder.config.getPackageRepositories().find("2ef830d7-dd66-42d6-b393-64a84646e557");
PackageDefinition aPackage = packageRepository.findPackage("88a3beca-cbe2-4c4d-9744-aa0cda3f371c");
assertThat(aPackage.isAutoUpdate(), is(true));
}
@Test
public void shouldAllowAuthorizationUnderEachTemplate_asPartOfMigration69() throws Exception {
String configString =
"<cruise schemaVersion='69'>" +
" <templates>" +
" <pipeline name='template-name'>" +
" <authorization>" +
" <admins>" +
" <user>admin1</user>" +
" <user>admin2</user>" +
" </admins>" +
" </authorization>" +
" <stage name='stage-name'>" +
" <jobs>" +
" <job name='job-name'/>" +
" </jobs>" +
" </stage>" +
" </pipeline>" +
" </templates>" +
"</cruise>";
String migratedContent = migrateXmlString(configString, 69);
assertThat(migratedContent, containsString("<authorization>"));
CruiseConfig configForEdit = loader.loadConfigHolder(migratedContent).configForEdit;
PipelineTemplateConfig template = configForEdit.getTemplateByName(new CaseInsensitiveString("template-name"));
Authorization authorization = template.getAuthorization();
assertThat(authorization, is(not(nullValue())));
assertThat(authorization.hasAdminsDefined(), is(true));
assertThat(authorization.getAdminsConfig().getUsers(), hasItems(new AdminUser(new CaseInsensitiveString("admin1")), new AdminUser(new CaseInsensitiveString("admin2"))));
}
@Test
public void shouldAllowPluggableTaskConfiguration_asPartOfMigration70() throws Exception {
String configString =
"<cruise schemaVersion='70'> <pipelines>"
+ "<pipeline name='pipeline1'>"
+ " <materials>"
+ " <svn url='svnurl' username='admin' password='%s'/>"
+ " </materials>"
+ " <stage name='mingle'>"
+ " <jobs>"
+ " <job name='do-something'><tasks>"
+ " <task name='run-curl'>"
+ " <pluginConfiguration id='plugin-id' version='1.0' />"
+ " <configuration>"
+ " <property><key>url</key><value>http://fake-yum-repo</value></property>"
+ " <property><key>username</key><value>godev</value></property>"
+ " <property><key>password</key><value>password</value></property>"
+ " </configuration>"
+ " </task> </tasks>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ "</pipeline></pipelines>"
+ "</cruise>";
CruiseConfig cruiseConfig = loadConfigFileWithContent(configString);
PipelineConfig pipelineConfig = cruiseConfig.getAllPipelineConfigs().get(0);
JobConfig jobConfig = pipelineConfig.getFirstStageConfig().getJobs().get(0);
Tasks tasks = jobConfig.getTasks();
assertThat(tasks.size(),is(1));
assertThat(tasks.get(0) instanceof PluggableTask, is(true));
}
@Test
public void shouldRemoveNameFromPluggableTask_asPartOfMigration71() throws Exception {
String oldConfigWithNameInTask =
"<cruise schemaVersion='70'> <pipelines>"
+ "<pipeline name='pipeline1'>"
+ " <materials>"
+ " <svn url='svnurl' username='admin' password='%s'/>"
+ " </materials>"
+ " <stage name='mingle'>"
+ " <jobs>"
+ " <job name='do-something'><tasks>"
+ " <task name='run-curl'>"
+ " <pluginConfiguration id='plugin-id' version='1.0' />"
+ " <configuration>"
+ " <property><key>url</key><value>http://fake-yum-repo</value></property>"
+ " <property><key>username</key><value>godev</value></property>"
+ " <property><key>password</key><value>password</value></property>"
+ " </configuration>"
+ " </task> </tasks>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ "</pipeline></pipelines>"
+ "</cruise>";
String newConfigWithoutNameInTask = migrateXmlString(oldConfigWithNameInTask, 70);
assertThat(newConfigWithoutNameInTask, not(containsString("<task name")));
assertThat(newConfigWithoutNameInTask, containsString("<task>"));
CruiseConfig cruiseConfig = loadConfigFileWithContent(newConfigWithoutNameInTask);
PipelineConfig pipelineConfig = cruiseConfig.getAllPipelineConfigs().get(0);
JobConfig jobConfig = pipelineConfig.getFirstStageConfig().getJobs().get(0);
Configuration configuration = new Configuration(
create("url", false, "http://fake-yum-repo"),
create("username", false, "godev"),
create("password", false, "password"));
Tasks tasks = jobConfig.getTasks();
assertThat(tasks.size(),is(1));
assertThat(tasks.get(0), is(new PluggableTask(new PluginConfiguration("plugin-id", "1.0"), configuration)));
}
@Test
public void shouldRemoveLicenseSection_asPartOfMigration72() throws Exception {
String licenseUser = "Go UAT ThoughtWorks";
String configWithLicenseSection =
"<cruise schemaVersion='71'>"+
"<server artifactsdir=\"logs\" commandRepositoryLocation=\"default\" serverId=\"dev-id\">" +
" <license user=\"" + licenseUser + "\">kTr+1ZBEr/5EiWlADIM6gUMtedtaLKPh6WRGp/2qISy1QczZpqJP5vmfydvx\n" +
" Hq6o5X+nrb69sGOaBAvmjJ4cZBaIq+/4Yb+ufQCUM2DkacG/BjdEDpIoPHRA\n" +
" fUnmjddxMnVKh2CW7gn7ZnmZUyasS9621UH2uNsfms3gfIK/1PRfbdrFuu5d\n" +
" 6xQEiEhjRVhKGFH4Uq2Cb0BVYCnQ+9eJ7WNwcV4pZCt1AoaMAxo4dox4NLpS\n" +
" pKtgCp1Is/7ui+MGzKEyLCuO/LLMt0ChxWSN62vXiwdW3jl2HCEsLpb70FYR\n" +
" Gj8eif3vuIB2rkOSvLkiAXqDFdEBEmb+GNV3nA4qOw==" +
"</license>\n" +
" </server>" +
"</cruise>";
String migratedContent = migrateXmlString(configWithLicenseSection, 71);
assertThat(migratedContent, not(containsString("license")));
assertThat(migratedContent, not(containsString(licenseUser)));
}
@Test
public void shouldPerformNOOPWhenNoLicenseIsPresent_asPartOfMigration72() throws Exception {
String licenseUser = "Go UAT ThoughtWorks";
String configWithLicenseSection =
"<cruise schemaVersion='71'>"+
"<server artifactsdir=\"logs\" commandRepositoryLocation=\"default\" serverId=\"dev-id\">" +
" </server>" +
"</cruise>";
String migratedContent = migrateXmlString(configWithLicenseSection, 71);
assertThat(migratedContent, not(containsString("license")));
assertThat(migratedContent, not(containsString(licenseUser)));
}
@Test
public void shouldTrimLeadingAndTrailingWhitespaceFromCommands_asPartOfMigration73() throws Exception {
String configXml =
"<cruise schemaVersion='72'>" +
" <pipelines group='first'>" +
" <pipeline name='Test'>" +
" <materials>" +
" <hg url='../manual-testing/ant_hg/dummy' />" +
" </materials>" +
" <stage name='Functional'>" +
" <jobs>" +
" <job name='Functional'>" +
" <tasks>" +
" <exec command=' c:\\program files\\cmd.exe ' args='arguments' />" +
" </tasks>" +
" </job>" +
" </jobs>" +
" </stage>" +
" </pipeline>" +
" </pipelines>" +
"</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 72);
Task task = migratedConfig.tasksForJob("Test", "Functional", "Functional").get(0);
assertThat(task, is(instanceOf(ExecTask.class)));
assertThat(task, is(new ExecTask("c:\\program files\\cmd.exe", "arguments", (String) null)));
}
@Test
public void shouldTrimLeadingAndTrailingWhitespaceFromCommandsInTemplates_asPartOfMigration73() throws Exception {
String configXml =
"<cruise schemaVersion='72'>" +
" <pipelines group='first'>" +
" <pipeline name='Test' template='test_template'>" +
" <materials>" +
" <hg url='../manual-testing/ant_hg/dummy' />" +
" </materials>" +
" </pipeline>" +
" </pipelines>" +
" <templates>" +
" <pipeline name='test_template'>" +
" <stage name='Functional'>" +
" <jobs>" +
" <job name='Functional'>" +
" <tasks>" +
" <exec command=' c:\\program files\\cmd.exe ' args='arguments' />" +
" </tasks>" +
" </job>" +
" </jobs>" +
" </stage>" +
" </pipeline>" +
" </templates>" +
"</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 72);
Task task = migratedConfig.tasksForJob("Test", "Functional", "Functional").get(0);
assertThat(task, is(instanceOf(ExecTask.class)));
assertThat(task, is(new ExecTask("c:\\program files\\cmd.exe", "arguments", (String) null)));
}
@Test
public void shouldNotRemoveNonEmptyUserTags_asPartOfMigration78() throws Exception {
String configXml =
"<cruise schemaVersion='77'>"
+" <pipelines group='first'>"
+" <authorization>"
+" <view>"
+" <user>abc</user>"
+" </view>"
+" </authorization>"
+" <pipeline name='Test' template='test_template'>"
+" <materials>"
+" <hg url='../manual-testing/ant_hg/dummy' />"
+" </materials>"
+" </pipeline>"
+" </pipelines>"
+"</cruise>";
String migratedXml = migrateXmlString(configXml, 77);
assertThat(migratedXml, containsString("<user>"));
}
@Test
public void shouldRemoveEmptyTags_asPartOfMigration78() throws Exception {
String configXml =
"<cruise schemaVersion='77'>"
+" <pipelines group='first'>"
+" <authorization>"
+" <view>"
+" <user>foo</user>"
+" <user />"
+" <user> </user>"
+" </view>"
+" <operate>"
+" <user></user>"
+" </operate>"
+" </authorization>"
+" <pipeline name='Test' template='test_template'>"
+" <materials>"
+" <hg url='../manual-testing/ant_hg/dummy' />"
+" </materials>"
+" </pipeline>"
+" </pipelines>"
+"</cruise>";
String migratedXml = migrateXmlString(configXml, 77);
assertThat(StringUtils.countMatches(migratedXml, "<user>"), is(1));
}
@Test
public void shouldRemoveEmptyTagsRecursively_asPartOfMigration78() throws Exception {
String configXml =
"<cruise schemaVersion='77'>"
+" <pipelines group='first'>"
+" <authorization>"
+" <view>"
+" <user></user>"
+" </view>"
+" </authorization>"
+" <pipeline name='Test' template='test_template'>"
+" <materials>"
+" <hg url='../manual-testing/ant_hg/dummy' />"
+" </materials>"
+" </pipeline>"
+" </pipelines>"
+"</cruise>";
String migratedXml = migrateXmlString(configXml, 77);
assertThat(migratedXml, not(containsString("<user>")));
assertThat(migratedXml, not(containsString("<view>")));
assertThat(migratedXml, not(containsString("<authorization>")));
}
@Test
public void ShouldTrimEnvironmentVariables_asPartOfMigration85() throws Exception {
String configXml = "<cruise schemaVersion='84'>"
+" <pipelines group='first'>"
+" <pipeline name='up42'>"
+" <environmentvariables>"
+" <variable name=\" test \">"
+" <value>foobar</value>"
+" </variable>"
+" <variable name=\" PATH \" secure=\"true\">\n" +
" <encryptedValue>trMHp15AjUE=</encryptedValue>\n" +
" </variable>"
+" </environmentvariables>"
+" <materials>"
+" <hg url='../manual-testing/ant_hg/dummy' />"
+" </materials>"
+ " <stage name='dist'>"
+ " <jobs>"
+ " <job name='test' />"
+ " </jobs>"
+ " </stage>"
+" </pipeline>"
+" </pipelines>"
+"</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 84);
PipelineConfig pipelineConfig = migratedConfig.pipelineConfigByName(new CaseInsensitiveString("up42"));
EnvironmentVariablesConfig variables = pipelineConfig.getVariables();
assertThat(variables.getPlainTextVariables().first().getName(), is("test"));
assertThat(variables.getPlainTextVariables().first().getValue(), is("foobar"));
assertThat(variables.getSecureVariables().first().getName(), is("PATH"));
// encrypted value for "abcd" is "trMHp15AjUE=" for the cipher "269298bc31c44620"
assertThat(variables.getSecureVariables().first().getValue(), is("abcd"));
}
@Test
public void shouldCreateProfilesFromAgentConfig_asPartOfMigration86And87() throws Exception {
String configXml = "<cruise schemaVersion='85'>"
+" <server serverId='dev-id'>"
+" </server>"
+" <pipelines group='first'>"
+" <pipeline name='up42'>"
+" <materials>"
+" <hg url='../manual-testing/ant_hg/dummy' />"
+" </materials>"
+ " <stage name='dist'>"
+ " <jobs>"
+ " <job name='test'>"
+ " <agentConfig pluginId='docker'>"
+ " <property>"
+ " <key>instance-type</key>"
+ " <value>m1.small</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " </pipelines>"
+"</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 85);
PipelineConfig pipelineConfig = migratedConfig.pipelineConfigByName(new CaseInsensitiveString("up42"));
JobConfig jobConfig = pipelineConfig.getStages().get(0).getJobs().get(0);
assertThat(migratedConfig.schemaVersion(), greaterThan(86));
ElasticProfiles profiles = migratedConfig.server().getElasticConfig().getProfiles();
assertThat(profiles.size(), is(1));
ElasticProfile expectedProfile = new ElasticProfile(jobConfig.getElasticProfileId(), "docker",
new ConfigurationProperty(new ConfigurationKey("instance-type"), new ConfigurationValue("m1.small")));
ElasticProfile elasticProfile = profiles.get(0);
assertThat(elasticProfile, is(expectedProfile));
}
@Test
public void shouldCreateProfilesFromMultipleAgentConfigs_asPartOfMigration86And87() throws Exception {
String configXml = "<cruise schemaVersion='85'>"
+" <server serverId='dev-id'>"
+" </server>"
+" <pipelines group='first'>"
+" <pipeline name='up42'>"
+" <materials>"
+" <hg url='../manual-testing/ant_hg/dummy' />"
+" </materials>"
+ " <stage name='dist'>"
+ " <jobs>"
+ " <job name='test1'>"
+ " <agentConfig pluginId='docker'>"
+ " <property>"
+ " <key>instance-type</key>"
+ " <value>m1.small</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " <job name='test2'>"
+ " <agentConfig pluginId='aws'>"
+ " <property>"
+ " <key>ami</key>"
+ " <value>some.ami</value>"
+ " </property>"
+ " <property>"
+ " <key>ram</key>"
+ " <value>1024</value>"
+ " </property>"
+ " <property>"
+ " <key>diskSpace</key>"
+ " <value>10G</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " </pipelines>"
+"</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 85);
PipelineConfig pipelineConfig = migratedConfig.pipelineConfigByName(new CaseInsensitiveString("up42"));
JobConfigs jobs = pipelineConfig.getStages().get(0).getJobs();
ElasticProfiles profiles = migratedConfig.server().getElasticConfig().getProfiles();
assertThat(profiles.size(), is(2));
ElasticProfile expectedDockerProfile = new ElasticProfile(jobs.get(0).getElasticProfileId(), "docker",
new ConfigurationProperty(new ConfigurationKey("instance-type"), new ConfigurationValue("m1.small")));
assertThat(profiles.get(0), is(expectedDockerProfile));
ElasticProfile expectedAWSProfile = new ElasticProfile(jobs.get(1).getElasticProfileId(), "aws",
new ConfigurationProperty(new ConfigurationKey("ami"), new ConfigurationValue("some.ami")),
new ConfigurationProperty(new ConfigurationKey("ram"), new ConfigurationValue("1024")),
new ConfigurationProperty(new ConfigurationKey("diskSpace"), new ConfigurationValue("10G")));
assertThat(profiles.get(1), is(expectedAWSProfile));
}
@Test
public void shouldCreateProfilesFromMultipleAgentConfigsAcrossStages_asPartOfMigration86And87() throws Exception {
String configXml = "<cruise schemaVersion='85'>"
+ " <server serverId='dev-id'>"
+ " </server>"
+ " <pipelines group='first'>"
+ " <pipeline name='up42'>"
+ " <materials>"
+ " <hg url='../manual-testing/ant_hg/dummy' />"
+ " </materials>"
+ " <stage name='build'>"
+ " <jobs>"
+ " <job name='test1'>"
+ " <agentConfig pluginId='docker'>"
+ " <property>"
+ " <key>instance-type</key>"
+ " <value>m1.small</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " <job name='test2'>"
+ " <agentConfig pluginId='aws'>"
+ " <property>"
+ " <key>ami</key>"
+ " <value>some.ami</value>"
+ " </property>"
+ " <property>"
+ " <key>ram</key>"
+ " <value>1024</value>"
+ " </property>"
+ " <property>"
+ " <key>diskSpace</key>"
+ " <value>10G</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " <stage name='dist'>"
+ " <jobs>"
+ " <job name='package'>"
+ " <agentConfig pluginId='docker'>"
+ " <property>"
+ " <key>instance-type</key>"
+ " <value>m1.small</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " </pipelines>"
+ "</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 85);
PipelineConfig pipelineConfig = migratedConfig.pipelineConfigByName(new CaseInsensitiveString("up42"));
JobConfigs buildJobs = pipelineConfig.getStages().get(0).getJobs();
JobConfigs distJobs = pipelineConfig.getStages().get(1).getJobs();
ElasticProfiles profiles = migratedConfig.server().getElasticConfig().getProfiles();
assertThat(profiles.size(), is(3));
ElasticProfile expectedDockerProfile = new ElasticProfile(buildJobs.get(0).getElasticProfileId(), "docker",
new ConfigurationProperty(new ConfigurationKey("instance-type"), new ConfigurationValue("m1.small")));
assertThat(profiles.get(0), is(expectedDockerProfile));
ElasticProfile expectedAWSProfile = new ElasticProfile(buildJobs.get(1).getElasticProfileId(), "aws",
new ConfigurationProperty(new ConfigurationKey("ami"), new ConfigurationValue("some.ami")),
new ConfigurationProperty(new ConfigurationKey("ram"), new ConfigurationValue("1024")),
new ConfigurationProperty(new ConfigurationKey("diskSpace"), new ConfigurationValue("10G")));
assertThat(profiles.get(1), is(expectedAWSProfile));
ElasticProfile expectedSecondDockerProfile = new ElasticProfile(distJobs.get(0).getElasticProfileId(), "docker",
new ConfigurationProperty(new ConfigurationKey("instance-type"), new ConfigurationValue("m1.small")));
assertThat(profiles.get(2), is(expectedSecondDockerProfile));
}
@Test
public void shouldCreateProfilesFromMultipleAgentConfigsAcrossPipelines_asPartOfMigration86And87() throws Exception {
String configXml = "<cruise schemaVersion='85'>"
+ " <server serverId='dev-id'>"
+ " </server>"
+ " <pipelines group='first'>"
+ " <pipeline name='up42'>"
+ " <materials>"
+ " <hg url='../manual-testing/ant_hg/dummy' />"
+ " </materials>"
+ " <stage name='build'>"
+ " <jobs>"
+ " <job name='test1'>"
+ " <agentConfig pluginId='docker'>"
+ " <property>"
+ " <key>instance-type</key>"
+ " <value>m1.small</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " <pipeline name='up43'>"
+ " <materials>"
+ " <hg url='../manual-testing/ant_hg/dummy' />"
+ " </materials>"
+ " <stage name='build'>"
+ " <jobs>"
+ " <job name='test2'>"
+ " <agentConfig pluginId='aws'>"
+ " <property>"
+ " <key>ami</key>"
+ " <value>some.ami</value>"
+ " </property>"
+ " <property>"
+ " <key>ram</key>"
+ " <value>1024</value>"
+ " </property>"
+ " <property>"
+ " <key>diskSpace</key>"
+ " <value>10G</value>"
+ " </property>"
+ " </agentConfig>"
+ " </job>"
+ " </jobs>"
+ " </stage>"
+ " </pipeline>"
+ " </pipelines>"
+ "</cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 85);
PipelineConfig up42 = migratedConfig.pipelineConfigByName(new CaseInsensitiveString("up42"));
PipelineConfig up43 = migratedConfig.pipelineConfigByName(new CaseInsensitiveString("up43"));
JobConfigs up42Jobs = up42.getStages().get(0).getJobs();
JobConfigs up43Jobs = up43.getStages().get(0).getJobs();
ElasticProfiles profiles = migratedConfig.server().getElasticConfig().getProfiles();
assertThat(profiles.size(), is(2));
ElasticProfile expectedDockerProfile = new ElasticProfile(up42Jobs.get(0).getElasticProfileId(), "docker",
new ConfigurationProperty(new ConfigurationKey("instance-type"), new ConfigurationValue("m1.small")));
assertThat(profiles.get(0), is(expectedDockerProfile));
ElasticProfile expectedAWSProfile = new ElasticProfile(up43Jobs.get(0).getElasticProfileId(), "aws",
new ConfigurationProperty(new ConfigurationKey("ami"), new ConfigurationValue("some.ami")),
new ConfigurationProperty(new ConfigurationKey("ram"), new ConfigurationValue("1024")),
new ConfigurationProperty(new ConfigurationKey("diskSpace"), new ConfigurationValue("10G")));
assertThat(profiles.get(1), is(expectedAWSProfile));
}
@Test
public void shouldMigrateLdapToAuthConfigAsPartOfMigration91() throws Exception {
String configXml = "<cruise schemaVersion='90'><server serverId='dev-id'><security>" +
"<ldap uri=\"ldap://ldap.server\" managerDn=\"cn=admin,ou=system,dc=example,dc=com\" encryptedManagerPassword=\""+encryptedPassword+"\" searchFilter=\"(|(sAMAccountName={0})(mail={0}))\">\n" +
" <bases>\n" +
" <base value=\"ou=system\" />\n" +
" <base value=\"ou=employee\" />\n" +
" </bases>\n" +
"</ldap>" +
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(1));
SecurityAuthConfig ldap = migratedConfig.server().security().securityAuthConfigs().get(0);
assertThat(ldap.getId(), is(not(nullValue())));
assertThat(ldap.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(ldap.getProperty("Url").getValue(), is("ldap://ldap.server"));
assertThat(ldap.getProperty("ManagerDN").getValue(), is("cn=admin,ou=system,dc=example,dc=com"));
assertThat(ldap.getProperty("Password").getValue(), is(password));
assertThat(ldap.getProperty("Password").getEncryptedValue(), is(encryptedPassword));
assertThat(ldap.getProperty("SearchBases").getValue(), is("ou=system\nou=employee\n"));
assertThat(ldap.getProperty("UserLoginFilter").getValue(), is("(|(sAMAccountName={0})(mail={0}))"));
}
@Test
public void shouldKeepExistingAuthConfigsWhileMigratingLdapAsPartOfMigration91() throws Exception {
String configXml = "<cruise schemaVersion='90'><server serverId='dev-id'><security>" +
"<ldap uri=\"ldap://ldap.server\" managerDn=\"cn=admin,ou=system,dc=example,dc=com\" encryptedManagerPassword=\"" + encryptedPassword + "\" searchFilter=\"uid\">\n" +
" <bases>\n" +
" <base value=\"ou=system\" />\n" +
" <base value=\"ou=employee\" />\n" +
" </bases>\n" +
"</ldap>" +
"<authConfigs><authConfig id=\"foo\" pluginId=\"cd.go.authentication.passwordfile\"><property><key>PasswordFilePath</key><value>../manual-testing/ant_hg/admins.properties</value></property></authConfig></authConfigs>" +
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(2));
SecurityAuthConfig existingPasswordFile = migratedConfig.server().security().securityAuthConfigs().first();
assertThat(existingPasswordFile.getProperty("PasswordFilePath").getValue(), is("../manual-testing/ant_hg/admins.properties"));
assertThat(existingPasswordFile.getId(), is("foo"));
assertThat(existingPasswordFile.getPluginId(), is("cd.go.authentication.passwordfile"));
SecurityAuthConfig ldap = migratedConfig.server().security().securityAuthConfigs().last();
assertThat(ldap.getId(), is(not(nullValue())));
assertThat(ldap.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(ldap.getProperty("Url").getValue(), is("ldap://ldap.server"));
assertThat(ldap.getProperty("ManagerDN").getValue(), is("cn=admin,ou=system,dc=example,dc=com"));
assertThat(ldap.getProperty("Password").getValue(), is(password));
assertThat(ldap.getProperty("Password").getEncryptedValue(), is(encryptedPassword));
assertThat(ldap.getProperty("SearchBases").getValue(), is("ou=system\nou=employee\n"));
assertThat(ldap.getProperty("UserLoginFilter").getValue(), is("uid"));
}
@Test
public void migrationShouldNotChangeOtherSecurityConfigAsPartOfMigration91() throws Exception {
String configXml = "<cruise schemaVersion='90'><server serverId='dev-id'><security>" +
"<ldap uri=\"ldap://ldap.server\" managerDn=\"cn=admin,ou=system,dc=example,dc=com\" encryptedManagerPassword=\"" + encryptedPassword + "\" searchFilter=\"uid\">\n" +
" <bases>\n" +
" <base value=\"ou=system\" />\n" +
" <base value=\"ou=employee\" />\n" +
" </bases>\n" +
"</ldap>" +
"<roles><role name=\"admin\"/></roles>" +
"<admins><user>bob</user></admins>" +
"</security></server></cruise>";
final CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
final SecurityConfig securityConfig = migratedConfig.server().security();
assertThat(securityConfig.securityAuthConfigs(), hasSize(1));
SecurityAuthConfig ldap = migratedConfig.server().security().securityAuthConfigs().get(0);
assertThat(ldap.getId(), is(not(nullValue())));
assertThat(ldap.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(ldap.getProperty("Url").getValue(), is("ldap://ldap.server"));
assertThat(ldap.getProperty("ManagerDN").getValue(), is("cn=admin,ou=system,dc=example,dc=com"));
assertThat(ldap.getProperty("Password").getValue(), is(password));
assertThat(ldap.getProperty("Password").getEncryptedValue(), is(encryptedPassword));
assertThat(ldap.getProperty("SearchBases").getValue(), is("ou=system\nou=employee\n"));
assertThat(ldap.getProperty("UserLoginFilter").getValue(), is("uid"));
assertThat(securityConfig.getRoles(), hasItem(new RoleConfig(new CaseInsensitiveString("admin"))));
assertThat(securityConfig.adminsConfig(), hasItem(new AdminUser(new CaseInsensitiveString("bob"))));
}
@Test
public void shouldNotConflictWithAnExistingLdapPluginConfigAfterMigration91() throws Exception {
String configXml = "<cruise schemaVersion='90'><server serverId='dev-id'><security>" +
"<ldap uri=\"ldap://ldap.server.1\" managerDn=\"cn=admin,ou=system,dc=example,dc=com\" encryptedManagerPassword=\"" + encryptedPassword + "\" searchFilter=\"(|(sAMAccountName={0})(mail={0}))\">\n" +
" <bases>\n" +
" <base value=\"ou=system\" />\n" +
" <base value=\"ou=employee\" />\n" +
" </bases>\n" +
"</ldap>" +
"<authConfigs>" +
"<authConfig id=\"ldap\" pluginId=\"cd.go.authentication.ldap\">\n" +
" <property>\n" +
" <key>Url</key>\n" +
" <value>ldap://ldap.server.2</value>\n" +
" </property>\n" +
" <property>\n" +
" <key>ManagerDN</key>\n" +
" <value>cn=admin,ou=system,dc=example,dc=com</value>\n" +
" </property>\n" +
" <property>\n" +
" <key>SearchBases</key>\n" +
" <value>ou=system\n" +
"ou=employee</value>\n" +
" </property>\n" +
" <property>\n" +
" <key>UserLoginFilter</key>\n" +
" <value>uid</value>\n" +
" </property>\n" +
" <property>\n" +
" <key>Password</key>\n" +
" <value>y10CG/z7QBs=</value>\n" +
" </property>\n" +
" </authConfig>\n" +
"</authConfigs>" +
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(2));
SecurityAuthConfig existingLdapPluginProfile = migratedConfig.server().security().securityAuthConfigs().get(0);
assertThat(existingLdapPluginProfile.getId(), is("ldap"));
assertThat(existingLdapPluginProfile.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(existingLdapPluginProfile.getProperty("Url").getValue(), is("ldap://ldap.server.2"));
assertThat(existingLdapPluginProfile.getProperty("ManagerDN").getValue(), is("cn=admin,ou=system,dc=example,dc=com"));
assertThat(existingLdapPluginProfile.getProperty("Password").getValue(), is("y10CG/z7QBs="));
assertThat(existingLdapPluginProfile.getProperty("SearchBases").getValue(), is("ou=system\nou=employee"));
assertThat(existingLdapPluginProfile.getProperty("UserLoginFilter").getValue(), is("uid"));
SecurityAuthConfig ldapConfigMigratedToAuthConfig = migratedConfig.server().security().securityAuthConfigs().get(1);
assertThat(ldapConfigMigratedToAuthConfig.getId(), is(not(nullValue())));
assertThat(ldapConfigMigratedToAuthConfig.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("Url").getValue(), is("ldap://ldap.server.1"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("ManagerDN").getValue(), is("cn=admin,ou=system,dc=example,dc=com"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("Password").getValue(), is(password));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("Password").getEncryptedValue(), is(encryptedPassword));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("SearchBases").getValue(), is("ou=system\nou=employee\n"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("UserLoginFilter").getValue(), is("(|(sAMAccountName={0})(mail={0}))"));
}
@Test
public void shouldMigrateLdapManagerPasswordWithNewlineAndSpaces_XslMigrationFrom88To91() throws Exception {
int fromVersion = 88;
String encryptedValueWithWhitespaceAndNewline = new StringBuilder(encryptedPassword).insert(2, "\r\n" +
" ").toString();
String content = ConfigFileFixture.config(
"<server artifactsdir='artifacts'>\n" +
"<security>\n" +
" <ldap uri='url' managerDn='manager-dn' encryptedManagerPassword='"+encryptedValueWithWhitespaceAndNewline+"'>\n" +
" <bases>\n" +
" <base value='base' />\n" +
" </bases>\n" +
" </ldap>\n" +
" </security>" +
" </server>", fromVersion);
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(content, fromVersion);
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
SecurityAuthConfig ldapConfigMigratedToAuthConfig = migratedConfig.server().security().securityAuthConfigs().get(0);
assertThat(ldapConfigMigratedToAuthConfig.getId(), is(not(nullValue())));
assertThat(ldapConfigMigratedToAuthConfig.getPluginId(), is("cd.go.authentication.ldap"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("Url").getValue(), is("url"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("ManagerDN").getValue(), is("manager-dn"));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("Password").getValue(), is(password));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("Password").getEncryptedValue(), is(encryptedPassword));
assertThat(ldapConfigMigratedToAuthConfig.getProperty("SearchBases").getValue(), is("base\n"));
}
@Test
public void shouldMigrateInbuiltPasswordFileToAuthConfigAsPartOfMigration92() throws Exception {
String configXml = "<cruise schemaVersion='90'><server><security>" +
"<passwordFile path=\"../path/to/password_file.properties\" />"+
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 91);
assertThat(migratedConfig.server().security().passwordFileConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(1));
SecurityAuthConfig passwordFileAuthConfig = migratedConfig.server().security().securityAuthConfigs().get(0);
assertThat(passwordFileAuthConfig.getId(), is(not(nullValue())));
assertThat(passwordFileAuthConfig.getPluginId(), is("cd.go.authentication.passwordfile"));
assertThat(passwordFileAuthConfig.getProperty("PasswordFilePath").getValue(), is("../path/to/password_file.properties"));
}
@Test
public void shouldKeepExistingAuthConfigsWhileMigratingPasswordFileAsPartOfMigration92() throws Exception {
String configXml = "<cruise schemaVersion='90'><server><security>" +
"<passwordFile path=\"../path/to/password_file.properties\" />"+
"<authConfigs><authConfig id=\"foo\" pluginId=\"cd.go.authentication.passwordfile\"><property><key>PasswordFilePath</key><value>../manual-testing/ant_hg/admins.properties</value></property></authConfig></authConfigs>" +
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().passwordFileConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(2));
SecurityAuthConfig existingPasswordFile = migratedConfig.server().security().securityAuthConfigs().first();
assertThat(existingPasswordFile.getProperty("PasswordFilePath").getValue(), is("../manual-testing/ant_hg/admins.properties"));
assertThat(existingPasswordFile.getId(), is("foo"));
assertThat(existingPasswordFile.getPluginId(), is("cd.go.authentication.passwordfile"));
SecurityAuthConfig migratedPasswordFileAuthConfig = migratedConfig.server().security().securityAuthConfigs().last();
assertThat(migratedPasswordFileAuthConfig.getId(), is(not(nullValue())));
assertThat(migratedPasswordFileAuthConfig.getPluginId(), is("cd.go.authentication.passwordfile"));
assertThat(migratedPasswordFileAuthConfig.getProperty("PasswordFilePath").getValue(), is("../path/to/password_file.properties"));
}
@Test
public void shouldNotChangeOtherSecurityConfigAsPartOfMigration92() throws Exception {
String configXml = "<cruise schemaVersion='90'><server serverId='dev-id'><security>" +
"<passwordFile path=\"../path/to/password_file.properties\" />"+
"<roles><role name=\"admin\"/></roles>" +
"<admins><user>bob</user></admins>" +
"</security></server></cruise>";
final CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().passwordFileConfig().isEnabled(), is(false));
final SecurityConfig securityConfig = migratedConfig.server().security();
assertThat(securityConfig.securityAuthConfigs(), hasSize(1));
SecurityAuthConfig migratedPasswordFileAuthConfig = migratedConfig.server().security().securityAuthConfigs().first();
assertThat(migratedPasswordFileAuthConfig.getId(), is(not(nullValue())));
assertThat(migratedPasswordFileAuthConfig.getPluginId(), is("cd.go.authentication.passwordfile"));
assertThat(migratedPasswordFileAuthConfig.getProperty("PasswordFilePath").getValue(), is("../path/to/password_file.properties"));
assertThat(securityConfig.getRoles(), hasItem(new RoleConfig(new CaseInsensitiveString("admin"))));
assertThat(securityConfig.adminsConfig(), hasItem(new AdminUser(new CaseInsensitiveString("bob"))));
}
@Test
public void shouldNotConflictWithAnExistingPasswordFilePluginConfigAfterMigration92() throws Exception {
String configXml = "<cruise schemaVersion='90'><server serverId='dev-id'><security>" +
"<passwordFile path=\"../path/to/password_file.properties\" />"+
"<authConfigs>" +
"<authConfig id=\"passwordFile\" pluginId=\"cd.go.authentication.passwordfile\">" +
"<property><key>PasswordFilePath</key><value>../manual-testing/ant_hg/admins.properties</value></property>" +
"</authConfig>" +
"</authConfigs>" +
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(2));
SecurityAuthConfig existingPasswordFile = migratedConfig.server().security().securityAuthConfigs().first();
assertThat(existingPasswordFile.getProperty("PasswordFilePath").getValue(), is("../manual-testing/ant_hg/admins.properties"));
assertThat(existingPasswordFile.getId(), is("passwordFile"));
assertThat(existingPasswordFile.getPluginId(), is("cd.go.authentication.passwordfile"));
SecurityAuthConfig migratedPasswordFileAuthConfig = migratedConfig.server().security().securityAuthConfigs().last();
assertThat(migratedPasswordFileAuthConfig.getId(), is(not(nullValue())));
assertThat(migratedPasswordFileAuthConfig.getPluginId(), is("cd.go.authentication.passwordfile"));
assertThat(migratedPasswordFileAuthConfig.getProperty("PasswordFilePath").getValue(), is("../path/to/password_file.properties"));
}
@Test
public void shouldGenerateUniqueNamesForBothLdapAndPasswordFileAuthConfigDuringMigration() throws Exception {
String configXml = "<cruise schemaVersion='90'><server><security>" +
"<passwordFile path=\"../path/to/password_file.properties\" />"+
"<ldap uri=\"ldap://ldap.server.1\" managerDn=\"cn=admin,ou=system,dc=example,dc=com\" encryptedManagerPassword=\"" + encryptedPassword + "\" searchFilter=\"(|(sAMAccountName={0})(mail={0}))\">\n" +
" <bases>\n" +
" <base value=\"ou=system\" />\n" +
" <base value=\"ou=employee\" />\n" +
" </bases>\n" +
"</ldap>" +
"</security></server></cruise>";
CruiseConfig migratedConfig = migrateConfigAndLoadTheNewConfig(configXml, 90);
assertThat(migratedConfig.server().security().passwordFileConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().ldapConfig().isEnabled(), is(false));
assertThat(migratedConfig.server().security().securityAuthConfigs(), hasSize(2));
SecurityAuthConfig passwordFileAuthConfig = migratedConfig.server().security().securityAuthConfigs().get(0);
SecurityAuthConfig ldapAuthConfig = migratedConfig.server().security().securityAuthConfigs().get(1);
assertThat(passwordFileAuthConfig.getId(), is(not(ldapAuthConfig.getId())));
}
private void assertStringsIgnoringCarriageReturnAreEqual(String expected, String actual) {
assertEquals(expected.replaceAll("\\r", ""), actual.replaceAll("\\r", ""));
}
private TimerConfig createTimerConfigWithAttribute(String valueForOnChangesInTimer) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
final String content = ConfigFileFixture.configWithPipeline("<pipeline name='old-timer'>"
+ " <timer " + valueForOnChangesInTimer + ">0 0 1 * * ?</timer>"
+ " <materials>"
+ " <git url='/tmp/git' />"
+ " </materials>"
+ " <stage name='dist'>"
+ " <jobs>"
+ " <job name='test' />"
+ " </jobs>"
+ " </stage>"
+ "</pipeline>", 63);
CruiseConfig configAfterMigration = migrateConfigAndLoadTheNewConfig(content, 63);
PipelineConfig pipelineConfig = configAfterMigration.pipelineConfigByName(new CaseInsensitiveString("old-timer"));
return pipelineConfig.getTimer();
}
private File[] configFiles() {
return configFile.getParentFile().listFiles(new FilenameFilter() {
public boolean accept(File file, String name) {
return name.startsWith("cruise-config.xml.");
}
}
);
}
private CruiseConfig migrateConfigAndLoadTheNewConfig(String content, int fromVersion) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
String migratedContent = migrateXmlString(content, fromVersion);
GoConfigService.XmlPartialSaver fileSaver = goConfigService.fileSaver(true);
GoConfigValidity configValidity = fileSaver.saveXml(migratedContent, goConfigService.configFileMd5());
assertThat(configValidity.errorMessage(), configValidity.isValid(), is(true));
return goConfigService.getCurrentConfig();
}
private String migrateXmlString(String content, int fromVersion) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
return migrateXmlString(content, fromVersion, GoConfigSchema.currentSchemaVersion());
}
private String migrateXmlString(String content, int fromVersion, int toVersion) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
final List<Exception> exs = new ArrayList<>();
GoConfigMigration upgrader = new GoConfigMigration(
new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
e.printStackTrace();
exs.add(e);
}
}, configRepository, new TimeProvider(), configCache, ConfigElementImplementationRegistryMother.withNoPlugins()
);
Method upgrade = upgrader.getClass().getDeclaredMethod("upgrade", String.class, Integer.TYPE, Integer.TYPE);
upgrade.setAccessible(true);
return (String) upgrade.invoke(upgrader, content, fromVersion, toVersion);
}
private CruiseConfig loadConfigFileWithContent(String content) throws Exception {
FileUtil.writeContentToFile(content, configFile);
return loadWithMigration(configFile).config;
}
private GoConfigHolder loadWithMigration(final File configFile) throws Exception {
GoConfigMigration migration = new GoConfigMigration(new GoConfigMigration.UpgradeFailedHandler() {
public void handle(Exception e) {
String content = "";
try {
content = FileUtil.readContentFromFile(configFile);
} catch (IOException e1) {
}
throw bomb(e.getMessage() + ": content=\n" + content, e);
}
}, configRepository, new TimeProvider(), configCache, registry
);
SystemEnvironment sysEnv = new SystemEnvironment();
FullConfigSaveNormalFlow normalFlow = new FullConfigSaveNormalFlow(configCache, registry, sysEnv, serverVersion, new TimeProvider(), configRepository, cachedGoPartials);
GoFileConfigDataSource configDataSource = new GoFileConfigDataSource(migration, configRepository, sysEnv, new TimeProvider(), configCache, serverVersion,
registry, serverHealthService, cachedGoPartials, null, normalFlow);
configDataSource.upgradeIfNecessary();
return configDataSource.forceLoad(configFile);
}
public void assertConfiguration(Configuration configuration, List<List> expectedKeyValuePair) {
int position = 0;
for (ConfigurationProperty configurationProperty : configuration) {
assertThat(configurationProperty.getConfigurationKey().getName(), is(expectedKeyValuePair.get(position).get(0)));
assertThat(configurationProperty.isSecure(), is(expectedKeyValuePair.get(position).get(1)));
assertThat(configurationProperty.getConfigurationValue().getValue(), is(expectedKeyValuePair.get(position).get(2)));
position++;
}
}
}