From 220e38337ae2e2b20e40f8fc1f831bf79fa0ad3a Mon Sep 17 00:00:00 2001 From: Dipak Pawar Date: Fri, 24 Nov 2017 15:52:00 +0530 Subject: [PATCH] Implemented map level inheritance --- .../configuration/ConfigurationInheriter.java | 80 ------------------- .../configuration/ConfigurationLoader.java | 20 ++--- .../configuration/ConfigurationReader.java | 32 +++++++- .../testing/configuration/ObjectMapper.java | 4 +- .../smart/testing/configuration/Range.java | 23 ------ .../smart/testing/configuration/Report.java | 19 ----- .../smart/testing/configuration/Scm.java | 19 ----- ...ile.java => ConfigurationFileBuilder.java} | 20 ++--- ...onfigurationOverWriteUsingInheritTest.java | 6 +- ...iteUsingInheritWithSystemPropertyTest.java | 4 +- .../configuration/ConfigurationTest.java | 2 +- .../ConfigurationUsingPropertyTest.java | 10 +-- 12 files changed, 57 insertions(+), 182 deletions(-) delete mode 100644 core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationInheriter.java rename core/src/test/java/org/arquillian/smart/testing/configuration/{ConfigurationFile.java => ConfigurationFileBuilder.java} (70%) diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationInheriter.java b/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationInheriter.java deleted file mode 100644 index d63aeafff..000000000 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationInheriter.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.arquillian.smart.testing.configuration; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.arquillian.smart.testing.configuration.Configuration.DISABLE; -import static org.arquillian.smart.testing.configuration.Configuration.INHERIT; - -class ConfigurationInheriter { - - Configuration overWriteNotDefinedValuesFromInherit(Configuration configuration, Path currentDir) { - final String inherit = configuration.getInherit(); - if (inherit == null) { - return configuration; - } else { - final List fieldsToInherit = fieldNamesToInherit(configuration); - final Path inheritPath = currentDir.resolve(inherit); - final ConfigurationReader configurationReader = new ConfigurationReader(); - final Map inheritedParameters = configurationReader.getConfigParametersFromFile(inheritPath); - if (inheritedParameters.isEmpty()) { - configuration.setInherit(null); - return configuration; - } - final Map parametersToInherit = inheritedParameters.entrySet().stream() - .filter(entry -> fieldsToInherit.contains(entry.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - - List configItems = configuration.registerConfigurationItems(); - - final ObjectMapper objectMapper = new ObjectMapper(); - Arrays.stream(configuration.getClass().getMethods()) - .filter(method -> fieldsToInherit.contains(fieldName(method)) && objectMapper.isSetter(method)) - .forEach(method -> objectMapper.invokeMethodWithMappedValue(configItems, method, configuration, - parametersToInherit)); - - configuration.setInherit((String) inheritedParameters.get(INHERIT)); - - return overWriteNotDefinedValuesFromInherit(configuration, inheritPath.getParent()); - } - } - - private List fieldNamesToInherit(Configuration configuration) { - return Arrays.stream(configuration.getClass().getDeclaredFields()) - .filter(field -> !Modifier.isStatic(field.getModifiers()) && - !hasFieldToIgnore(field) && hasValueNotDefined(field, configuration)) - .map(Field::getName) - .collect(Collectors.toList()); - } - - private boolean hasFieldToIgnore(Field field) { - return Arrays.asList(DISABLE, INHERIT).contains(field.getName()); - } - - private boolean hasValueNotDefined(Field field, Configuration configuration) { - final ObjectMapper objectMapper = new ObjectMapper(); - final Configuration defaultConfiguration = objectMapper.readValue(Configuration.class, Collections.emptyMap()); - - field.setAccessible(true); - try { - final Object actualValue = field.get(configuration); - final Object defaultValue = field.get(defaultConfiguration); - return actualValue == null || actualValue.equals(defaultValue) || - (field.getType().isArray() && Arrays.equals(((Object[]) actualValue), ((Object[]) defaultValue))); - } catch (IllegalAccessException e) { - throw new RuntimeException("Failed to access fieldName: " + field, e); - } - } - - private String fieldName(Method method) { - final String field = method.getName().substring(3); - return Character.toLowerCase(field.charAt(0)) + field.substring(1); - } -} diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationLoader.java b/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationLoader.java index 3233624eb..9e9692569 100644 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationLoader.java +++ b/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationLoader.java @@ -64,19 +64,14 @@ public static Configuration load(File projectDir, Function stopCo configFile = projectDir; } - return loadInheritedConfiguration(configFile); + return loadEffectiveConfiguration(configFile); } - private static Configuration loadInheritedConfiguration(File configFile) { - Path configFileDir = configFile.isFile()? configFile.getParentFile().toPath(): configFile.toPath(); + private static Configuration loadEffectiveConfiguration(File configFile) { + ConfigurationReader configurationReader = new ConfigurationReader(); + final Map effectiveConfig = configurationReader.readConfiguration(configFile); - final ConfigurationReader configurationReader = new ConfigurationReader(); - final Map yamlConfiguration = configurationReader.readConfiguration(configFile); - - final Configuration configuration = ConfigurationLoader.loadAsConfiguration(yamlConfiguration); - - final ConfigurationInheriter inheriter = new ConfigurationInheriter(); - return inheriter.overWriteNotDefinedValuesFromInherit(configuration, configFileDir); + return ConfigurationLoader.loadAsConfiguration(effectiveConfig); } /** @@ -117,11 +112,6 @@ static Configuration loadConfigurationFromFile(File configFile) { } } - // testing - static Configuration load(Path path) { - return loadInheritedConfiguration(path.toFile()); - } - private static Configuration loadAsConfiguration(Map yamlConfiguration) { final Object strategiesConfiguration = yamlConfiguration.get("strategiesConfiguration"); final ObjectMapper objectMapper = new ObjectMapper(); diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationReader.java b/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationReader.java index 50e7eb97e..200009e3c 100644 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationReader.java +++ b/core/src/main/java/org/arquillian/smart/testing/configuration/ConfigurationReader.java @@ -6,13 +6,16 @@ import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Map; import org.arquillian.smart.testing.logger.Log; import org.arquillian.smart.testing.logger.Logger; import org.yaml.snakeyaml.Yaml; +import static org.arquillian.smart.testing.configuration.Configuration.INHERIT; import static org.arquillian.smart.testing.configuration.ConfigurationLoader.SMART_TESTING_YAML; import static org.arquillian.smart.testing.configuration.ConfigurationLoader.SMART_TESTING_YML; @@ -22,7 +25,7 @@ class ConfigurationReader { Map readConfiguration(File configPath) { if (!configPath.isDirectory()) { - return getConfigParametersFromFile(getConfigurationFilePath(configPath)); + return readEffectiveConfig(getConfigurationFilePath(configPath)); } final File[] files = @@ -36,12 +39,12 @@ Map readConfiguration(File configPath) { logger.info("Config file `" + SMART_TESTING_YAML + "` OR `" + SMART_TESTING_YML + "` is not found. " + "Using system properties to load configuration for smart testing."); } else { - return getConfigParametersFromFile(getConfigurationFilePath(files)); + return readEffectiveConfig(getConfigurationFilePath(files)); } return Collections.emptyMap(); } - Map getConfigParametersFromFile(Path filePath) { + private Map getConfigParametersFromFile(Path filePath) { if (!filePath.toFile().exists()) { logger.warn(String.format("The configuration file %s is not exists.", filePath)); return Collections.emptyMap(); @@ -88,4 +91,27 @@ private Path getDefaultConfigFile(File... files) { .findFirst() .get(); } + + private Map readEffectiveConfig(Path filePath){ + Map config = getConfigParametersFromFile(filePath); + + List> configs = new ArrayList<>(); + configs.add(config); + while (config.get(INHERIT) != null) { + String inherit = String.valueOf(config.get(INHERIT)); + filePath = filePath.getParent().resolve(inherit); + config = getConfigParametersFromFile(filePath); + if (!config.isEmpty()) { + configs.add(0, config); + } + } + Map effectiveConfig = configs.get(0); + for (int i = 1; i < configs.size(); i++){ + effectiveConfig.putAll(configs.get(i)); + } + + effectiveConfig.remove(INHERIT); + + return effectiveConfig; + } } diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/ObjectMapper.java b/core/src/main/java/org/arquillian/smart/testing/configuration/ObjectMapper.java index b23937250..90f9ed10f 100644 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/ObjectMapper.java +++ b/core/src/main/java/org/arquillian/smart/testing/configuration/ObjectMapper.java @@ -32,7 +32,7 @@ T readValue(Class aClass, Map void invokeMethodWithMappedValue(List configItems, Method method, T instance, + private void invokeMethodWithMappedValue(List configItems, Method method, T instance, Map map) { method.setAccessible(true); if (method.getParameterTypes().length != 1) { @@ -228,7 +228,7 @@ private List getConvertedList(Class parameterType, Object mappedValue) return null; } - boolean isSetter(Method candidate) { + private boolean isSetter(Method candidate) { return candidate.getName().matches("^(set|add)[A-Z].*") && (candidate.getReturnType().equals(Void.TYPE) || candidate.getReturnType() .equals(candidate.getDeclaringClass())) diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/Range.java b/core/src/main/java/org/arquillian/smart/testing/configuration/Range.java index 6623ea5d8..20b7e4386 100644 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/Range.java +++ b/core/src/main/java/org/arquillian/smart/testing/configuration/Range.java @@ -46,27 +46,4 @@ public List registerConfigurationItems() { return configItems; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final Range range = (Range) o; - - return (head != null ? head.equals(range.head) : range.head == null) - && (tail != null ? tail.equals(range.tail) : range.tail == null); - } - - @Override - public int hashCode() { - int result = head != null ? head.hashCode() : 0; - result = 31 * result + (tail != null ? tail.hashCode() : 0); - - return result; - } } diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/Report.java b/core/src/main/java/org/arquillian/smart/testing/configuration/Report.java index ec327c4e9..78e05f664 100644 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/Report.java +++ b/core/src/main/java/org/arquillian/smart/testing/configuration/Report.java @@ -45,23 +45,4 @@ public List registerConfigurationItems() { configItems.add(new ConfigurationItem("dir", null, TARGET)); return configItems; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final Report report = (Report) o; - - return enable == report.enable; - } - - @Override - public int hashCode() { - return (enable ? 1 : 0); - } } diff --git a/core/src/main/java/org/arquillian/smart/testing/configuration/Scm.java b/core/src/main/java/org/arquillian/smart/testing/configuration/Scm.java index 97c00a27c..d38ab63b4 100644 --- a/core/src/main/java/org/arquillian/smart/testing/configuration/Scm.java +++ b/core/src/main/java/org/arquillian/smart/testing/configuration/Scm.java @@ -41,23 +41,4 @@ public List registerConfigurationItems() { return configItems; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final Scm scm = (Scm) o; - - return range != null ? range.equals(scm.range) : scm.range == null; - } - - @Override - public int hashCode() { - return range != null ? range.hashCode() : 0; - } } diff --git a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationFile.java b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationFileBuilder.java similarity index 70% rename from core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationFile.java rename to core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationFileBuilder.java index 793bad72e..1a07d25ef 100644 --- a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationFile.java +++ b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationFileBuilder.java @@ -7,44 +7,44 @@ import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; -class ConfigurationFile { +class ConfigurationFileBuilder { private HashMap properties; - private ConfigurationFile() { + private ConfigurationFileBuilder() { properties = new HashMap<>(); } - static ConfigurationFile SmartTestingConfigurationFile() { - return new ConfigurationFile(); + static ConfigurationFileBuilder SmartTestingConfigurationFile() { + return new ConfigurationFileBuilder(); } - ConfigurationFile inherit(String inherit) { + ConfigurationFileBuilder inherit(String inherit) { properties.put("inherit", inherit); return this; } - ConfigurationFile mode(String mode) { + ConfigurationFileBuilder mode(String mode) { properties.put("mode", mode); return this; } - ConfigurationFile applyTo(String applyTo) { + ConfigurationFileBuilder applyTo(String applyTo) { properties.put("applyTo", applyTo); return this; } - ConfigurationFile strategies(String strategies) { + ConfigurationFileBuilder strategies(String strategies) { properties.put("strategies", strategies); return this; } - ConfigurationFile debug(boolean debug) { + ConfigurationFileBuilder debug(boolean debug) { properties.put("debug", debug); return this; } - ConfigurationFile disable(boolean disable) { + ConfigurationFileBuilder disable(boolean disable) { properties.put("disable", disable); return this; } diff --git a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritTest.java b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritTest.java index 911ec49e2..7db9a019e 100644 --- a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritTest.java +++ b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritTest.java @@ -8,7 +8,7 @@ import static org.arquillian.smart.testing.RunMode.ORDERING; import static org.arquillian.smart.testing.RunMode.SELECTING; -import static org.arquillian.smart.testing.configuration.ConfigurationFile.SmartTestingConfigurationFile; +import static org.arquillian.smart.testing.configuration.ConfigurationFileBuilder.SmartTestingConfigurationFile; import static org.arquillian.smart.testing.configuration.ConfigurationLoader.SMART_TESTING_YAML; import static org.arquillian.smart.testing.configuration.ConfigurationLoader.SMART_TESTING_YML; import static org.assertj.core.api.Assertions.assertThat; @@ -66,7 +66,7 @@ public void should_load_configuration_properties_from_relative_inherit_if_not_de .create(Paths.get(root, SMART_TESTING_YML)); // when - final Configuration configuration = ConfigurationLoader.load(Paths.get(root, CONFIG, IMPL_BASE)); + final Configuration configuration = ConfigurationLoader.load(Paths.get(root, CONFIG, IMPL_BASE).toFile()); // then assertThat(configuration.getMode()).isEqualTo(SELECTING); @@ -92,7 +92,7 @@ public void should_not_overwrite_disable_parameter_from_inherit() throws IOExcep .create(Paths.get(root, SMART_TESTING_YML)); // when - final Configuration configuration = ConfigurationLoader.load(Paths.get(root, CONFIG)); + final Configuration configuration = ConfigurationLoader.load(Paths.get(root, CONFIG).toFile()); // then assertThat(configuration.getMode()).isEqualTo(ORDERING); diff --git a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritWithSystemPropertyTest.java b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritWithSystemPropertyTest.java index 8fce8f06b..2bd23b184 100644 --- a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritWithSystemPropertyTest.java +++ b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationOverWriteUsingInheritWithSystemPropertyTest.java @@ -11,7 +11,7 @@ import static org.arquillian.smart.testing.RunMode.ORDERING; import static org.arquillian.smart.testing.configuration.Configuration.SMART_TESTING; -import static org.arquillian.smart.testing.configuration.ConfigurationFile.SmartTestingConfigurationFile; +import static org.arquillian.smart.testing.configuration.ConfigurationFileBuilder.SmartTestingConfigurationFile; import static org.arquillian.smart.testing.configuration.ConfigurationLoader.SMART_TESTING_YML; import static org.arquillian.smart.testing.configuration.ConfigurationOverWriteUsingInheritTest.CONFIG; import static org.arquillian.smart.testing.scm.ScmRunnerProperties.HEAD; @@ -50,7 +50,7 @@ public void system_properties_should_take_precedence_over_config_file() throws I range.setTail(HEAD + "~3"); // when - final Configuration configuration = ConfigurationLoader.load(Paths.get(root, CONFIG)); + final Configuration configuration = ConfigurationLoader.load(Paths.get(root, CONFIG).toFile()); // then assertThat(configuration.getStrategies()).isEqualTo(new String[] {"changed"}); diff --git a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationTest.java b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationTest.java index 4d13413ac..3ba5a4958 100644 --- a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationTest.java +++ b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationTest.java @@ -71,7 +71,7 @@ public void should_load_configuration_with_default_values_if_property_is_not_spe // when final Configuration actualConfiguration = - ConfigurationLoader.load(getResourceAsPath("configuration/smart-testing.yml")); + ConfigurationLoader.load(getResourceAsFile("configuration/smart-testing.yml")); // then assertThat(actualConfiguration).isEqualToComparingFieldByFieldRecursively(expectedConfiguration); diff --git a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationUsingPropertyTest.java b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationUsingPropertyTest.java index d41242bea..58515d630 100644 --- a/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationUsingPropertyTest.java +++ b/core/src/test/java/org/arquillian/smart/testing/configuration/ConfigurationUsingPropertyTest.java @@ -50,7 +50,7 @@ public void should_load_configuration_with_overwriting_system_property_for_scmLa // when final Configuration actualConfiguration = - ConfigurationLoader.load(getResourceAsPath("configuration/smart-testing-with-lastChanges.yml")); + ConfigurationLoader.load(getResourceAsFile("configuration/smart-testing-with-lastChanges.yml")); // then final Range range = actualConfiguration.getScm().getRange(); @@ -61,7 +61,7 @@ public void should_load_configuration_with_overwriting_system_property_for_scmLa public void should_load_configuration_for_scmLastChanges_from_config_file() { // when final Configuration actualConfiguration = - ConfigurationLoader.load(getResourceAsPath("configuration/smart-testing-with-lastChanges.yml")); + ConfigurationLoader.load(getResourceAsFile("configuration/smart-testing-with-lastChanges.yml")); // then final Range range = actualConfiguration.getScm().getRange(); @@ -72,7 +72,7 @@ public void should_load_configuration_for_scmLastChanges_from_config_file() { public void should_load_configuration_for_rangeHead_and_rangeTail_from_config_file() { // when final Configuration actualConfiguration = - ConfigurationLoader.load(getResourceAsPath("configuration/smart-testing.yml")); + ConfigurationLoader.load(getResourceAsFile("configuration/smart-testing.yml")); // then final Range range = actualConfiguration.getScm().getRange(); @@ -87,7 +87,7 @@ public void should_load_configuration_with_overwriting_system_property_for_range // when final Configuration actualConfiguration = - ConfigurationLoader.load(getResourceAsPath("configuration/smart-testing.yml")); + ConfigurationLoader.load(getResourceAsFile("configuration/smart-testing.yml")); // then final Range range = actualConfiguration.getScm().getRange(); @@ -141,7 +141,7 @@ public void should_load_configuration_with_overwriting_system_properties_over_pr // when final Configuration actualConfiguration = - ConfigurationLoader.load(getResourceAsPath("configuration/smart-testing.yml")); + ConfigurationLoader.load(getResourceAsFile("configuration/smart-testing.yml")); // then assertThat(actualConfiguration).isEqualToComparingFieldByFieldRecursively(expectedConfiguration);