All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.exactpro.sf.scriptrunner.EnvironmentSettings Maven / Gradle / Ivy

There is a newer version: 3.4.260
Show newest version
/******************************************************************************
 * 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.scriptrunner;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.HierarchicalConfiguration.Node;
import org.apache.commons.lang3.StringUtils;
import org.mvel2.math.MathProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.exactpro.sf.aml.Description;
import com.exactpro.sf.aml.ValidateRegex;
import com.exactpro.sf.common.util.ICommonSettings;
import com.exactpro.sf.configuration.dictionary.interfaces.IDictionaryValidator;
import com.google.common.collect.ImmutableSet;

public class EnvironmentSettings implements ICommonSettings
{
    private static final Logger logger = LoggerFactory.getLogger(EnvironmentSettings.class);

    public enum StorageType {
        DB("db"),
        FILE("file"),
        MEMORY("memory");

        private final String name;

        StorageType(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public static StorageType parse(String value) {
            if(value != null) {
                for(StorageType element : StorageType.values()) {
                    if(element.name.equalsIgnoreCase(value)) {
                        return element;
                    }
                }
            }

            return null;
        }
    }

    public enum ReportOutputFormat {
        ZIP("zip"),
        FILES("files"),
        ZIP_FILES("zip_files");

        private final String name;

        ReportOutputFormat(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public static ReportOutputFormat parse(String value) {
            if(value != null) {
                for(ReportOutputFormat element : ReportOutputFormat.values()) {
                    if(element.name.equalsIgnoreCase(value)) {
                        return element;
                    }
                }
            }

            return null;
        }

        public boolean isEnableZip(){
            return !name.equalsIgnoreCase(FILES.name);
        }

        public boolean isEnableFiles(){
            return !name.equalsIgnoreCase(ZIP.name);
        }
    }

    public enum RelevantMessagesSortingMode {
        ARRIVAL_TIME("arrival_time"),
        FAILED_FIELDS("failed_fields");

        private final String name;

        RelevantMessagesSortingMode(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public static RelevantMessagesSortingMode parse(String value) {
            if(value != null) {
                for(RelevantMessagesSortingMode mode : values()) {
                    if(mode.name.equalsIgnoreCase(value)) {
                        return mode;
                    }
                }
            }

            return null;
        }
    }

    private static final String GENERAL_KEY = "GeneralSettings";
    private static final String ASYNC_RUN_MATRIX_KEY = "AsyncRunMatrix";
    private static final String NOTIFICATION_IF_SOME_SERVICES_NOT_STARTED = "NotificationIfSomeServicesNotStarted";
    private static final String MATRIX_COMPILER_PRIORITY = "MatrixCompilerPriority";
    private static final String EXCLUDED_MESSAGES_FROM_REPORT = "ExcludedMessagesFromReport";
    private static final String COMPARISON_PRECISION = "ComparisonPrecision";

    private static final String SCRIPT_RUN = "ScriptRun";
    private static final String FAIL_UNEXPECTED_KEY = "FailUnexpected";
    private static final String REPORT_OUTPUT_FORMAT = "ReportOutputFormat";
    private static final String RELEVANT_MESSAGES_SORTING_MODE = "RelevantMessagesSortingMode";
    private static final String MAX_STORAGE_QUEUE_SIZE = "MaxStorageQueueSize";

    private static final String VERIFICATION_LIMIT = "VerificationLimit";

	private StorageType storageType = StorageType.DB;
	private String fileStoragePath = "storage";
	private boolean storeAdminMessages;
	private boolean asyncRunMatrix;
	private long maxQueueSize;

	private boolean notificationIfServicesNotStarted;
	private int matrixCompilerPriority;
	private Set excludedMessages = ImmutableSet.of("Heartbeat");
    private String failUnexpected = "N";
    private ReportOutputFormat reportOutputFormat = ReportOutputFormat.ZIP_FILES;
    private RelevantMessagesSortingMode relevantMessagesSortingMode;
    private BigDecimal comparisonPrecision = MathProcessor.COMPARISON_PRECISION;

    private int verificationLimit;

    // this config is one per SF
    private final HierarchicalConfiguration config;

	public EnvironmentSettings(HierarchicalConfiguration hierarchicalConfiguration) {
		this.config = hierarchicalConfiguration;
		if (config.configurationsAt(GENERAL_KEY).isEmpty()) {
            config.getRootNode().addChild(new Node(GENERAL_KEY));
        }
        if (config.configurationsAt(SCRIPT_RUN).isEmpty()) {
            config.getRootNode().addChild(new Node(SCRIPT_RUN));
        }
	}

    @Override
    public EnvironmentSettings clone() {
        EnvironmentSettings result = new EnvironmentSettings(config);
        result.fileStoragePath = fileStoragePath;
        result.storeAdminMessages = storeAdminMessages;
        result.asyncRunMatrix = asyncRunMatrix;
        result.notificationIfServicesNotStarted = notificationIfServicesNotStarted;
        result.matrixCompilerPriority = matrixCompilerPriority;
        result.excludedMessages = excludedMessages;
        result.failUnexpected = failUnexpected;
        result.storageType = storageType;
        result.reportOutputFormat = reportOutputFormat;
        result.relevantMessagesSortingMode = relevantMessagesSortingMode;
        result.comparisonPrecision = comparisonPrecision;
        result.maxQueueSize = maxQueueSize;
        result.verificationLimit = verificationLimit;

        return result;
    }

    public void set(EnvironmentSettings other) {
        this.fileStoragePath = other.fileStoragePath;
        this.storageType = other.storageType;
        this.storeAdminMessages = other.storeAdminMessages;
        this.asyncRunMatrix = other.asyncRunMatrix;
        this.notificationIfServicesNotStarted = other.notificationIfServicesNotStarted;
        this.matrixCompilerPriority = other.matrixCompilerPriority;
        this.excludedMessages = other.excludedMessages;
        this.failUnexpected = other.failUnexpected;
        this.relevantMessagesSortingMode = other.relevantMessagesSortingMode;
        this.comparisonPrecision = other.comparisonPrecision;
        this.maxQueueSize = other.maxQueueSize;
        this.verificationLimit = other.verificationLimit;

        update();
    }

	public String getFileStoragePath() {
        return fileStoragePath;
	}

	@Description("The directory where the files which contain all the sent/received messages are stored. It is required for 'file' store type.

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight public void setFileStoragePath(String path) { this.fileStoragePath = path; update(); } public StorageType getStorageType() { return storageType; } @Description("This setting allows to set the type of HDD storage used for the long-term " + "storage of the received/sent messages.
" + "Supported storage types:
" + "
    " + "
  • file – for each message, a separate file is created in the directory specified in the 'File Storage Path' field. " + "This type of storage is recommended to be used when opening Sailfish for a short period of time:" + "to check the connection to the test system, to run a smoke test, for demo demonstration.
    " + "When using this storage type, the user cannot query the messages on the Messages page.
  • " + "
  • db – messages are saved in a Database. The DB connection should be set up in the Database tab. This " + "storage type is recommended for long-term work with Sailfish.
  • " + "

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight @ValidateRegex(regex = "(?i)^(file|db)$") public void setStorageType(StorageType storageType) { this.storageType = storageType; update(); } public boolean isStoreAdminMessages() { return storeAdminMessages; } @Description("The setting that allows the user to store or not to store admin " + "messages in HDD storage (e.g. messages for creating, maintaining and closing the connections " + "between the services and the target server).
" + "If admin messages are being stored, they will not be displayed in the report or on the Messages page, " + "and they will not be obtained via the retrieve action.
" + "Not storing admin messages will save the space in HDD storage.

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight @ValidateRegex(regex = "^(true|false)$") public void setStoreAdminMessages(boolean storeAdminMessages) { this.storeAdminMessages = storeAdminMessages; update(); } public boolean isAsyncRunMatrix() { return asyncRunMatrix; } @Description("This parameter is used for changing the matrix execution mode.
" + "
    " + "
  • false – sequential execution (only one matrix will be executed at once).
  • " + "
  • true – execution in parallel (this mode allows to run up to 3 matrices at once, unless the same services are used in these matrices).
  • " + "

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight @ValidateRegex(regex = "^(true|false)$") public void setAsyncRunMatrix(boolean asyncRunMatrix) { this.asyncRunMatrix = asyncRunMatrix; update(); } public long getMaxStorageQueueSize() { return maxQueueSize; } @Description("Maximum MQ volume capacity in RAM for saving messages in " + "HDD. If the memory is full, the arrived messages will not be stored. These messages will not be " + "displayed on the Messages page, neither in the ‘All Messages’ table in the report and will not be " + "found using the retrieve action. MQ overflow can be provoked by the arrival of a large number " + "of messages. The ‘Max Storage Queue Size’ functionality allows preventing JVM crash with OutOfMemory error.

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight @ValidateRegex(regex = "^\\d+$") public void setMaxStorageQueueSize(long size) { maxQueueSize = size; update(); } public boolean isNotificationIfServicesNotStarted() { return notificationIfServicesNotStarted; } @Description("Option is used to notify the user, before matrix execution is started, if the services specified in the test script are not started.
" + "If value is true, and at least one of the services specified in the matrix is not " + "started, the execution of the test script will be on hold, which would be observed on the Test scripts " + "page in the Reports, and on the Matrix execution panel the user will see: ’The following services have " + "not been started’ (not started services will be listed). The user will be able to move to another step, " + "continue or stop the execution.
" + "This feature can be useful when running the test scripts manually, because it allows to take an action " + "before the execution is started.") @ValidateRegex(regex = "^(true|false)$") public void setNotificationIfServicesNotStarted(boolean notificationIfServicesNotStarted) { this.notificationIfServicesNotStarted = notificationIfServicesNotStarted; update(); } public int getMatrixCompilerPriority() { return matrixCompilerPriority; } @Description("Option is used for regulating the priority between the Matrices compilation " + "and the rest of the actions: start of the services, matrices execution and general Sailfish processes.
" + "Integer values have to be specified: 1 – minimal priority, 10 – maximum priority. By default, 5 is used.

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight @ValidateRegex(regex = "^([1-9]|10)$") public void setMatrixCompilerPriority(int matrixCompilerPriority) { this.matrixCompilerPriority = matrixCompilerPriority; update(); } @Description("The setting that allows the user to set up the default value in the " + "#faild_unexpected field, which sets the way of comparing the messages, for example, in the receive action.
" + "Possible values in the #faild_unexpected field:
" + "
    " + "
  • N or n – only filtered fields are checked.
  • " + "
  • Y or n – all fields in the message are checked.
  • " + "
  • A or a – all fields in the message as well as the message structure are checked.
  • " + "
") @ValidateRegex(regex = "(?i)^(N|Y|A)$") public void setFailUnexpected(String failUnexpected) { this.failUnexpected = failUnexpected; update(); } public String getFailUnexpected() { return failUnexpected; } public ReportOutputFormat getReportOutputFormat(){ return reportOutputFormat; } public Set getExcludedMessages() { return excludedMessages; } @Description("These messages will not be presented in a report.
" + "The excluded messages must be listed separated by commas and must have the same names as the ones set in the dictionary.
" + "This feature might be useful for messages like Heartbeat – this will allow to decrease the size of the report, thus, saving memory, excluding undescriptive messages.

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight @ValidateRegex(regex = IDictionaryValidator.NAME_REGEX) public void setExcludedMessages(Set excludedMessages) { this.excludedMessages = CollectionUtils.isEmpty(excludedMessages) ? Collections.emptySet() : ImmutableSet.copyOf(excludedMessages); update(); } public RelevantMessagesSortingMode getRelevantMessagesSortingMode() { return relevantMessagesSortingMode; } @Description("This setting allows to change the way of displaying similar " + "messages in the failed actions of the report.
" + "Supported parameters:
" + "
    " + "
  • ARRIVAL_TIME – similar messages will be displayed in the same order as they have been received by " + "the service (by default).
  • " + "
  • FAILED_FIELDS – similar messages will be displayed in the report sorted by the number of failed fields, " + "from low to high. This function is only supported in an HTML report.
  • " + "
") @ValidateRegex(regex = "(?i)^(ARRIVAL_TIME|FAILED_FIELDS)$") public void setRelevantMessagesSortingMode(RelevantMessagesSortingMode relevantMessagesSortingMode) { this.relevantMessagesSortingMode = relevantMessagesSortingMode; } public BigDecimal getComparisonPrecision() { return comparisonPrecision; } @Description("Allows to set up the default sensibility of numeric values with a floating" + "point. The values are considered equal when their absolute difference does not exceed the set value.
" + "Comparison Precision is considered when Receive actions are executed and can be re-set up using the " + "Precision application function.

" + "NOTE: Changes of this setting will be applied only after Sailfish restart.") //TODO color highlight public void setComparisonPrecision(BigDecimal comparisonPrecision) { this.comparisonPrecision = comparisonPrecision; } public int getVerificationLimit() { return verificationLimit; } @Description("Limits the amount of saved verifications in the report. " + "If an action has more verifications than this limit allows, they will be truncated. " + "Works on per-action basis and does not affect related messages. " + "Value '-1' disables the limit") public void setVerificationLimit(int verificationLimit) { this.verificationLimit = verificationLimit; update(); } @Override public void load(HierarchicalConfiguration config) { if(!config.configurationsAt(GENERAL_KEY).isEmpty()) { loadGeneralSettings(config.configurationAt(GENERAL_KEY)); } if (!config.configurationsAt(SCRIPT_RUN).isEmpty()){ loadScriptRunSettings(config.configurationAt(SCRIPT_RUN)); } } private static Set parseSet(HierarchicalConfiguration config, String propertyName, String regex, Set defaultValue) { List value = config.getList(propertyName); if (CollectionUtils.isNotEmpty(value)) { Pattern pattern = Pattern.compile(regex); Set incorrectNames = new HashSet<>(); Set result = ImmutableSet.copyOf(value.stream() .map(Object::toString) .map(String::trim) .filter(StringUtils::isNotEmpty) .filter(name -> { if (pattern.matcher(name).matches()) { return true; } else { incorrectNames.add(name); return false; } }) .collect(Collectors.toSet())); if (!incorrectNames.isEmpty()) { logger.error("Property '{}' has incorrect values {}", propertyName, incorrectNames); } return result; } return defaultValue; } private void update() { if(!config.configurationsAt(GENERAL_KEY).isEmpty()) { updateGeneralSettings(config.configurationAt(GENERAL_KEY)); } if (!config.configurationsAt(SCRIPT_RUN).isEmpty()){ updateScriptRunSettings(config.configurationAt(SCRIPT_RUN)); } } private void loadGeneralSettings(HierarchicalConfiguration config) { this.fileStoragePath = config.getString("FileStoragePath", "storage"); this.storeAdminMessages = config.getBoolean("StoreAdminMessages", true); this.asyncRunMatrix = config.getBoolean(ASYNC_RUN_MATRIX_KEY, false); this.maxQueueSize = config.getLong(MAX_STORAGE_QUEUE_SIZE, 1024*1024*512); this.storageType = StorageType.parse(config.getString("StorageType", StorageType.DB.getName())); this.comparisonPrecision = config.getBigDecimal(COMPARISON_PRECISION, MathProcessor.COMPARISON_PRECISION); } private void updateGeneralSettings(HierarchicalConfiguration config) { config.setProperty("FileStoragePath", fileStoragePath); config.setProperty("StoreAdminMessages", storeAdminMessages); config.setProperty(ASYNC_RUN_MATRIX_KEY, asyncRunMatrix); config.setProperty("StorageType", storageType.getName()); config.setProperty(COMPARISON_PRECISION, comparisonPrecision); config.setProperty(MAX_STORAGE_QUEUE_SIZE, maxQueueSize); } private void loadScriptRunSettings(HierarchicalConfiguration config) { notificationIfServicesNotStarted = config.getBoolean(NOTIFICATION_IF_SOME_SERVICES_NOT_STARTED, false); failUnexpected = config.getString(FAIL_UNEXPECTED_KEY, "N"); matrixCompilerPriority = config.getInt(MATRIX_COMPILER_PRIORITY, Thread.NORM_PRIORITY); reportOutputFormat = ReportOutputFormat.parse(config.getString(REPORT_OUTPUT_FORMAT, ReportOutputFormat.ZIP_FILES.getName())); excludedMessages = parseSet(config, EXCLUDED_MESSAGES_FROM_REPORT, IDictionaryValidator.NAME_REGEX, excludedMessages); relevantMessagesSortingMode = RelevantMessagesSortingMode.parse(config.getString(RELEVANT_MESSAGES_SORTING_MODE, RelevantMessagesSortingMode.ARRIVAL_TIME.getName())); verificationLimit = config.getInt(VERIFICATION_LIMIT, 200); } private void updateScriptRunSettings(HierarchicalConfiguration config) { config.setProperty(NOTIFICATION_IF_SOME_SERVICES_NOT_STARTED, notificationIfServicesNotStarted); config.setProperty(FAIL_UNEXPECTED_KEY, failUnexpected); config.setProperty(MATRIX_COMPILER_PRIORITY, matrixCompilerPriority); config.setProperty(EXCLUDED_MESSAGES_FROM_REPORT, excludedMessages.isEmpty() ? "" : excludedMessages); config.setProperty(REPORT_OUTPUT_FORMAT, reportOutputFormat); config.setProperty(RELEVANT_MESSAGES_SORTING_MODE, relevantMessagesSortingMode.getName()); config.setProperty(VERIFICATION_LIMIT, verificationLimit); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy