/*
* Sakuli - Testing and Monitoring-Tool for Websites and common UIs.
*
* Copyright 2013 - 2016 the original author or authors.
*
* 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 org.sakuli.services.forwarder;
import org.apache.commons.lang.StringUtils;
import org.sakuli.datamodel.TestCase;
import org.sakuli.datamodel.TestCaseStep;
import org.sakuli.datamodel.TestSuite;
import org.sakuli.datamodel.properties.SakuliProperties;
import org.sakuli.datamodel.state.TestCaseState;
import org.sakuli.datamodel.state.TestSuiteState;
import org.sakuli.exceptions.SakuliRuntimeException;
import org.sakuli.services.forwarder.gearman.TextPlaceholder;
import org.sakuli.services.forwarder.gearman.model.ScreenshotDiv;
import org.sakuli.services.forwarder.gearman.model.builder.NagiosFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.SortedSet;
import java.util.stream.Collectors;
import static org.sakuli.services.forwarder.gearman.TextPlaceholder.*;
/**
* @author tschneck
* Date: 2/24/16
*/
public abstract class AbstractOutputBuilder {
public final static SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.YY HH:mm:ss");
protected Logger LOGGER = LoggerFactory.getLogger(getClass());
@Autowired
protected ScreenshotDivConverter screenshotDivConverter;
@Autowired
protected TestSuite testSuite;
public static String replacePlaceHolder(String message, PlaceholderMap placeholderStringMap) {
if (StringUtils.isBlank(message)) {
throw new SakuliRuntimeException("Template for resolving test suite output is EMPTY!");
}
String modifiedString = message;
for (TextPlaceholder key : placeholderStringMap.keySet()) {
modifiedString = StringUtils.replace(modifiedString, key.getPattern(), placeholderStringMap.get(key));
}
//check if still placeholders can be resolved
for (TextPlaceholder placeholder : placeholderStringMap.keySet()) {
if (StringUtils.contains(modifiedString, placeholder.getPattern())) {
return replacePlaceHolder(modifiedString, placeholderStringMap);
}
}
return modifiedString;
}
static String generateStepInformation(SortedSet<TestCaseStep> steps) {
StringBuilder sb = new StringBuilder();
steps.stream().filter(step -> step.getState().isWarning() || step.getState().isError())
.forEach(step -> {
sb.append(", step \"").append(step.getName()).append("\" ");
if (step.getState().isError()) {
sb.append("EXCEPTION: ").append(step.getExceptionMessages(true));
} else {
sb.append("over runtime (")
.append(NagiosFormatter.formatToSec(step.getDuration()))
.append("/warn at ")
.append(NagiosFormatter.formatToSec(step.getWarningTime()))
.append(")");
}
});
return sb.toString();
}
static String generateCaseInformation(SortedSet<TestCase> cases) {
StringBuilder sb = new StringBuilder();
cases.stream().filter(c -> c.getState().isWarning() || c.getState().isCritical() || c.getState().isError())
.forEach(c -> {
sb.append(", case \"").append(c.getName()).append("\" ");
if (c.getState().isError()) {
sb.append("EXCEPTION: ").append(c.getExceptionMessages(true));
} else {
sb.append("over runtime (").append(NagiosFormatter.formatToSec(c.getDuration()));
if (c.getState().isCritical()) {
sb.append("/crit at ").append(NagiosFormatter.formatToSec(c.getCriticalTime()));
} else {
sb.append("/warn at ").append(NagiosFormatter.formatToSec(c.getWarningTime()));
}
sb.append(")");
}
});
return sb.toString();
}
protected static String cutTo(String string, int summaryMaxLength) {
if (string != null && string.length() > summaryMaxLength) {
return StringUtils.substring(string, 0, summaryMaxLength) + " ...";
}
return string;
}
protected abstract int getSummaryMaxLength();
protected abstract String getOutputScreenshotDivWidth();
protected String formatTestSuiteSummaryStateMessage(TestSuite testSuite, String templateSuiteSummary) {
if (StringUtils.isBlank(templateSuiteSummary)) {
throw new SakuliRuntimeException("Template for resolving test suite output is EMPTY!");
}
String result = replacePlaceHolder(templateSuiteSummary, getTextPlaceholder(testSuite));
LOGGER.debug("{{xxx}} patterns in template '{}' replaced with message '{}'", templateSuiteSummary, result);
return cutTo(result, getSummaryMaxLength());
}
protected PlaceholderMap getTextPlaceholder(TestSuite testSuite) {
PlaceholderMap placeholderMap = new PlaceholderMap();
OutputState outputState = OutputState.lookupSakuliState(testSuite.getState());
ScreenshotDiv screenshotDiv = screenshotDivConverter.convert(testSuite.getException());
placeholderMap.put(STATE, outputState.name());
placeholderMap.put(STATE_SHORT, outputState.getShortState());
placeholderMap.put(STATE_DESC, testSuite.getState().getNagiosStateDescription());
placeholderMap.put(SUITE_SUMMARY, generateStateSummary(testSuite.getState()));
placeholderMap.put(NAME, testSuite.getName());
placeholderMap.put(ID, testSuite.getId());
placeholderMap.put(DURATION, String.format(Locale.ENGLISH, "%.2f", testSuite.getDuration()));
placeholderMap.put(START_DATE, (testSuite.getStartDate() == null) ? "xx" : dateFormat.format(testSuite.getStartDate()));
placeholderMap.put(STOP_DATE, (testSuite.getStopDate() == null) ? "xx" : dateFormat.format(testSuite.getStopDate()));
placeholderMap.put(WARN_THRESHOLD, String.valueOf(testSuite.getWarningTime()));
placeholderMap.put(CRITICAL_THRESHOLD, String.valueOf(testSuite.getCriticalTime()));
placeholderMap.put(ERROR_SCREENSHOT, screenshotDiv != null ? screenshotDiv.getPayloadString() : null);
placeholderMap.put(ERROR_MESSAGE, testSuite.getExceptionMessages(true));
placeholderMap.put(SUITE_FOLDER, testSuite.getTestSuiteFolder() != null ? testSuite.getTestSuiteFolder().toString() : null);
placeholderMap.put(HOST, testSuite.getHost());
placeholderMap.put(BROWSER_INFO, testSuite.getBrowserInfo());
placeholderMap.put(TD_CSS_CLASS, "service" + outputState.name());
placeholderMap.put(CASE_INFORMATION, generateCaseInformation(testSuite.getTestCasesAsSortedSet()));
placeholderMap.put(STEP_INFORMATION,
testSuite.getTestCasesAsSortedSet().stream()
.map(c -> generateStepInformation(c.getStepsAsSortedSet()))
.collect(Collectors.joining()));
return placeholderMap;
}
private String generateStateSummary(TestSuiteState state) {
StringBuilder summary = new StringBuilder(state.isError() ? "" : STATE_DESC.getPattern());
switch (state) {
case OK:
summary.append(" (").append(DURATION.getPattern()).append("s)");
break;
case WARNING_IN_STEP:
summary.append(STEP_INFORMATION.getPattern());
break;
case WARNING_IN_CASE:
summary.append(CASE_INFORMATION.getPattern());
break;
case WARNING_IN_SUITE:
summary.append(" (").append(DURATION.getPattern()).append("s/warn at ").append(WARN_THRESHOLD.getPattern()).append("s)");
break;
case CRITICAL_IN_CASE:
summary.append(CASE_INFORMATION.getPattern());
break;
case CRITICAL_IN_SUITE:
summary.append(" (").append(DURATION.getPattern()).append("s/crit at ").append(CRITICAL_THRESHOLD.getPattern()).append("s)");
break;
case ERRORS:
summary.append("(").append(DURATION.getPattern()).append("s) ").append(STATE_DESC.getPattern()).append(": '").append(ERROR_MESSAGE.getPattern()).append("'");
break;
default:
break;
}
return summary.toString();
}
protected PlaceholderMap getTextPlaceholder(TestCase testCase) {
PlaceholderMap placeholderMap = new PlaceholderMap();
OutputState outputState = OutputState.lookupSakuliState(testCase.getState());
placeholderMap.put(STATE, outputState.name());
placeholderMap.put(STATE_SHORT, outputState.getShortState());
placeholderMap.put(STATE_DESC, (testCase.getState() == null)
? TestCaseState.ERRORS.getNagiosStateDescription()
: testCase.getState().getNagiosStateDescription());
placeholderMap.put(NAME, testCase.getName());
placeholderMap.put(ID, testCase.getId());
placeholderMap.put(DURATION, String.format(Locale.ENGLISH, "%.2f", testCase.getDuration()));
placeholderMap.put(START_DATE, (testCase.getStartDate() == null) ? "xx" : dateFormat.format(testCase.getStartDate()));
placeholderMap.put(STOP_DATE, (testCase.getStopDate() == null) ? "xx" : dateFormat.format(testCase.getStopDate()));
placeholderMap.put(WARN_THRESHOLD, String.valueOf(testCase.getWarningTime()));
placeholderMap.put(CRITICAL_THRESHOLD, String.valueOf(testCase.getCriticalTime()));
placeholderMap.put(ERROR_MESSAGE, testCase.getExceptionMessages(true));
placeholderMap.put(ERROR_SCREENSHOT, generateTestCaseScreenshotsHTML(testCase));
placeholderMap.put(STEP_INFORMATION, generateStepInformation(testCase.getStepsAsSortedSet()));
placeholderMap.put(CASE_FILE, testCase.getTcFile() != null ? testCase.getTcFile().toString() : null);
placeholderMap.put(CASE_START_URL, testCase.getStartUrl());
placeholderMap.put(CASE_LAST_URL, testCase.getLastURL());
placeholderMap.put(TD_CSS_CLASS, "service" + outputState.name());
return placeholderMap;
}
/**
* Generates '<div></div>' tag for the screenshots included in the {@link TestCase} and the suppressed {@link TestCaseStep}s.
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
protected String generateTestCaseScreenshotsHTML(TestCase testCase) {
StringBuilder sb = new StringBuilder();
ScreenshotDiv caseDiv = screenshotDivConverter.convert(testCase.getException());
if (caseDiv != null) {
sb.append(caseDiv.getPayloadString());
}
for (TestCaseStep step : testCase.getStepsAsSortedSet()) {
ScreenshotDiv stepDiv = screenshotDivConverter.convert(step.getException());
if (stepDiv != null) {
sb.append(stepDiv.getPayloadString());
}
}
return sb.toString();
}
}