/* * 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.domain.packagerepository; import java.util.HashMap; import java.util.Map; import com.thoughtworks.go.config.BasicCruiseConfig; import com.thoughtworks.go.config.ConfigSaveValidationContext; import com.thoughtworks.go.config.helper.ConfigurationHolder; import com.thoughtworks.go.config.materials.AbstractMaterial; import com.thoughtworks.go.config.materials.AbstractMaterialConfig; import com.thoughtworks.go.domain.config.PluginConfiguration; import com.thoughtworks.go.domain.config.Configuration; import com.thoughtworks.go.domain.config.ConfigurationKey; import com.thoughtworks.go.domain.config.ConfigurationProperty; import com.thoughtworks.go.domain.config.ConfigurationValue; import com.thoughtworks.go.domain.config.EncryptedConfigurationValue; import com.thoughtworks.go.domain.config.RepositoryMetadataStoreHelper; import com.thoughtworks.go.security.GoCipher; import com.thoughtworks.go.util.CachedDigestUtils; import com.thoughtworks.go.plugin.access.packagematerial.PackageMetadataStore; import com.thoughtworks.go.plugin.access.packagematerial.RepositoryMetadataStore; import com.thoughtworks.go.plugin.access.packagematerial.PackageConfiguration; import com.thoughtworks.go.plugin.access.packagematerial.PackageConfigurations; import org.junit.After; import org.junit.Before; import org.junit.Test; import static com.thoughtworks.go.domain.packagerepository.ConfigurationPropertyMother.create; import static java.util.Arrays.asList; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; public class PackageDefinitionTest extends PackageMaterialTestBase { @Before public void setup() { RepositoryMetadataStoreHelper.clear(); } @After public void teardown() { RepositoryMetadataStoreHelper.clear(); } @Test public void shouldCheckForEqualityOfPackageDefinition() { Configuration configuration = new Configuration(); PackageDefinition packageDefinition = new PackageDefinition("id", "name", configuration); assertThat(packageDefinition, is(new PackageDefinition("id", "name", configuration))); } @Test public void shouldOnlyDisplayFieldsWhichAreNonSecureAndPartOfIdentityInGetConfigForDisplayWhenPluginExists() { String pluginId = "plugin-id"; PackageConfigurations repositoryConfigurations = new PackageConfigurations(); repositoryConfigurations.add(new PackageConfiguration("rk1", "rv1").with(PackageConfiguration.PART_OF_IDENTITY, true).with(PackageConfiguration.SECURE, false)); repositoryConfigurations.add(new PackageConfiguration("rk2", "rv2").with(PackageConfiguration.PART_OF_IDENTITY, false).with(PackageConfiguration.SECURE, false)); repositoryConfigurations.add(new PackageConfiguration("rk3", "rv3").with(PackageConfiguration.PART_OF_IDENTITY, true).with(PackageConfiguration.SECURE, true)); RepositoryMetadataStore.getInstance().addMetadataFor(pluginId, repositoryConfigurations); PackageConfigurations packageConfigurations = new PackageConfigurations(); packageConfigurations.add(new PackageConfiguration("pk1", "pv1").with(PackageConfiguration.PART_OF_IDENTITY, true).with(PackageConfiguration.SECURE, false)); packageConfigurations.add(new PackageConfiguration("pk2", "pv2").with(PackageConfiguration.PART_OF_IDENTITY, false).with(PackageConfiguration.SECURE, false)); packageConfigurations.add(new PackageConfiguration("pk3", "pv3").with(PackageConfiguration.PART_OF_IDENTITY, true).with(PackageConfiguration.SECURE, true)); packageConfigurations.add(new PackageConfiguration("pk4", "pv4").with(PackageConfiguration.PART_OF_IDENTITY, false).with(PackageConfiguration.SECURE, true)); packageConfigurations.add(new PackageConfiguration("pk5", "pv5").with(PackageConfiguration.PART_OF_IDENTITY, true).with(PackageConfiguration.SECURE, false)); PackageMetadataStore.getInstance().addMetadataFor(pluginId, packageConfigurations); PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", pluginId, "version", new Configuration(create("rk1", false, "rv1"), create("rk2", false, "rv2"), create("rk3", true, "rv3"))); Configuration packageConfig = new Configuration(create("pk1", false, "pv1"), create("pk2", false, "pv2"), create("pk3", true, "pv3"), create("pk4", true, "pv4"), create("pk5", false, "pv5")); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", packageConfig, repository); packageDefinition.setRepository(repository); assertThat(packageDefinition.getConfigForDisplay(), is("Repository: [rk1=rv1] - Package: [pk1=pv1, pk5=pv5]")); } @Test public void shouldDisplayAllNonSecureFieldsInGetConfigForDisplayWhenPluginDoesNotExist() { PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", "some-plugin-which-does-not-exist", "version", new Configuration(create("rk1", false, "rv1"), create("rk2", true, "rv2"))); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", new Configuration(create("pk1", false, "pv1"), create("pk2", true, "pv2"), create("pk3", false, "pv3")), repository); packageDefinition.setRepository(repository); assertThat(packageDefinition.getConfigForDisplay(), is("WARNING! Plugin missing for Repository: [rk1=rv1] - Package: [pk1=pv1, pk3=pv3]")); } @Test public void shouldConvertKeysToLowercaseInGetConfigForDisplay() throws Exception { RepositoryMetadataStore.getInstance().addMetadataFor("some-plugin", new PackageConfigurations()); PackageMetadataStore.getInstance().addMetadataFor("some-plugin", new PackageConfigurations()); PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", "some-plugin", "version", new Configuration(create("rk1", false, "rv1"))); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", new Configuration(create("pack_key_1", false, "pack_value_1"), create("PACK_KEY_2", false, "PACK_VALUE_2"), create("pacK_KeY3", false, "pacKValue_3")), repository); packageDefinition.setRepository(repository); assertThat(packageDefinition.getConfigForDisplay(), is("Repository: [rk1=rv1] - Package: [pack_key_1=pack_value_1, pack_key_2=PACK_VALUE_2, pack_key3=pacKValue_3]")); } @Test public void shouldNotDisplayEmptyValuesInGetConfigForDisplay() throws Exception { RepositoryMetadataStore.getInstance().addMetadataFor("some-plugin", new PackageConfigurations()); PackageMetadataStore.getInstance().addMetadataFor("some-plugin", new PackageConfigurations()); PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", "some-plugin", "version", new Configuration(create("rk1", false, "rv1"))); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", new Configuration(create("pk1", false, ""), create("pk2", false, "pack_value_2"), create("pk3", false, null)), repository); packageDefinition.setRepository(repository); assertThat(packageDefinition.getConfigForDisplay(), is("Repository: [rk1=rv1] - Package: [pk2=pack_value_2]")); } @Test public void shouldGetFingerprint() { String pluginId = "pluginid"; PackageConfigurations repositoryConfigurations = new PackageConfigurations(); repositoryConfigurations.add(new PackageConfiguration("k1", "v1").with(PackageConfiguration.PART_OF_IDENTITY, true)); RepositoryMetadataStore.getInstance().addMetadataFor(pluginId, repositoryConfigurations); PackageConfigurations packageConfigurations = new PackageConfigurations(); packageConfigurations.add(new PackageConfiguration("k2", "v2").with(PackageConfiguration.PART_OF_IDENTITY, true)); PackageMetadataStore.getInstance().addMetadataFor(pluginId, packageConfigurations); PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", pluginId, "version", new Configuration(create("k1", false, "v1"))); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", new Configuration(create("k2", false, "v2")), repository); String fingerprint = packageDefinition.getFingerprint(AbstractMaterial.FINGERPRINT_DELIMITER); assertThat(fingerprint, is(CachedDigestUtils.sha256Hex("plugin-id=pluginid<|>k2=v2<|>k1=v1"))); } @Test public void shouldNotConsiderPropertiesMarkedAsNotPartOfIdentity_GetFingerprint() { String pluginId = "plugin-id"; PackageConfigurations repositoryConfigurations = new PackageConfigurations(); repositoryConfigurations.add(new PackageConfiguration("rk1", "rv1").with(PackageConfiguration.PART_OF_IDENTITY, true)); repositoryConfigurations.add(new PackageConfiguration("rk2", "rv2").with(PackageConfiguration.PART_OF_IDENTITY, false)); RepositoryMetadataStore.getInstance().addMetadataFor(pluginId, repositoryConfigurations); PackageConfigurations packageConfigurations = new PackageConfigurations(); packageConfigurations.add(new PackageConfiguration("pk1", "pv1").with(PackageConfiguration.PART_OF_IDENTITY, false)); packageConfigurations.add(new PackageConfiguration("pk2", "pv2").with(PackageConfiguration.PART_OF_IDENTITY, true)); PackageMetadataStore.getInstance().addMetadataFor(pluginId, packageConfigurations); PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", pluginId, "version", new Configuration(create("rk1", false, "rv1"), create("rk2", false, "rv2"))); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", new Configuration(create("pk1", false, "pv1"), create("pk2", false, "pv2")), repository); String fingerprint = packageDefinition.getFingerprint(AbstractMaterial.FINGERPRINT_DELIMITER); assertThat(fingerprint, is(CachedDigestUtils.sha256Hex("plugin-id=plugin-id<|>pk2=pv2<|>rk1=rv1"))); } @Test public void shouldNotConsiderAllPropertiesForFingerprintWhenMetadataIsNotAvailable() { String pluginId = "plugin-id"; PackageRepository repository = PackageRepositoryMother.create("repo-id", "repo", pluginId, "version", new Configuration(create("rk1", false, "rv1"), create("rk2", false, "rv2"))); PackageDefinition packageDefinition = PackageDefinitionMother.create("p-id", "name", new Configuration(create("pk1", false, "pv1"), create("pk2", false, "pv2")), repository); String fingerprint = packageDefinition.getFingerprint(AbstractMaterial.FINGERPRINT_DELIMITER); assertThat(fingerprint, is(CachedDigestUtils.sha256Hex("plugin-id=plugin-id<|>pk1=pv1<|>pk2=pv2<|>rk1=rv1<|>rk2=rv2"))); } @Test public void shouldMakeConfigurationSecureBasedOnMetadata() throws Exception { /*secure property is set based on metadata*/ ConfigurationProperty secureProperty = new ConfigurationProperty(new ConfigurationKey("key1"), new ConfigurationValue("value1"), null, new GoCipher()); ConfigurationProperty nonSecureProperty = new ConfigurationProperty(new ConfigurationKey("key2"), new ConfigurationValue("value2"), null, new GoCipher()); PackageDefinition packageDefinition = new PackageDefinition("go", "name", new Configuration(secureProperty, nonSecureProperty)); PackageRepository packageRepository = new PackageRepository(); packageRepository.setPluginConfiguration(new PluginConfiguration("plugin-id", "1.0")); packageDefinition.setRepository(packageRepository); PackageConfigurations packageConfigurations = new PackageConfigurations(); packageConfigurations.addConfiguration(new PackageConfiguration("key1").with(PackageConfiguration.SECURE, true)); packageConfigurations.addConfiguration(new PackageConfiguration("key2").with(PackageConfiguration.SECURE, false)); PackageMetadataStore.getInstance().addMetadataFor("plugin-id", packageConfigurations); packageDefinition.applyPackagePluginMetadata("plugin-id"); assertThat(secureProperty.isSecure(), is(true)); assertThat(nonSecureProperty.isSecure(), is(false)); } @Test public void shouldSetConfigAttributes() throws Exception { PackageDefinition definition = new PackageDefinition(); String pluginId = "plugin"; Map config = createPackageDefinitionConfiguration("package-name", pluginId, new ConfigurationHolder("key1", "value1"), new ConfigurationHolder("key2", "value2", "encrypted-value", true, "1"), new ConfigurationHolder("key3", "test", "encrypted-value", true, "0")); PackageConfigurations metadata = new PackageConfigurations(); metadata.addConfiguration(new PackageConfiguration("key1")); metadata.addConfiguration(new PackageConfiguration("key2").with(PackageConfiguration.SECURE, true)); metadata.addConfiguration(new PackageConfiguration("key3").with(PackageConfiguration.SECURE, true)); PackageMetadataStore.getInstance().addMetadataFor(pluginId, metadata); definition.setRepository(PackageRepositoryMother.create("1")); definition.setConfigAttributes(config); String encryptedValue = new GoCipher().encrypt("value2"); assertThat(definition.getName(), is("package-name")); assertThat(definition.getConfiguration().size(), is(3)); assertThat(definition.getConfiguration().getProperty("key1").getConfigurationValue().getValue(), is("value1")); assertThat(definition.getConfiguration().getProperty("key1").getEncryptedConfigurationValue(), is(nullValue())); assertThat(definition.getConfiguration().getProperty("key2").getEncryptedValue(), is(encryptedValue)); assertThat(definition.getConfiguration().getProperty("key2").getConfigurationValue(), is(nullValue())); assertThat(definition.getConfiguration().getProperty("key3").getEncryptedValue(), is("encrypted-value")); assertThat(definition.getConfiguration().getProperty("key3").getConfigurationValue(), is(nullValue())); } @Test public void shouldValidateIfNameIsMissing() { PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.validate(new ConfigSaveValidationContext(new BasicCruiseConfig(), null)); assertThat(packageDefinition.errors().isEmpty(), is(false)); assertThat(packageDefinition.errors().getAllOn("name"), is(asList("Package name is mandatory"))); } @Test public void shouldAddErrorToGivenKey() throws Exception { PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.addError("field", "error message"); assertThat(packageDefinition.errors().getAllOn("field").contains("error message"), is(true)); } @Test public void shouldClearConfigurationsWhichAreEmptyAndNoErrors() throws Exception { PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.getConfiguration().add(new ConfigurationProperty(new ConfigurationKey("name-one"), new ConfigurationValue())); packageDefinition.getConfiguration().add(new ConfigurationProperty(new ConfigurationKey("name-two"), new EncryptedConfigurationValue())); packageDefinition.getConfiguration().add(new ConfigurationProperty(new ConfigurationKey("name-three"), null, new EncryptedConfigurationValue(), null)); ConfigurationProperty configurationProperty = new ConfigurationProperty(new ConfigurationKey("name-four"), null, new EncryptedConfigurationValue(), null); configurationProperty.addErrorAgainstConfigurationValue("error"); packageDefinition.getConfiguration().add(configurationProperty); packageDefinition.clearEmptyConfigurations(); assertThat(packageDefinition.getConfiguration().size(), is(1)); assertThat(packageDefinition.getConfiguration().get(0).getConfigurationKey().getName(), is("name-four")); } @Test public void shouldValidateName() throws Exception { PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.setName("some name"); packageDefinition.validate(new ConfigSaveValidationContext(null)); assertThat(packageDefinition.errors().isEmpty(), is(false)); assertThat(packageDefinition.errors().getAllOn(PackageDefinition.NAME).get(0), is("Invalid Package name 'some name'. This must be alphanumeric and can contain underscores and periods (however, it cannot start with a period). The maximum allowed length is 255 characters.")); } @Test public void shouldSetAutoUpdateValue() throws Exception { PackageDefinition aPackage = new PackageDefinition(); assertThat(aPackage.isAutoUpdate(), is(true)); aPackage.setAutoUpdate(false); assertThat(aPackage.isAutoUpdate(), is(false)); } @Test public void shouldValidateUniqueNames() { PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.setName("PKG"); HashMap<String, PackageDefinition> nameMap = new HashMap<>(); PackageDefinition original = new PackageDefinition(); original.setName("pkg"); nameMap.put("pkg", original); packageDefinition.validateNameUniqueness(nameMap); assertThat(packageDefinition.errors().isEmpty(), is(false)); assertThat( packageDefinition.errors().getAllOn(PackageDefinition.NAME).contains( "You have defined multiple packages called 'PKG'. Package names are case-insensitive and must be unique within a repository."), is(true)); } @Test public void shouldValidateUniqueKeysInConfiguration() { ConfigurationProperty one = new ConfigurationProperty(new ConfigurationKey("one"), new ConfigurationValue("value1")); ConfigurationProperty duplicate1 = new ConfigurationProperty(new ConfigurationKey("ONE"), new ConfigurationValue("value2")); ConfigurationProperty duplicate2 = new ConfigurationProperty(new ConfigurationKey("ONE"), new ConfigurationValue("value3")); ConfigurationProperty two = new ConfigurationProperty(new ConfigurationKey("two"), new ConfigurationValue()); PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.setConfiguration(new Configuration(one, duplicate1, duplicate2, two)); packageDefinition.setName("go-server"); packageDefinition.validate(null); assertThat(one.errors().isEmpty(), is(false)); assertThat(one.errors().getAllOn(ConfigurationProperty.CONFIGURATION_KEY).contains("Duplicate key 'ONE' found for Package 'go-server'"), is(true)); assertThat(duplicate1.errors().isEmpty(), is(false)); assertThat(one.errors().getAllOn(ConfigurationProperty.CONFIGURATION_KEY).contains("Duplicate key 'ONE' found for Package 'go-server'"), is(true)); assertThat(duplicate2.errors().isEmpty(), is(false)); assertThat(one.errors().getAllOn(ConfigurationProperty.CONFIGURATION_KEY).contains("Duplicate key 'ONE' found for Package 'go-server'"), is(true)); assertThat(two.errors().isEmpty(), is(true)); } @Test public void shouldGenerateIdIfNotAssigned() { PackageDefinition packageDefinition = new PackageDefinition(); packageDefinition.ensureIdExists(); assertThat(packageDefinition.getId(), is(notNullValue())); packageDefinition = new PackageDefinition(); packageDefinition.setId("id"); packageDefinition.ensureIdExists(); assertThat(packageDefinition.getId(), is("id")); } @Test public void shouldAddFingerprintFieldErrorWhenPackageDefinitionWithSameFingerprintExist() throws Exception { String expectedErrorMessage = "Cannot save package or repo, found duplicate packages. [Repo Name: 'repo-repo1', Package Name: 'pkg1'], [Repo Name: 'repo-repo1', Package Name: 'pkg3']"; PackageRepository repository = PackageRepositoryMother.create("repo1"); PackageDefinition definition1 = PackageDefinitionMother.create("1", "pkg1", new Configuration(new ConfigurationProperty(new ConfigurationKey("k1"), new ConfigurationValue("v1"))), repository); PackageDefinition definition2 = PackageDefinitionMother.create("2", "pkg2", new Configuration(new ConfigurationProperty(new ConfigurationKey("k2"), new ConfigurationValue("v2"))), repository); PackageDefinition definition3 = PackageDefinitionMother.create("3", "pkg3", new Configuration(new ConfigurationProperty(new ConfigurationKey("k1"), new ConfigurationValue("v1"))), repository); HashMap<String, Packages> map = new HashMap<>(); map.put(definition1.getFingerprint(AbstractMaterialConfig.FINGERPRINT_DELIMITER), new Packages(definition1, definition3)); map.put(definition2.getFingerprint(AbstractMaterialConfig.FINGERPRINT_DELIMITER), new Packages(definition2)); definition1.validateFingerprintUniqueness(map); definition2.validateFingerprintUniqueness(map); definition3.validateFingerprintUniqueness(map); assertThat(definition1.errors().getAllOn(PackageDefinition.ID), is(asList(expectedErrorMessage))); assertThat(definition3.errors().getAllOn(PackageDefinition.ID), is(asList(expectedErrorMessage))); assertThat(definition2.errors().getAllOn(PackageDefinition.ID), is(nullValue())); } @Test public void shouldNotAddFingerprintFieldErrorWhenPackageDefinitionWithSameFingerprintNotFound() throws Exception { PackageRepository repository = PackageRepositoryMother.create("repo1"); PackageDefinition packageDefinition = PackageDefinitionMother.create("1", "pkg1", new Configuration(new ConfigurationProperty(new ConfigurationKey("k1"), new ConfigurationValue("v1"))), repository); HashMap<String, Packages> map = new HashMap<>(); map.put(packageDefinition.getFingerprint(AbstractMaterialConfig.FINGERPRINT_DELIMITER), new Packages(packageDefinition)); packageDefinition.validateFingerprintUniqueness(map); assertThat(packageDefinition.errors().getAllOn(PackageDefinition.ID), is(nullValue())); } }