package org.arquillian.smart.testing.ftest.testbed.project; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.stream.Collectors; import org.arquillian.smart.testing.RunMode; import org.arquillian.smart.testing.configuration.Configuration; import org.arquillian.smart.testing.ftest.testbed.configuration.Mode; import org.arquillian.smart.testing.ftest.testbed.configuration.Strategy; import org.arquillian.smart.testing.ftest.testbed.configuration.builder.ConfigurationBuilder; import org.arquillian.smart.testing.spi.JavaSPILoader; import org.arquillian.smart.testing.spi.StrategyConfiguration; import org.arquillian.smart.testing.spi.TestExecutionPlannerFactory; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.introspector.Property; import org.yaml.snakeyaml.nodes.NodeTuple; import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; import static org.arquillian.smart.testing.configuration.ConfigurationLoader.SMART_TESTING_YML; public class ProjectConfigurator { private static final String SMART_TESTING = "smart.testing"; private static final String SMART_TESTING_MODE = "smart.testing.mode"; private static final String SMART_TESTING_VERSION = "smart.testing.version"; private Strategy[] strategies; private Mode mode; private String version; private Configuration configuration; private final Project project; private final Path root; private boolean createConfigFile; private Path configFilePath; ProjectConfigurator(Project project, Path root) { this.project = project; this.root = root; } Strategy[] getStrategies() { return strategies; } Mode getMode() { return mode; } public ProjectConfigurator executionOrder(Strategy... strategies) { this.strategies = strategies; return this; } public ProjectConfigurator withConfiguration(Configuration configuration) { this.configuration = configuration; return this; } public ProjectConfigurator createConfigFile() { this.createConfigFile = true; createConfigurationFile(SMART_TESTING_YML); return this; } public ProjectConfigurator createConfigFileIn(String path) { return createConfigFile(path + File.separator + SMART_TESTING_YML); } public ProjectConfigurator createConfigFile(String configFile) { this.createConfigFile = true; createConfigurationFile(configFile); return this; } public ProjectConfigurator inMode(Mode mode) { this.mode = mode; return this; } public ProjectConfigurator version(String version) { this.version = version; return this; } /** * Enables using extension file {@link Using#EXTENSION_FILE} * * @return A modified instance of {@link Project} */ public Project enable() { return enable(Using.EXTENSION_FILE); } public Project enable(Using usingInstallation) { project.build().options().setUsingInstallation(usingInstallation); final Path rootPom = Paths.get(root.toString(), "pom.xml"); String currentVersion = resolveVersion(); if (usingInstallation == Using.EXTENSION_FILE) { new MavenExtensionFileRegisterer(rootPom).addSmartTestingExtension(currentVersion); } if (!createConfigFile) { this.project.build().options() .withSystemProperties(SMART_TESTING, strategies(), SMART_TESTING_MODE, getMode().getName(), SMART_TESTING_VERSION, currentVersion) .configure(); } else { if (configuration == null) { this.configuration = new ConfigurationBuilder() .strategies(strategies().split("\\s*,\\s*")) .mode(RunMode.valueOf(getMode().getName().toUpperCase())) .build(); dumpConfiguration(this.configFilePath); } } return this.project; } public String strategies() { return Arrays.stream(getStrategies()).map(Strategy::getName).collect(Collectors.joining(",")); } private void createConfigurationFile(String configFilePath) { this.configFilePath = Paths.get(root.toString(), configFilePath); if (configuration != null) { dumpConfiguration(this.configFilePath); } } private void dumpConfiguration(Path configFilePath) { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.FLOW); Representer representer = new Representer() { @Override protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { // if value of property is null, ignore it. if (propertyValue == null) { return null; } else { return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); } } }; representer.addClassTag(Configuration.class, Tag.MAP); Yaml yaml = new Yaml(representer, options); String config = yaml.dump(configuration); for (TestExecutionPlannerFactory factory : new JavaSPILoader().all(TestExecutionPlannerFactory.class)) { StrategyConfiguration strategyConfig = factory.strategyConfiguration(); config = config.replaceAll("!!" + strategyConfig.getClass().getName(), strategyConfig.name() + ":"); } try { Files.write(configFilePath, config.getBytes()); } catch (IOException e) { throw new RuntimeException("Failed to dump configuration in file " + configFilePath, e); } } private String resolveVersion() { if (this.version == null) { String systemProperty = System.getProperty(SMART_TESTING_VERSION); if (systemProperty == null) { return readVersionFromExtensionFile(); } return systemProperty; } return this.version; } private String readVersionFromExtensionFile() { try (BufferedReader reader = new BufferedReader( new InputStreamReader(ProjectConfigurator.class.getResourceAsStream("/extension_version")))) { return reader.readLine().trim(); } catch (IOException e) { throw new RuntimeException("Couldn't read extension version", e); } } }