diff --git a/jkube-kit/build/api/src/main/java/org/eclipse/jkube/kit/build/api/helper/BuildArgResolverUtil.java b/jkube-kit/build/api/src/main/java/org/eclipse/jkube/kit/build/api/helper/BuildArgResolverUtil.java new file mode 100644 index 0000000000..89a93431ac --- /dev/null +++ b/jkube-kit/build/api/src/main/java/org/eclipse/jkube/kit/build/api/helper/BuildArgResolverUtil.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.kit.build.api.helper; + +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jkube.kit.common.JKubeConfiguration; +import org.eclipse.jkube.kit.config.image.ImageConfiguration; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +import static org.eclipse.jkube.kit.common.util.MapUtil.mergeMapsImmutable; + +public class BuildArgResolverUtil { + private static final String ARG_PREFIX = "docker.buildArg."; + + private BuildArgResolverUtil() { } + + /** + * Merges Docker Build Args in the following order (in decreasing order of precedence): + * + * @param imageConfig ImageConfiguration for which Build Args would be resolved + * @param configuration {@link JKubeConfiguration} JKubeConfiguration + * @return a Map containing merged Build Args from all sources. + */ + public static Map mergeBuildArgs(ImageConfiguration imageConfig, JKubeConfiguration configuration) { + Map buildArgsFromProjectProperties = addBuildArgsFromProperties(configuration.getProject().getProperties()); + Map buildArgsFromSystemProperties = addBuildArgsFromProperties(System.getProperties()); + Map buildArgsFromDockerConfig = addBuildArgsFromDockerConfig(); + + return mergeMapsImmutable(imageConfig.getBuild().getArgs(), + buildArgsFromSystemProperties, + buildArgsFromProjectProperties, + Optional.ofNullable(configuration.getBuildArgs()).orElse(Collections.emptyMap()), + buildArgsFromDockerConfig); + } + + private static Map addBuildArgsFromProperties(Properties properties) { + Map buildArgs = new HashMap<>(); + for (Object keyObj : properties.keySet()) { + String key = (String) keyObj; + if (key.startsWith(ARG_PREFIX)) { + String argKey = key.replaceFirst(ARG_PREFIX, ""); + String value = properties.getProperty(key); + + if (StringUtils.isNotBlank(value)) { + buildArgs.put(argKey, value); + } + } + } + return buildArgs; + } + + private static Map addBuildArgsFromDockerConfig() { + final Map dockerConfig = DockerFileUtil.readDockerConfig(); + if (dockerConfig == null) { + return Collections.emptyMap(); + } + + // add proxies + Map buildArgs = new HashMap<>(); + if (dockerConfig.containsKey("proxies")) { + final Map proxies = (Map) dockerConfig.get("proxies"); + if (proxies.containsKey("default")) { + final Map defaultProxyObj = (Map) proxies.get("default"); + String[] proxyMapping = new String[] { + "httpProxy", "http_proxy", + "httpsProxy", "https_proxy", + "noProxy", "no_proxy", + "ftpProxy", "ftp_proxy" + }; + + for(int index = 0; index < proxyMapping.length; index += 2) { + if (defaultProxyObj.containsKey(proxyMapping[index])) { + buildArgs.put(ARG_PREFIX + proxyMapping[index+1], defaultProxyObj.get(proxyMapping[index])); + } + } + } + } + return buildArgs; + } +} diff --git a/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/helper/BuildArgResolverUtilMergeBuildArgsTest.java b/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/helper/BuildArgResolverUtilMergeBuildArgsTest.java new file mode 100644 index 0000000000..ec3f6ca91c --- /dev/null +++ b/jkube-kit/build/api/src/test/java/org/eclipse/jkube/kit/build/api/helper/BuildArgResolverUtilMergeBuildArgsTest.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2019 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at: + * + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +package org.eclipse.jkube.kit.build.api.helper; + +import org.eclipse.jkube.kit.common.JKubeConfiguration; +import org.eclipse.jkube.kit.common.JavaProject; +import org.eclipse.jkube.kit.common.util.EnvUtil; +import org.eclipse.jkube.kit.config.image.ImageConfiguration; +import org.eclipse.jkube.kit.config.image.build.BuildConfiguration; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +class BuildArgResolverUtilMergeBuildArgsTest { + private ImageConfiguration imageConfiguration; + private JKubeConfiguration jKubeConfiguration; + private Properties projectProperties; + private Map buildArgFromPluginConfiguration; + + @BeforeEach + void setUp() { + projectProperties = new Properties(); + buildArgFromPluginConfiguration = new HashMap<>(); + jKubeConfiguration = JKubeConfiguration.builder() + .project(JavaProject.builder() + .properties(projectProperties) + .build()) + .buildArgs(buildArgFromPluginConfiguration) + .build(); + imageConfiguration = ImageConfiguration.builder() + .name("image-name") + .build(BuildConfiguration.builder() + .build()) + .build(); + } + + @Test + @DisplayName("build args in image config and project properties") + void whenBuildArgsFromImageConfigAndFromProjectProperties_shouldMergeBuildArgs() { + // Given + projectProperties.setProperty("docker.buildArg.VERSION", "latest"); + projectProperties.setProperty("docker.buildArg.FULL_IMAGE", "busybox:latest"); + Map buildArgImageConfiguration = new HashMap<>(); + buildArgImageConfiguration.put("REPO_1", "docker.io/library"); + buildArgImageConfiguration.put("IMAGE-1", "openjdk"); + imageConfiguration = imageConfiguration.toBuilder() + .build(imageConfiguration.getBuild().toBuilder().args(buildArgImageConfiguration).build()) + .build(); + + // When + Map mergedBuildArgs = BuildArgResolverUtil.mergeBuildArgs(imageConfiguration, jKubeConfiguration); + + // Then + assertThat(mergedBuildArgs) + .containsEntry("VERSION", "latest") + .containsEntry("FULL_IMAGE", "busybox:latest") + .containsEntry("REPO_1", "docker.io/library") + .containsEntry("IMAGE-1", "openjdk"); + } + + @Test + @DisplayName("build args in image config, project properties, system properties, plugin configuration") + void fromAllSourcesWithDifferentKeys_shouldMergeBuildArgs() { + // Given + givenBuildArgsFromImageConfiguration("VERSION", "latest"); + System.setProperty("docker.buildArg.IMAGE-1", "openjdk"); + projectProperties.setProperty("docker.buildArg.REPO_1", "docker.io/library"); + givenBuildArgsFromJKubeConfiguration("FULL_IMAGE", "busybox:latest"); + + // When + Map mergedBuildArgs = BuildArgResolverUtil.mergeBuildArgs(imageConfiguration, jKubeConfiguration); + + // Then + assertThat(mergedBuildArgs) + .containsEntry("VERSION", "latest") + .containsEntry("FULL_IMAGE", "busybox:latest") + .containsEntry("REPO_1", "docker.io/library") + .containsEntry("IMAGE-1", "openjdk"); + } + + @Test + @DisplayName("build args in image config and system properties with same key, should throw exception") + void fromBuildConfigurationAndSystemPropertiesWithSameKey_shouldNotMergeBuildArgs() { + // Given + givenBuildArgsFromImageConfiguration("VERSION", "latest"); + System.setProperty("docker.buildArg.VERSION", "1.0.0"); + + // When & Then + assertThatIllegalArgumentException() + .isThrownBy(() -> BuildArgResolverUtil.mergeBuildArgs(imageConfiguration, jKubeConfiguration)) + .withMessage("Multiple entries with same key: VERSION=latest and VERSION=1.0.0"); + } + + @Test + @DisplayName("build args in image config and project properties with same key, should throw exception") + void fromBuildConfigurationAndProjectPropertiesWithSameKey_shouldNotMergeBuildArgs() { + // Given + givenBuildArgsFromImageConfiguration("VERSION", "latest"); + projectProperties.setProperty("docker.buildArg.VERSION", "1.0.0"); + + // When & Then + assertThatIllegalArgumentException() + .isThrownBy(() -> BuildArgResolverUtil.mergeBuildArgs(imageConfiguration, jKubeConfiguration)) + .withMessage("Multiple entries with same key: VERSION=latest and VERSION=1.0.0"); + } + + @Test + @DisplayName("build args in image config and plugin config with same key, should throw exception") + void fromBuildConfigurationAndJKubeConfigurationWithSameKey_shouldNotMergeBuildArgs() { + // Given + givenBuildArgsFromImageConfiguration("VERSION", "latest"); + givenBuildArgsFromJKubeConfiguration("VERSION", "1.0.0"); + + // When & Then + assertThatIllegalArgumentException() + .isThrownBy(() -> BuildArgResolverUtil.mergeBuildArgs(imageConfiguration, jKubeConfiguration)) + .withMessage("Multiple entries with same key: VERSION=latest and VERSION=1.0.0"); + } + + @Test + @DisplayName("should add proxy build args from ~/.docker/config.json") + void shouldAddBuildArgsFromDockerConfig(@TempDir File temporaryFolder) throws IOException { + try { + // Given + Path dockerConfig = temporaryFolder.toPath(); + final Map env = Collections.singletonMap("DOCKER_CONFIG", dockerConfig.toFile().getAbsolutePath()); + EnvUtil.overrideEnvGetter(env::get); + Files.write(dockerConfig.resolve("config.json"), ("{\"proxies\": {\"default\": {\n" + + " \"httpProxy\": \"http://proxy.example.com:3128\",\n" + + " \"httpsProxy\": \"https://proxy.example.com:3129\",\n" + + " \"noProxy\": \"*.test.example.com,.example.org,127.0.0.0/8\"\n" + + " }}}").getBytes()); + // When + final Map mergedBuildArgs = BuildArgResolverUtil.mergeBuildArgs(imageConfiguration, jKubeConfiguration); + // Then + assertThat(mergedBuildArgs) + .containsEntry("docker.buildArg.http_proxy", "http://proxy.example.com:3128") + .containsEntry("docker.buildArg.https_proxy", "https://proxy.example.com:3129") + .containsEntry("docker.buildArg.no_proxy", "*.test.example.com,.example.org,127.0.0.0/8"); + } finally { + EnvUtil.overrideEnvGetter(System::getenv); + } + } + + private void givenBuildArgsFromImageConfiguration(String key, String value) { + imageConfiguration = imageConfiguration.toBuilder() + .build(BuildConfiguration.builder() + .args( + Collections.singletonMap(key, value)) + .build()) + .build(); + } + + private void givenBuildArgsFromJKubeConfiguration(String key, String value) { + buildArgFromPluginConfiguration.put(key, value); + } + + @AfterEach + void clearSystemPropertiesUsedInTests() { + System.clearProperty("docker.buildArg.IMAGE-1"); + System.clearProperty("docker.buildArg.VERSION"); + } +} diff --git a/jkube-kit/build/service/docker/src/main/java/org/eclipse/jkube/kit/build/service/docker/BuildService.java b/jkube-kit/build/service/docker/src/main/java/org/eclipse/jkube/kit/build/service/docker/BuildService.java index d4cc79d024..afe53693a6 100644 --- a/jkube-kit/build/service/docker/src/main/java/org/eclipse/jkube/kit/build/service/docker/BuildService.java +++ b/jkube-kit/build/service/docker/src/main/java/org/eclipse/jkube/kit/build/service/docker/BuildService.java @@ -16,18 +16,13 @@ import java.io.File; import java.io.IOException; import java.util.Collections; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Properties; import java.util.LinkedList; -import com.google.common.collect.ImmutableMap; - import org.eclipse.jkube.kit.common.JKubeConfiguration; import org.eclipse.jkube.kit.build.api.helper.DockerFileUtil; -import org.apache.commons.lang3.StringUtils; import org.eclipse.jkube.kit.build.api.assembly.AssemblyManager; import org.eclipse.jkube.kit.common.util.EnvUtil; import org.eclipse.jkube.kit.build.service.docker.access.BuildOptions; @@ -39,12 +34,11 @@ import org.eclipse.jkube.kit.config.image.build.BuildConfiguration; import org.eclipse.jkube.kit.config.image.build.CleanupMode; +import static org.eclipse.jkube.kit.build.api.helper.BuildArgResolverUtil.mergeBuildArgs; import static org.eclipse.jkube.kit.build.api.helper.BuildUtil.extractBaseFromConfiguration; public class BuildService { - private static final String ARG_PREFIX = "docker.buildArg."; - private final DockerAccess docker; private final QueryService queryService; private final ArchiveService archiveService; @@ -79,10 +73,6 @@ public void buildImage(ImageConfiguration imageConfig, ImagePullManager imagePul buildImage(imageConfig, configuration, checkForNocache(imageConfig), mergedBuildArgs); } - static Map mergeBuildArgs(ImageConfiguration imageConfig, JKubeConfiguration configuration) { - return prepareBuildArgs(addBuildArgs(configuration), imageConfig.getBuildConfiguration()); - } - public void tagImage(String imageName, ImageConfiguration imageConfig) throws DockerAccessException { List tags = imageConfig.getBuildConfiguration().getTags(); @@ -165,14 +155,6 @@ protected void buildImage(ImageConfiguration imageConfig, JKubeConfiguration par } } - private static Map prepareBuildArgs(Map buildArgs, BuildConfiguration buildConfig) { - ImmutableMap.Builder builder = ImmutableMap.builder().putAll(buildArgs); - if (buildConfig.getArgs() != null) { - builder.putAll(buildConfig.getArgs()); - } - return builder.build(); - } - private String getDockerfileName(BuildConfiguration buildConfig) { if (buildConfig.isDockerFileMode()) { return buildConfig.getDockerFile().getName(); @@ -187,64 +169,6 @@ private String doBuildImage(String imageName, File dockerArchive, BuildOptions o return queryService.getImageId(imageName); } - private static Map addBuildArgs(JKubeConfiguration configuration) { - Properties props = configuration.getProject().getProperties(); - Map buildArgsFromProject = addBuildArgsFromProperties(props); - Map buildArgsFromSystem = addBuildArgsFromProperties(System.getProperties()); - Map buildArgsFromDockerConfig = addBuildArgsFromDockerConfig(); - return ImmutableMap.builder() - .putAll(buildArgsFromDockerConfig) - .putAll(Optional.ofNullable(configuration.getBuildArgs()).orElse(Collections.emptyMap())) - .putAll(buildArgsFromProject) - .putAll(buildArgsFromSystem) - .build(); - } - - private static Map addBuildArgsFromProperties(Properties properties) { - Map buildArgs = new HashMap<>(); - for (Object keyObj : properties.keySet()) { - String key = (String) keyObj; - if (key.startsWith(ARG_PREFIX)) { - String argKey = key.replaceFirst(ARG_PREFIX, ""); - String value = properties.getProperty(key); - - if (StringUtils.isNotBlank(value)) { - buildArgs.put(argKey, value); - } - } - } - return buildArgs; - } - - private static Map addBuildArgsFromDockerConfig() { - final Map dockerConfig = DockerFileUtil.readDockerConfig(); - if (dockerConfig == null) { - return Collections.emptyMap(); - } - - // add proxies - Map buildArgs = new HashMap<>(); - if (dockerConfig.containsKey("proxies")) { - final Map proxies = (Map) dockerConfig.get("proxies"); - if (proxies.containsKey("default")) { - final Map defaultProxyObj = (Map) proxies.get("default"); - String[] proxyMapping = new String[] { - "httpProxy", "http_proxy", - "httpsProxy", "https_proxy", - "noProxy", "no_proxy", - "ftpProxy", "ftp_proxy" - }; - - for(int index = 0; index < proxyMapping.length; index += 2) { - if (defaultProxyObj.containsKey(proxyMapping[index])) { - buildArgs.put(ARG_PREFIX + proxyMapping[index+1], defaultProxyObj.get(proxyMapping[index])); - } - } - } - } - return buildArgs; - } - private void autoPullBaseImage(ImageConfiguration imageConfig, ImagePullManager imagePullManager, JKubeConfiguration configuration, Map mergedBuildArgs) throws IOException { diff --git a/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/BuildServiceTest.java b/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/BuildServiceTest.java index fff6800585..1cf0f05bb3 100644 --- a/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/BuildServiceTest.java +++ b/jkube-kit/build/service/docker/src/test/java/org/eclipse/jkube/kit/build/service/docker/BuildServiceTest.java @@ -107,126 +107,6 @@ void tagImage_whenValidImageConfigurationProvided_shouldTagImage() throws Docker .tag("image-name", "image-name:latest", true); } - @Test - void mergeBuildArgs_whenBuildArgsFromImageConfigAndFromProjectProperties_shouldMergeBuildArgs() { - // Given - Properties props = new Properties(); - props.setProperty("docker.buildArg.VERSION", "latest"); - props.setProperty("docker.buildArg.FULL_IMAGE", "busybox:latest"); - when(mockedJKubeConfiguration.getProject().getProperties()).thenReturn(props); - - Map imgConfigBuildArg = new HashMap<>(); - imgConfigBuildArg.put("REPO_1", "docker.io/library"); - imgConfigBuildArg.put("IMAGE-1", "openjdk"); - imageConfiguration = ImageConfiguration.builder() - .name("image-name") - .build(BuildConfiguration.builder() - .args(imgConfigBuildArg) - .build()) - .build(); - - // When - Map mergedBuildArgs = BuildService.mergeBuildArgs(imageConfiguration, mockedJKubeConfiguration); - - // Then - assertThat(mergedBuildArgs) - .containsEntry("VERSION", "latest") - .containsEntry("FULL_IMAGE", "busybox:latest") - .containsEntry("REPO_1", "docker.io/library") - .containsEntry("IMAGE-1", "openjdk"); - } - - @Nested - @DisplayName("mergeBuildArgs with BuildArgs") - class MergeBuildArgs { - @Test - void fromAllSourcesWithDifferentKeys_shouldMergeBuildArgs() { - // Given - givenBuildArgsFromImageConfiguration("VERSION", "latest"); - givenBuildArgsFromSystemProperties("docker.buildArg.IMAGE-1", "openjdk"); - givenBuildArgsFromProjectProperties("docker.buildArg.REPO_1", "docker.io/library"); - givenBuildArgsFromJKubeConfiguration("FULL_IMAGE", "busybox:latest"); - - // When - Map mergedBuildArgs = BuildService.mergeBuildArgs(imageConfiguration, mockedJKubeConfiguration); - - // Then - assertThat(mergedBuildArgs) - .containsEntry("VERSION", "latest") - .containsEntry("FULL_IMAGE", "busybox:latest") - .containsEntry("REPO_1", "docker.io/library") - .containsEntry("IMAGE-1", "openjdk"); - } - - @Test - void fromBuildConfigurationAndSystemPropertiesWithSameKey_shouldNotMergeBuildArgs() { - // Given - givenBuildArgsFromImageConfiguration("VERSION", "latest"); - givenBuildArgsFromSystemProperties("docker.buildArg.VERSION", "1.0.0"); - - // When & Then - assertThatIllegalArgumentException() - .isThrownBy(() -> BuildService.mergeBuildArgs(imageConfiguration, mockedJKubeConfiguration)) - .withMessage("Multiple entries with same key: VERSION=latest and VERSION=1.0.0"); - } - - @Test - void fromBuildConfigurationAndProjectPropertiesWithSameKey_shouldNotMergeBuildArgs() { - // Given - givenBuildArgsFromImageConfiguration("VERSION", "latest"); - givenBuildArgsFromProjectProperties("docker.buildArg.VERSION", "1.0.0"); - - // When & Then - assertThatIllegalArgumentException() - .isThrownBy(() -> BuildService.mergeBuildArgs(imageConfiguration, mockedJKubeConfiguration)) - .withMessage("Multiple entries with same key: VERSION=latest and VERSION=1.0.0"); - } - - @Test - void fromBuildConfigurationAndJKubeConfigurationWithSameKey_shouldNotMergeBuildArgs() { - // Given - givenBuildArgsFromImageConfiguration("VERSION", "latest"); - givenBuildArgsFromJKubeConfiguration("VERSION", "1.0.0"); - - // When & Then - assertThatIllegalArgumentException() - .isThrownBy(() -> BuildService.mergeBuildArgs(imageConfiguration, mockedJKubeConfiguration)) - .withMessage("Multiple entries with same key: VERSION=latest and VERSION=1.0.0"); - } - - private void givenBuildArgsFromImageConfiguration(String key, String value) { - imageConfiguration = ImageConfiguration.builder() - .name("image-name") - .build(BuildConfiguration.builder() - .args( - Collections.singletonMap(key, value)) - .build()) - .build(); - } - - private void givenBuildArgsFromSystemProperties(String key, String value) { - System.setProperty(key, value); - } - - private void givenBuildArgsFromProjectProperties(String key, String value) { - Properties props = new Properties(); - props.setProperty(key, value); - when(mockedJKubeConfiguration.getProject().getProperties()) - .thenReturn(props); - } - - private void givenBuildArgsFromJKubeConfiguration(String key, String value) { - when(mockedJKubeConfiguration.getBuildArgs()) - .thenReturn(Collections.singletonMap(key, value)); - } - - @AfterEach - void clearSystemPropertiesUsedInTests() { - System.clearProperty("docker.buildArg.IMAGE-1"); - System.clearProperty("docker.buildArg.VERSION"); - } - } - @Test void buildImage_whenMultiStageDockerfileWithBuildArgs_shouldPrepullImages() throws IOException { // Given diff --git a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java index f2657f2cea..238e86c010 100644 --- a/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java +++ b/jkube-kit/common/src/main/java/org/eclipse/jkube/kit/common/util/MapUtil.java @@ -42,6 +42,32 @@ public static void mergeIfAbsent(Map map, Map to } } + /** + * Returns a new map with all the entries of first map with rest map entries. It throws IllegalArgumentException + * when it encounters conflicting keys + * + * @param maps var arg parameter of maps to be merged + * @return merged map + * @param key type + * @param value type + * @throws IllegalArgumentException when multiple entries with same key are found + */ + @SafeVarargs + public static Map mergeMapsImmutable(Map... maps) { + Map answer = new HashMap<>(); + for (int i = maps.length-1; i >= 0; i--) { + if (maps[i] != null) { + for (Map.Entry e : maps[i].entrySet()) { + if (answer.containsKey(e.getKey())) { + throw new IllegalArgumentException(String.format("Multiple entries with same key: %s=%s and %s=%s", e.getKey(), e.getValue(), e.getKey(), answer.get(e.getKey()))); + } + answer.put(e.getKey(), e.getValue()); + } + } + } + return answer; + } + /** * Returns a new map with all the entries of first map with rest map entries which don't override map1. * diff --git a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/MapUtilTest.java b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/MapUtilTest.java index 999fc21306..1000e052f1 100644 --- a/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/MapUtilTest.java +++ b/jkube-kit/common/src/test/java/org/eclipse/jkube/kit/common/util/MapUtilTest.java @@ -19,12 +19,16 @@ import java.util.Map; import org.assertj.core.api.InstanceOfAssertFactories; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.entry; import static org.eclipse.jkube.kit.common.util.MapUtil.getFlattenedMap; import static org.eclipse.jkube.kit.common.util.MapUtil.getNestedMap; +import static org.eclipse.jkube.kit.common.util.MapUtil.mergeMapsImmutable; import static org.junit.jupiter.api.Assertions.assertThrows; /** @@ -136,6 +140,39 @@ void getNestedMap_withInvalidFlattenedMap_shouldThrowNodeOverlapsException() { assertThat(result).hasMessage("The provided input Map is invalid (node overlaps with key)"); } + @Nested + class MergeMapsImmutable { + @Test + @DisplayName("different keys present in maps, then merge maps") + void whenNoConflictingKeysProvided_thenMergeMaps() { + // Given + Map m1 = createMap("foo", "bar"); + Map m2 = createMap("BAR", "FOO"); + + // When + Map result = mergeMapsImmutable(m1, m2); + + // Then + assertThat(result) + .containsEntry("foo", "bar") + .containsEntry("BAR", "FOO"); + } + + @Test + @DisplayName("same keys present in maps, then throw exception") + void whenConflictingKeysProvided_thenThrowException() { + // Given + Map m1 = createMap("foo", "bar"); + Map m2 = createMap("foo", "FOO"); + + // When + Then + assertThatIllegalArgumentException() + .isThrownBy(() -> MapUtil.mergeMapsImmutable(m1, m2, null)) + .withMessage("Multiple entries with same key: foo=bar and foo=FOO"); + } + } + + private Map createMap(String ... args) { Map ret = new LinkedHashMap<>(); for (int i = 0; i < args.length; i+=2) {