/******************************************************************************* * Copyright (c) 2013 Rene Schneider, GEBIT Solutions GmbH and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package de.gebit.integrity.runner.callbacks.console; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.google.inject.Inject; import de.gebit.integrity.dsl.Call; import de.gebit.integrity.dsl.ConstantEntity; import de.gebit.integrity.dsl.Suite; import de.gebit.integrity.dsl.SuiteDefinition; import de.gebit.integrity.dsl.SuiteReturn; import de.gebit.integrity.dsl.TableTest; import de.gebit.integrity.dsl.TableTestRow; import de.gebit.integrity.dsl.Test; import de.gebit.integrity.dsl.ValueOrEnumValueOrOperationCollection; import de.gebit.integrity.dsl.VariableAssignment; import de.gebit.integrity.dsl.VariableEntity; import de.gebit.integrity.dsl.VariantDefinition; import de.gebit.integrity.dsl.VisibleComment; import de.gebit.integrity.dsl.VisibleDivider; import de.gebit.integrity.exceptions.MethodNotFoundException; import de.gebit.integrity.fixtures.ExtendedResultFixture.ExtendedResult; import de.gebit.integrity.fixtures.ExtendedResultFixture.ExtendedResultHTML; import de.gebit.integrity.fixtures.ExtendedResultFixture.ExtendedResultImage; import de.gebit.integrity.fixtures.ExtendedResultFixture.ExtendedResultText; import de.gebit.integrity.operations.UnexecutableException; import de.gebit.integrity.parameter.conversion.ConversionContext; import de.gebit.integrity.parameter.resolving.ParameterResolver; import de.gebit.integrity.parameter.variables.VariableManager; import de.gebit.integrity.remoting.transport.enums.TestRunnerCallbackMethods; import de.gebit.integrity.runner.TestModel; import de.gebit.integrity.runner.callbacks.AbstractTestRunnerCallback; import de.gebit.integrity.runner.callbacks.TestFormatter; import de.gebit.integrity.runner.results.SuiteResult; import de.gebit.integrity.runner.results.SuiteSummaryResult; import de.gebit.integrity.runner.results.call.CallResult; import de.gebit.integrity.runner.results.test.TestComparisonFailureResult; import de.gebit.integrity.runner.results.test.TestComparisonResult; import de.gebit.integrity.runner.results.test.TestExceptionSubResult; import de.gebit.integrity.runner.results.test.TestExecutedSubResult; import de.gebit.integrity.runner.results.test.TestResult; import de.gebit.integrity.runner.results.test.TestSubResult; import de.gebit.integrity.utils.DateUtil; import de.gebit.integrity.utils.IntegrityDSLUtil; import de.gebit.integrity.utils.ParameterUtil; /** * A simple callback which prints out test progression information onto the console. * * * @author Rene Schneider - initial API and implementation * */ public class ConsoleTestCallback extends AbstractTestRunnerCallback { /** * Test execution start time. */ protected long startTime; /** * The number of tests executed. */ protected int testCount; /** * Counting table test rows. */ protected int tableTestRowCount; /** * The number of calls executed. */ protected int callCount; /** * The number of suites executed. */ protected int suiteCount; /** * Map remembering suite numbers. */ protected Map<Suite, Integer> suiteNumbers = new HashMap<Suite, Integer>(); /** * The classloader to use. */ @Inject protected ClassLoader classLoader; /** * The parameter resolver to use. */ @Inject protected ParameterResolver parameterResolver; /** * The variable manager to use. */ @Inject protected VariableManager variableManager; /** * The test formatter to use. */ @Inject protected TestFormatter testFormatter; @Override public void onExecutionStart(TestModel aModel, VariantDefinition aVariant) { String tempLine = "Test execution has begun"; if (aVariant != null) { tempLine += " (variant '" + aVariant.getName() + "'"; if (aVariant.getDescription() != null) { tempLine += ": '" + aVariant.getDescription() + "'"; } tempLine += ")"; } tempLine += "..."; println(tempLine); startTime = System.nanoTime(); } @Override public void onTestStart(Test aTest) { testCount++; try { println("Now running test " + testCount + ": " + testFormatter.testToHumanReadableString(aTest, null) + "..."); } catch (ClassNotFoundException exc) { exc.printStackTrace(); } catch (UnexecutableException exc) { exc.printStackTrace(); } catch (InstantiationException exc) { exc.printStackTrace(); } catch (MethodNotFoundException exc) { exc.printStackTrace(); } } @Override public void onTestFinish(Test aTest, TestResult aResult) { displayTestSubResult(aResult.getSubResults().get(0)); displayExtendedResults(aResult.getExtendedResults()); } /** * Displays the provided extended results on the console. * * @param someExtendedResults * the extended result list to display */ protected void displayExtendedResults(List<ExtendedResult> someExtendedResults) { int tempImageCount = 0; int tempHtmlCount = 0; if (someExtendedResults != null) { for (ExtendedResult tempResult : someExtendedResults) { if (tempResult instanceof ExtendedResultText) { println("Ext. result: " + ((ExtendedResultText) tempResult).getText()); } else if (tempResult instanceof ExtendedResultImage) { tempImageCount++; } else if (tempResult instanceof ExtendedResultHTML) { tempHtmlCount++; } } if (tempImageCount > 0) { println("Ext. result: " + tempImageCount + " images"); } if (tempHtmlCount > 0) { println("Ext. result: " + tempHtmlCount + " hypertext snippets"); } } } /** * Displays a test sub-result. * * @param aSubResult * the sub-result to display */ protected void displayTestSubResult(TestSubResult aSubResult) { if (aSubResult instanceof TestExecutedSubResult) { if (aSubResult.wereAllComparisonsSuccessful()) { println("SUCCESS!"); } else { print("FAILURE: "); boolean tempHasBegun = false; for (Entry<String, TestComparisonResult> tempEntry : aSubResult.getComparisonResults().entrySet()) { if (tempEntry.getValue() instanceof TestComparisonFailureResult) { if (tempHasBegun) { print("; "); } // Either there is an expected value, or if there isn't, "true" is the default ValueOrEnumValueOrOperationCollection tempExpectedValue = tempEntry.getValue() .getExpectedValue(); boolean tempExpectedIsNestedObject = containsNestedObject(tempExpectedValue); print("'" + valueConverter.convertValueToString( (tempExpectedValue == null ? true : tempExpectedValue), false, null) + "' expected" + (tempEntry.getKey().equals(ParameterUtil.DEFAULT_PARAMETER_NAME) ? "" : " for '" + tempEntry.getKey() + "'") + ", but got '" + convertResultValueToStringGuarded(tempEntry.getValue().getActualValue(), aSubResult, tempExpectedIsNestedObject, new ConversionContext().withComparisonResult(tempEntry.getValue().getResult())) + "'!"); tempHasBegun = true; } } println(""); } } else if (aSubResult instanceof TestExceptionSubResult) { println("EXCEPTION OCCURRED, SEE STDERR!"); ((TestExceptionSubResult) aSubResult).getException().printStackTrace(); } } @Override public void onExecutionFinish(TestModel aModel, SuiteSummaryResult aResult) { if (aResult != null) { println("Finished executing " + suiteCount + " suites with " + testCount + " tests and " + callCount + " calls in " + DateUtil .convertNanosecondTimespanToHumanReadableFormat(System.nanoTime() - startTime, false, false) + "!"); println(aResult.getTestSuccessCount() + " tests finished sucessfully, accompanied by " + aResult.getTestFailCount() + " failures and " + aResult.getExceptionCount() + " exceptions."); } } @Override public void onSuiteStart(Suite aSuite) { suiteCount++; suiteNumbers.put(aSuite, suiteCount); println("Now entering suite " + suiteCount + ": " + IntegrityDSLUtil.getQualifiedSuiteName(aSuite.getDefinition())); } @Override public void onSuiteFinish(Suite aSuite, SuiteSummaryResult aResult) { println("Now leaving suite " + suiteNumbers.remove(aSuite) + ": " + IntegrityDSLUtil.getQualifiedSuiteName(aSuite.getDefinition())); } @Override public void onVariableDefinition(VariableEntity aDefinition, SuiteDefinition aSuite, Object anInitialValue) { println("Defined variable " + IntegrityDSLUtil.getQualifiedVariableEntityName(aDefinition, false) + (anInitialValue == null ? "" : " with initial value: " + valueConverter.convertValueToString(anInitialValue, false, null))); } @Override public void onConstantDefinition(ConstantEntity aDefinition, SuiteDefinition aSuite, Object aValue, boolean aParameterizedFlag) { println("Defined constant " + IntegrityDSLUtil.getQualifiedVariableEntityName(aDefinition, false) + (aValue == null ? "" : " with value: " + valueConverter.convertValueToString(aValue, false, null)) + (aParameterizedFlag ? " (parameterized)" : "")); } @Override public void onVariableAssignment(VariableAssignment anAssignment, VariableEntity aDefinition, SuiteDefinition aSuite, Object aValue) { println("Assigned variable " + IntegrityDSLUtil.getQualifiedVariableEntityName(aDefinition, false) + " - new value: " + valueConverter.convertValueToString(aValue, false, null)); } @Override public void onReturnVariableAssignment(SuiteReturn aReturn, VariableEntity aSource, VariableEntity aTarget, Suite aSuite, Object aValue) { println("Assigned return variable " + IntegrityDSLUtil.getQualifiedVariableEntityName(aSource, false) + " to calling suites' variable " + IntegrityDSLUtil.getQualifiedVariableEntityName(aTarget, false) + " - returned value: " + valueConverter.convertValueToString(aValue, false, null)); } @Override public void onCallStart(Call aCall) { callCount++; try { println("Now executing call " + callCount + ": " + testFormatter.callToHumanReadableString(aCall, null) + "..."); } catch (ClassNotFoundException exc) { exc.printStackTrace(); } catch (UnexecutableException exc) { exc.printStackTrace(); } catch (InstantiationException exc) { exc.printStackTrace(); } catch (MethodNotFoundException exc) { exc.printStackTrace(); } } @Override public void onCallFinish(Call aCall, CallResult aResult) { if (aResult instanceof de.gebit.integrity.runner.results.call.SuccessResult) { println("SUCCESS!"); } else if (aResult instanceof de.gebit.integrity.runner.results.call.ExceptionResult) { println("EXCEPTION OCCURRED, SEE STDERR!"); System.err.println(aResult.toString()); } displayExtendedResults(aResult.getExtendedResults()); } @Override public void onSetupStart(SuiteDefinition aSetupSuite) { println("Now entering setup suite: " + IntegrityDSLUtil.getQualifiedSuiteName(aSetupSuite)); } @Override public void onSetupFinish(SuiteDefinition aSetupSuite, SuiteResult aResult) { println("Now leaving setup suite: " + IntegrityDSLUtil.getQualifiedSuiteName(aSetupSuite)); } @Override public void onTearDownStart(SuiteDefinition aTearDownSuite) { println("Now entering teardown suite: " + IntegrityDSLUtil.getQualifiedSuiteName(aTearDownSuite)); } @Override public void onTearDownFinish(SuiteDefinition aTearDownSuite, SuiteResult aResult) { println("Now leaving teardown suite: " + IntegrityDSLUtil.getQualifiedSuiteName(aTearDownSuite)); } @Override public void onTableTestStart(TableTest aTableTest) { testCount++; tableTestRowCount = 0; println("Now running table test " + testCount + ":"); } @Override public void onTableTestRowStart(TableTest aTableTest, TableTestRow aRow) { tableTestRowCount++; try { print("\tRow " + tableTestRowCount + " (" + testFormatter.tableTestRowToHumanReadableString(aTableTest, aRow, null) + ")..."); } catch (ClassNotFoundException exc) { exc.printStackTrace(); } catch (UnexecutableException exc) { exc.printStackTrace(); } catch (InstantiationException exc) { exc.printStackTrace(); } catch (MethodNotFoundException exc) { exc.printStackTrace(); } } @Override public void onTableTestRowFinish(TableTest aTableTest, TableTestRow aRow, TestSubResult aSubResult) { displayTestSubResult(aSubResult); } @Override public void onTableTestFinish(TableTest aTableTest, TestResult someResults) { println("\tTotal: " + someResults.getSubTestSuccessCount() + "x SUCCESS, " + someResults.getSubTestFailCount() + "x FAILURE, " + someResults.getSubTestExceptionCount() + "x EXCEPTION."); displayExtendedResults(someResults.getExtendedResults()); } @Override public void onVisibleComment(String aCommentText, boolean anIsTitle, VisibleComment aCommentElement) { if (!isDryRun()) { // don't want to print this if we're not actually executing stuff String tempDelimiters = (anIsTitle ? "**" : "--"); System.out.println(" " + tempDelimiters + " " + aCommentText + " " + tempDelimiters); } } @Override public void onVisibleDivider(String aDividerText, VisibleDivider aDividerElement) { if (!isDryRun()) { // don't want to print this if we're not actually executing stuff System.out.println(" " + aDividerText + ""); } } @Override public void onAbortExecution(String anAbortExecutionMessage, String anAbortExecutionStackTrace) { if (!isDryRun()) { System.out.print("TEST EXECUTION WAS ABORTED"); if (anAbortExecutionMessage != null) { System.out.println(": " + anAbortExecutionMessage); } else { System.out.println("!"); } } } @Override public void onMessageFromFork(TestRunnerCallbackMethods aMethod, Serializable... someObjects) { // nothing to do; this callback is not fork-aware } /** * Prints something, if we're not currently in a dry run. * * @param aString * the string to print */ protected void print(String aString) { if (!isDryRun()) { System.out.print(aString); } } /** * Prints plus newline, if we're not currently in a dry run. * * @param aString * the string to print */ protected void println(String aString) { if (!isDryRun()) { System.out.println(aString); } } }