Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.exactpro.sf.statictesting.StaticMatrixTest Maven / Gradle / Ivy
/******************************************************************************
* Copyright 2009-2018 Exactpro (Exactpro Systems Limited)
*
* 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.exactpro.sf.statictesting;
import static com.exactpro.sf.common.services.ServiceName.DEFAULT_ENVIRONMENT;
import static com.exactpro.sf.util.LogUtils.LOG4J_PROPERTIES_FILE_NAME;
import static com.exactpro.sf.util.LogUtils.setConfigLocation;
import static com.google.common.collect.Lists.reverse;
import static java.lang.String.format;
import static java.lang.String.join;
import static java.lang.System.lineSeparator;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.io.FileUtils.deleteQuietly;
import static org.apache.commons.io.FilenameUtils.concat;
import static org.apache.commons.io.FilenameUtils.getBaseName;
import static org.apache.commons.io.FilenameUtils.isExtension;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import org.junit.runner.RunWith;
import org.junit.runner.notification.RunListener;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.exactpro.sf.aml.AML;
import com.exactpro.sf.aml.AMLException;
import com.exactpro.sf.aml.AMLSettings;
import com.exactpro.sf.aml.generator.Alert;
import com.exactpro.sf.aml.generator.AlertType;
import com.exactpro.sf.aml.generator.GeneratedScript;
import com.exactpro.sf.aml.iomatrix.MatrixFileTypes;
import com.exactpro.sf.center.ISFContext;
import com.exactpro.sf.center.IVersion;
import com.exactpro.sf.common.services.ServiceName;
import com.exactpro.sf.configuration.suri.SailfishURI;
import com.exactpro.sf.configuration.workspace.FolderType;
import com.exactpro.sf.configuration.workspace.IWorkspaceDispatcher;
import com.exactpro.sf.scriptrunner.IConnectionManager;
import com.exactpro.sf.scriptrunner.ScriptContext;
import com.exactpro.sf.scriptrunner.languagemanager.AutoLanguageFactory;
import com.exactpro.sf.services.ServiceDescription;
import com.exactpro.sf.services.ServiceMarshalManager;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.qameta.allure.Allure;
@RunWith(Parameterized.class)
public class StaticMatrixTest extends AbstractStaticTest {
private static final Logger LOGGER = LoggerFactory.getLogger(StaticMatrixTest.class);
private static final ObjectReader VARIABLE_SET_READER = new ObjectMapper(new YAMLFactory()).readerFor(new TypeReference>>() {});
private static final String WORKSPACES_LONG_OPT = "workspaces";
private static final String MATRICES_LONG_OPT = "matrices";
private static final String SERVICES_LONG_OPT = "services";
private static final String REPORT_LONG_OPT = "report";
private static final String LOGGER_CONFIG_LONG_OPT = "logger-config";
private static final String LOGS_ZIP_LONG_OPT = "logs-zip";
private static final String SKIP_OPTIONAL_LONG_OPT = "skip-optional";
private static final String VARIABLE_SETS_LONG_OPT = "variable-sets";
private static final String ENVIRONMENT_VARIABLE_SET_LONG_OPT = "environment-variable-set";
private static final String TEMP_DIRECTORY_LONG_OPT = "temp-directory";
private static final String LANGUAGE_URI_LONG_OPT = "language-uri";
private static List testData = Collections.emptyList();
private final ISFContext context;
private final File matrix;
private final File services;
private final boolean skipOptional;
private final SailfishURI languageUri;
public StaticMatrixTest(ISFContext context, File matrix, File services, boolean skipOptional, SailfishURI languageUri) {
this.context = context;
this.matrix = matrix;
this.services = services;
this.skipOptional = skipOptional;
this.languageUri = languageUri;
}
@Parameters(name = "{1}")
public static Iterable data() {
return testData;
}
@Test
public void testMatrix() throws Exception {
String canonicalPath = matrix.getCanonicalPath();
LOGGER.info("Testing matrix: {}", canonicalPath);
System.out.println("Testing matrix: " + canonicalPath);
try {
compileMatrix(context, matrix, skipOptional, languageUri);
} catch (AMLException e) {
LOGGER.error("Failed to compile matrix: {}", canonicalPath, e);
attachFiles();
String errors = e.getAlertCollector()
.getAlerts(AlertType.ERROR)
.stream()
.map(Alert::toString)
.collect(joining(lineSeparator()));
throw new AssertionError("Failed to compile matrix. Errors: " + lineSeparator() + errors, e);
} catch(Exception e) {
LOGGER.error("Failed to compile matrix: {}", canonicalPath, e);
attachFiles();
throw e;
}
LOGGER.info("Tested matrix: {}", canonicalPath);
}
private void attachFiles() throws IOException {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Attaching files for matrix: {}", matrix.getCanonicalPath());
}
try(InputStream stream = new FileInputStream(matrix)) {
String name = matrix.getName();
Allure.addAttachment(name, Files.probeContentType(matrix.toPath()), stream, FilenameUtils.getExtension(name));
}
try(InputStream stream = new FileInputStream(services)) {
Allure.addAttachment("Services.zip", Files.probeContentType(services.toPath()), stream, "zip");
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Attached files for matrix: {}", matrix.getCanonicalPath());
}
}
public static void main(String[] args) throws Exception {
try {
CommandLine commandLine = parseArguments(args);
if (commandLine == null) {
return;
}
List workspacePaths = stream(commandLine.getOptionValues(WORKSPACES_LONG_OPT))
.map(File::new)
.distinct()
.collect(toList());
File matricesPath = (File)commandLine.getParsedOptionValue(MATRICES_LONG_OPT);
Set servicesPaths = stream(commandLine.getOptionValues(SERVICES_LONG_OPT))
.map(File::new)
.collect(Collectors.toSet());
File reportDir = (File)commandLine.getParsedOptionValue(REPORT_LONG_OPT);
File loggerConfigFile = (File)commandLine.getParsedOptionValue(LOGGER_CONFIG_LONG_OPT);
File logsZipFile = (File)commandLine.getParsedOptionValue(LOGS_ZIP_LONG_OPT);
boolean skipOptional = commandLine.hasOption(SKIP_OPTIONAL_LONG_OPT);
File variableSetsFile = (File)commandLine.getParsedOptionValue(VARIABLE_SETS_LONG_OPT);
String environmentVariableSet = commandLine.getOptionValue(ENVIRONMENT_VARIABLE_SET_LONG_OPT);
File tempDirectory = (File)commandLine.getParsedOptionValue(TEMP_DIRECTORY_LONG_OPT);
SailfishURI languageUri = ObjectUtils.defaultIfNull(SailfishURI.parse(commandLine.getOptionValue(LANGUAGE_URI_LONG_OPT)), AutoLanguageFactory.URI);
if(!reportDir.exists() && !reportDir.mkdirs()) {
throw new Exception("Report directory cannot be created: " + reportDir.getCanonicalPath());
}
if(loggerConfigFile == null) {
for(File workspacePath : reverse(workspacePaths)) {
File layerConfigFile = new File(workspacePath, concat("cfg", LOG4J_PROPERTIES_FILE_NAME));
if(layerConfigFile.exists() && layerConfigFile.isFile()) {
loggerConfigFile = layerConfigFile;
break;
}
}
if(loggerConfigFile == null) {
throw new Exception("Unable to locate logger config file");
}
} else if(!loggerConfigFile.isFile()) {
throw new Exception("Logger config is not a file: " + loggerConfigFile.getCanonicalPath());
}
if(logsZipFile.exists()) {
throw new Exception("Logs zip file already exists: " + logsZipFile.getCanonicalPath());
}
if(variableSetsFile != null && !variableSetsFile.isFile()) {
throw new Exception("Variable sets is not a file: " + variableSetsFile.getCanonicalPath());
}
if (tempDirectory == null) {
tempDirectory = FileUtils.getTempDirectory();
} else if (tempDirectory.exists() && !tempDirectory.isDirectory()) {
throw new Exception("Temp directory is not a directory: " + tempDirectory.getCanonicalPath());
}
tempDirectory.mkdirs();
File lastWorkspaceLayer = Files.createTempDirectory(tempDirectory.toPath(), "statictest").toFile();
File logsFolder = new File(lastWorkspaceLayer, "logs");
logsFolder.mkdirs();
System.setProperty("sf.log.dir", logsFolder.getAbsolutePath());
setConfigLocation(loggerConfigFile);
workspacePaths.add(lastWorkspaceLayer);
LOGGER.info("Initializing SF context with following workspace layers: {}", workspacePaths);
ISFContext context = initContext(workspacePaths);
LOGGER.info("Initialized SF context with following workspace layers: {}", workspacePaths);
try(PrintWriter writer = new PrintWriter(new File(reportDir, "environment.properties"))) {
String coreVersion = context.getVersion();
System.out.println("--------------------------------");
System.out.println("Components:");
System.out.println("--------------------------------");
System.out.println("Core - " + coreVersion);
LOGGER.info("--------------------------------");
LOGGER.info("Components:");
LOGGER.info("--------------------------------");
LOGGER.info("Core - {}", coreVersion);
writer.printf("core=%s", coreVersion).println();
for(IVersion version : context.getPluginVersions()) {
String pluginAlias = version.getAlias();
String pluginVersion = version.buildVersion();
System.out.println(pluginAlias + " - " + pluginVersion);
LOGGER.info("{} - {}", pluginAlias, pluginVersion);
writer.printf("%s=%s", pluginAlias, pluginVersion).println();
}
System.out.println("--------------------------------");
LOGGER.info("--------------------------------");
}
File services = Files.createTempFile(tempDirectory.toPath(), "services", ".zip").toFile();
try (AutoCloseable closeable = context::dispose) {
if (languageUri != AutoLanguageFactory.URI && !context.getLanguageManager().containsLanguage(languageUri)) {
throw new Exception("Unknown language URI: " + languageUri);
}
if (variableSetsFile != null) {
loadVariableSets(variableSetsFile, environmentVariableSet, context);
}
loadServices(servicesPaths, context);
if (variableSetsFile != null) {
servicesPaths.add(variableSetsFile);
}
zipFile(servicesPaths, services);
testData = new ArrayList<>();
for (File matrix : getMatrices(matricesPath)) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Adding test data for matrix: {}", matrix.getCanonicalPath());
}
testData.add(ArrayUtils.toArray(context, matrix, services, skipOptional, languageUri));
}
System.setProperty("allure.results.directory", reportDir.getCanonicalPath());
LOGGER.info("Initializing Allure");
RunListener listener = new ExtendedAllureJunit4();
LOGGER.info("Initializing JUnit");
JUnitCore core = new JUnitCore();
core.addListener(listener);
LOGGER.info("Launching test");
core.run(StaticMatrixTest.class);
LOGGER.info("Test completed");
} catch (Exception e) {
LOGGER.error("Failed to launch test", e);
throw e;
} finally {
try {
if(logsZipFile.exists()) {
File newLogsZipFile = new File(logsZipFile.getParentFile(), getBaseName(logsZipFile.getName()) + System.currentTimeMillis() + ".zip");
if (LOGGER.isErrorEnabled()) {
LOGGER.error("Logs zip file already exists: {}", logsZipFile.getCanonicalPath());
LOGGER.error("Saving logs into this file instead: {}", newLogsZipFile.getCanonicalPath());
}
logsZipFile = newLogsZipFile;
}
zipFile(Collections.singleton(logsFolder), logsZipFile);
} finally {
deleteQuietly(services);
deleteQuietly(lastWorkspaceLayer);
}
}
} catch(ParseException e) {
// do nothing
}
}
private static CommandLine parseArguments(String[] args) throws ParseException {
Options options = new Options();
Option workspacePathOption = Option.builder("w")
.longOpt(WORKSPACES_LONG_OPT)
.hasArg()
.argName("path")
.required()
.type(File.class)
.numberOfArgs(Option.UNLIMITED_VALUES)
.desc("paths to workspace layers")
.build();
Option matricesPathOption = Option.builder("m")
.longOpt(MATRICES_LONG_OPT)
.hasArg()
.argName("path")
.required()
.type(File.class)
.desc("path to matrices (file or directory)")
.build();
Option servicesPathOption = Option.builder("s")
.longOpt(SERVICES_LONG_OPT)
.hasArg()
.argName("paths")
.required()
.type(File.class)
.numberOfArgs(Option.UNLIMITED_VALUES)
.desc("paths to services (files or directories)")
.build();
Option reportDirOption = Option.builder("r")
.longOpt(REPORT_LONG_OPT)
.hasArg()
.argName("path")
.required()
.type(File.class)
.desc("path to report directory")
.build();
Option loggerConfigFileOption = Option.builder("l")
.longOpt(LOGGER_CONFIG_LONG_OPT)
.hasArg()
.argName("file")
.type(File.class)
.desc("path to logger configuration file")
.build();
Option logsZipFileOption = Option.builder("z")
.longOpt(LOGS_ZIP_LONG_OPT)
.hasArg()
.argName("file")
.required()
.type(File.class)
.desc("path for logs zip file")
.build();
Option skipOptionalOption = Option.builder("so")
.longOpt(SKIP_OPTIONAL_LONG_OPT)
.desc("skip optional actions")
.build();
Option variableSetsFileOption = Option.builder("vs")
.longOpt(VARIABLE_SETS_LONG_OPT)
.hasArg()
.argName("file")
.type(File.class)
.desc("path to variable sets file")
.build();
Option environmentVariableSetOption = Option.builder("ev")
.longOpt(ENVIRONMENT_VARIABLE_SET_LONG_OPT)
.hasArg()
.argName("name")
.desc("name of variable set to apply to environment")
.build();
Option tempDirOption = Option.builder("td")
.longOpt(TEMP_DIRECTORY_LONG_OPT)
.hasArg()
.argName("directory")
.type(File.class)
.desc("path to temp directory")
.build();
Option languageUriOption = Option.builder("lu")
.longOpt(LANGUAGE_URI_LONG_OPT)
.hasArg()
.argName("uri")
.desc("sailfish URI for desired matrix language")
.build();
options.addOption(workspacePathOption);
options.addOption(matricesPathOption);
options.addOption(servicesPathOption);
options.addOption(reportDirOption);
options.addOption(loggerConfigFileOption);
options.addOption(logsZipFileOption);
options.addOption(skipOptionalOption);
options.addOption(variableSetsFileOption);
options.addOption(environmentVariableSetOption);
options.addOption(tempDirOption);
options.addOption(languageUriOption);
try {
return new DefaultParser().parse(options, args);
} catch (ParseException e) {
new HelpFormatter().printHelp(StaticMatrixTest.class.getSimpleName(), options, true);
throw e;
}
}
private static void loadServices(Set paths, ISFContext context) throws Exception {
LOGGER.info("Loading services from: {}", paths);
ServiceMarshalManager manager = new ServiceMarshalManager(context.getStaticServiceManager(), context.getDictionaryManager());
IConnectionManager connectionManager = context.getConnectionManager();
List services = new ArrayList<>();
Map> serviceLocations = new HashMap<>();
List errors = new ArrayList<>();
for(File path : paths) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Loading service path: {}", path.getCanonicalPath());
}
for (File file : getServices(path)) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Loading service from: {}", file.getCanonicalPath());
}
List list = new ArrayList<>();
try (InputStream stream = new FileInputStream(file)) {
manager.unmarshalServices(stream, isExtension(file.getName(), "zip"), list, errors);
}
for (ServiceDescription service : list) {
services.add(service);
serviceLocations.computeIfAbsent(service.getName(), it -> new ArrayList<>()).add(file.getCanonicalPath());
}
}
}
serviceLocations.entrySet()
.stream()
.filter(entry -> entry.getValue().size() > 1)
.forEach(entry -> {
errors.add(format("Service %s is defined in multiple locations: %s", entry.getKey(), join(", ", entry.getValue())));
});
if (!errors.isEmpty()) {
throw new Exception("Failed to load services. Errors: " + lineSeparator() + join(lineSeparator(), errors));
}
for (ServiceDescription service : services) {
service.setEnvironment(DEFAULT_ENVIRONMENT);
ServiceName serviceName = service.getServiceName();
LOGGER.info("Adding service: {}", serviceName);
if (connectionManager.getService(serviceName) != null) {
LOGGER.info("Service already exists, removing: {}", serviceName);
connectionManager.removeService(serviceName, null).get(); // remove default service from plugin
}
connectionManager.addService(service, null).get();
LOGGER.info("Added service: {}", serviceName);
}
LOGGER.info("Loaded services from: {}", paths);
}
private static void loadVariableSets(File variableSetsFile, String environmentVariableSet, ISFContext context) throws IOException {
if(environmentVariableSet == null) {
return;
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Loading variable sets from file: {}", variableSetsFile.getCanonicalPath());
}
IConnectionManager connectionManager = context.getConnectionManager();
Map> variableSets = VARIABLE_SET_READER.readValue(variableSetsFile);
variableSets.forEach(connectionManager::putVariableSet);
connectionManager.setEnvironmentVariableSet(DEFAULT_ENVIRONMENT, environmentVariableSet);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Loaded variable sets from file: {}", variableSetsFile.getCanonicalPath());
}
}
private static List getMatrices(File path) throws IOException {
return getFiles(path, file -> {
MatrixFileTypes type = MatrixFileTypes.detectFileType(file.getName());
return type.isSupported();
});
}
private static List getServices(File path) throws IOException {
return getFiles(path, file -> isExtension(file.getName(), asList("zip", "xml")));
}
private static List getFiles(File path, Predicate filter) throws IOException {
return Files.walk(path.toPath())
.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(filter)
.collect(toList());
}
private static void compileMatrix(ISFContext context, File matrix, boolean skipOptional, SailfishURI languageUri) throws Exception {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Compiling matrix: {}", matrix.getCanonicalPath());
}
IWorkspaceDispatcher dispatcher = context.getWorkspaceDispatcher();
File reportFolder = dispatcher.getFolder(FolderType.REPORT);
File copiedMatrix = new File(reportFolder, matrix.getName());
Files.copy(matrix.toPath(), copiedMatrix.toPath(), StandardCopyOption.REPLACE_EXISTING);
AMLSettings settings = new AMLSettings();
settings.setAutoStart(true);
settings.setBaseDir(matrix.getName() + System.currentTimeMillis());
settings.setContinueOnFailed(true);
settings.setLanguageURI(languageUri);
settings.setMatrixPath(matrix.getName());
settings.setSkipOptional(skipOptional);
AML aml = new AML(settings,
dispatcher,
context.getAdapterManager(),
context.getEnvironmentManager(),
context.getDictionaryManager(),
context.getStaticServiceManager(),
context.getLanguageManager(),
context.getActionManager(),
context.getUtilityManager(),
context.getCompilerClassPath());
ScriptContext scriptContext = new ScriptContext(context, null, null, null, System.getProperty("user.name"), 0, DEFAULT_ENVIRONMENT);
GeneratedScript script = aml.run(scriptContext, StandardCharsets.UTF_8.name());
if(aml.getAlertCollector().getCount(AlertType.ERROR) != 0) {
throw new AMLException("Errors detected", aml.getAlertCollector());
}
AML.compileScript(script, new File(reportFolder, settings.getBaseDir()), null, context.getCompilerClassPath());
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Compiled matrix: {}", matrix.getCanonicalPath());
}
}
private static void zipFile(Set sourceFiles, File zipFile) throws IOException {
try(ZipOutputStream stream = new ZipOutputStream(new FileOutputStream(zipFile))) {
for(File sourceFile : sourceFiles) {
zipFile(sourceFile, sourceFile.getName(), stream);
}
}
}
private static void zipFile(File file, String name, ZipOutputStream stream) throws IOException {
if(file.isDirectory()) {
for(File child : file.listFiles()) {
zipFile(child, name + "/" + child.getName(), stream);
}
return;
}
try(InputStream fileStream = new FileInputStream(file)) {
stream.putNextEntry(new ZipEntry(name));
IOUtils.copy(fileStream, stream);
}
}
}