package com.sequenceiq.it;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.io.Resource;
import org.springframework.util.CollectionUtils;
import org.testng.TestNG;
import org.testng.internal.YamlParser;
import org.testng.xml.IFileParser;
import org.testng.xml.SuiteXmlParser;
import org.testng.xml.XmlSuite;
import org.uncommons.reportng.HTMLReporter;
import org.uncommons.reportng.JUnitXMLReporter;
import com.sequenceiq.it.cloudbreak.config.ITProps;
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
@ComponentScan(basePackages = "com.sequenceiq.it")
@EnableConfigurationProperties(ITProps.class)
public class IntegrationTestApp implements CommandLineRunner {
private static final Logger LOG = LoggerFactory.getLogger(IntegrationTestApp.class);
private static final IFileParser<XmlSuite> XML_PARSER = new SuiteXmlParser();
private static final IFileParser<XmlSuite> YAML_PARSER = new YamlParser();
private static final IFileParser<XmlSuite> DEFAULT_FILE_PARSER = XML_PARSER;
@Value("${integrationtest.testsuite.threadPoolSize}")
private int suiteThreadPoolSize;
@Value("${integrationtest.command:}")
private String itCommand;
@Value("${integrationtest.fulltest.regindex:-1}")
private int fullTestRegionIndex;
@Value("${integrationtest.fulltest.regnum:-1}")
private int fullTestRegionNumber;
@Value("${integrationtest.outputdir:.}")
private String outputDirectory;
@Inject
private TestNG testng;
@Inject
private ApplicationContext applicationContext;
@Inject
private ITProps itProps;
@Override
public void run(String... args) throws Exception {
testng.setSuiteThreadPoolSize(suiteThreadPoolSize);
testng.setVerbose(2);
testng.setOutputDirectory(outputDirectory + "/test-output");
testng.addListener(new ThreadLocalTestListener());
testng.addListener(new HTMLReporter());
testng.addListener(new JUnitXMLReporter());
setupSuites(testng);
testng.run();
}
private void setupSuites(TestNG testng) throws Exception {
switch (itCommand) {
case "smoketest":
setupSmokeTest(testng, itProps.getTestTypes());
break;
case "fulltest":
if (fullTestRegionIndex > -1 && fullTestRegionNumber > 0) {
setupFullTest(testng, fullTestRegionIndex, fullTestRegionNumber);
} else {
LOG.info("fulltest command require integrationtest.fulltest.regindex and integrationtest.fulltest.regnum parameters!");
}
break;
case "suites":
List<String> suiteFiles = itProps.getSuiteFiles();
if (!CollectionUtils.isEmpty(suiteFiles)) {
testng.setTestSuites(suiteFiles);
}
break;
case "suiteurls":
List<String> suitePathes = itProps.getSuiteFiles();
testng.setXmlSuites(loadSuites(suitePathes));
break;
default:
LOG.info("Unknown command: {}", itCommand);
break;
}
}
private void setupSmokeTest(TestNG testng, List<String> testTypes) throws IOException {
if (!CollectionUtils.isEmpty(testTypes)) {
Set<String> suitePathes = new LinkedHashSet<>();
for (String testType : testTypes) {
List<String> suites = itProps.getTestSuites(testType);
if (suites != null) {
suitePathes.addAll(suites);
}
}
testng.setXmlSuites(loadSuites(suitePathes));
}
}
private void setupFullTest(TestNG testng, int salt, int regionNum) throws IOException {
List<Resource> suites = new ArrayList<>();
suites.addAll(getProviderSuites("classpath:/testsuites/aws/full/*.yaml", salt, regionNum));
suites.addAll(getProviderSuites("classpath:/testsuites/azure/full/*.yaml", salt, regionNum));
suites.addAll(getProviderSuites("classpath:/testsuites/gcp/full/*.yaml", salt, regionNum));
LOG.info("The following suites will be executed: {}", suites);
testng.setXmlSuites(loadSuiteResources(suites));
}
private Set<Resource> getProviderSuites(String providerDirPattern, int salt, int regionNum) throws IOException {
Resource[] suites = applicationContext.getResources(providerDirPattern);
Set<Resource> providerTests = new HashSet<>();
regionNum = Math.min(regionNum, suites.length);
int regionIndex = salt * regionNum % suites.length;
for (int i = regionIndex; i < regionIndex + regionNum; i++) {
providerTests.add(suites[i % suites.length]);
}
return providerTests;
}
private List<XmlSuite> loadSuiteResources(Collection<Resource> suitePathes) throws IOException {
List<XmlSuite> suites = new ArrayList<>();
for (Resource suite: suitePathes) {
suites.add(loadSuite(suite.getURL().toString(), suite));
}
return suites;
}
private List<XmlSuite> loadSuites(Collection<String> suitePathes) throws IOException {
List<XmlSuite> suites = new ArrayList<>();
for (String suitePath: suitePathes) {
suites.add(loadSuite(suitePath));
}
return suites;
}
private XmlSuite loadSuite(String suitePath) throws IOException {
return loadSuite(suitePath, applicationContext.getResource(suitePath));
}
private XmlSuite loadSuite(String suitePath, Resource resource) throws IOException {
IFileParser<XmlSuite> parser = getParser(suitePath);
try (InputStream inputStream = resource.getInputStream()) {
return parser.parse(suitePath, inputStream, true);
}
}
private IFileParser getParser(String fileName) {
IFileParser result = DEFAULT_FILE_PARSER;
if (fileName.endsWith("xml")) {
result = XML_PARSER;
} else if (fileName.endsWith("yaml") || fileName.endsWith("yml")) {
result = YAML_PARSER;
}
return result;
}
public static void main(String[] args) {
SpringApplication springApp = new SpringApplication(IntegrationTestApp.class);
springApp.setWebEnvironment(false);
springApp.run(args);
}
}