/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.integration.regression;
import static org.testng.AssertJUnit.assertTrue;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collections;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.opengamma.financial.tool.ToolContext;
import com.opengamma.util.test.TestGroup;
/**
*
*/
public abstract class AbstractRegressionTest {
private static final String LATEST_BUILD_VERSION = "Latest build";
private static final String FILE_WRITE_MODE_PROPERTY = "Regression.writeReportToFile";
private static final String CONSOLE_WRITE_MODE_PROPERTY = "Regression.writeReportToConsole";
private static final double s_defaultAcceptableDelta = 0.0000001;
private RegressionTestToolContextManager _contextManager;
private GoldenCopyPersistenceHelper _goldenCopyPersistenceHelper;
private static final String s_defaultRegressionToolContext = "classpath:regression/regression-toolcontext.properties";
/**
* Initializes the test. A valid tool context properties file is required - this cut down context is used to
* initialize the database. Secondly, a "regressionPropertiesFile" is also required. This is used to execute
* the views and must therefore contain a full engine configuration. Typically this can be created by using
* the fullstack.properties/ini as a starting point, removing the enterprise services such as web and amq
* exposure.
*
* @param regressionRoot the root for this set of tests (i.e. the directory
* containing the dbdump zip and golden_copy folder
* @param toolContextPropertiesFile path to a valid tool context properties file
* @param regressionPropertiesFile path to a valid regression properties file
*/
public AbstractRegressionTest(File regressionRoot, String toolContextPropertiesFile, String regressionPropertiesFile) {
_contextManager = new RegressionTestToolContextManager(new File(regressionRoot, GoldenCopyDumpCreator.DB_DUMP_ZIP), toolContextPropertiesFile, regressionPropertiesFile);
_goldenCopyPersistenceHelper = new GoldenCopyPersistenceHelper(regressionRoot);
}
public AbstractRegressionTest(File regressionRoot, String regressionPropertiesFile) {
this(regressionRoot, s_defaultRegressionToolContext, regressionPropertiesFile);
}
@BeforeTest(groups = TestGroup.UNIT)
public void initContext() {
_contextManager.init();
}
@AfterTest(groups = TestGroup.UNIT)
public void closeContext() {
_contextManager.close();
}
/**
* Executes viewName against snapshotName in the running engine context.
* @param viewName name of the view to run
* @param snapshotName name of the snapshot to run
*/
protected final void runTestForView(String viewName, String snapshotName) {
ToolContext toolContext = _contextManager.getToolContext();
GoldenCopy original = _goldenCopyPersistenceHelper.load(viewName, snapshotName);
ViewRunner viewRunner = new ViewRunner(toolContext.getConfigMaster(),
toolContext.getViewProcessor(),
toolContext.getPositionSource(),
toolContext.getSecuritySource(),
toolContext.getMarketDataSnapshotMaster());
CalculationResults thisRun = viewRunner.run(LATEST_BUILD_VERSION, viewName, snapshotName, original.getValuationTime());
CalculationDifference differences = evaluateDifferences(original, thisRun);
String baseVersion = original.getCalculationResults().getVersion();
RegressionTestResults testResults = new RegressionTestResults(baseVersion, LATEST_BUILD_VERSION, Collections.singleton(differences));
if (isWriteReportToFile()) {
writeReportToFile(testResults, viewName, snapshotName);
}
if (isWriteReportToConsole()) {
writeReportToConsole(testResults);
}
assertTrue("Found results only in base", differences.getOnlyBase().isEmpty());
assertTrue("Found results only in test", differences.getOnlyTest().isEmpty());
assertTrue("Found differing results", differences.getDifferent().isEmpty());
assertTrue("Found differing result properties", differences.getDifferentProperties().isEmpty());
}
private void writeReportToConsole(RegressionTestResults testResults) {
OutputStreamWriter writer = new OutputStreamWriter(System.out);
ReportGenerator.generateReport(testResults, ReportGenerator.Format.TEXT, writer);
}
private void writeReportToFile(RegressionTestResults testResults, String viewName, String snapshotName) {
File file;
FileWriter fileWriter;
try {
file = getDifferencesReportFile(viewName, snapshotName);
fileWriter = new FileWriter(getDifferencesReportFile(viewName, snapshotName));
} catch (IOException ex) {
throw Throwables.propagate(ex);
}
ReportGenerator.generateReport(testResults, ReportGenerator.Format.TEXT, fileWriter);
System.out.println("Differences report written to " + file.getAbsolutePath());
}
private CalculationDifference evaluateDifferences(GoldenCopy original, CalculationResults thisRun) {
CalculationDifference result = CalculationDifference.generatorWithDelta(getAcceptableDelta()).
compareValueProperties(compareValueProperties()).
between(original.getCalculationResults(), thisRun);
System.out.println("Total results in golden copy: " + original.getCalculationResults().getValues().size());
System.out.println("Total results in test run: " + thisRun.getValues().size());
System.out.println("Equal: " + result.getEqualResultCount());
System.out.println("Different: " + result.getDifferent().size());
if (compareValueProperties()) {
System.out.println("Different properties: " + result.getDifferentProperties().size());
}
System.out.println("Only base: " + result.getOnlyBase().size());
System.out.println("Only test: " + result.getOnlyTest().size());
return result;
}
//---------------------------------------------------------------------------------------------------------
//default test settings for overriding
//---------------------------------------------------------------------------------------------------------
/**
* The smallest acceptable delta when comparing outputs.
* @return a double
*/
protected double getAcceptableDelta() {
return s_defaultAcceptableDelta;
}
/**
* Whether to compare value properties. Not normally significant if numbers match ok.
* False unless overridden.
* @return a boolean
*/
protected boolean compareValueProperties() {
return false;
}
/**
* If true, a report with the differences will be written to
* the location specified by {@link #getDifferencesReportFile(String, String)}.
* @return True if specified as a system property by {@value #FILE_WRITE_MODE_PROPERTY},
* else false.
*/
protected boolean isWriteReportToFile() {
return Boolean.getBoolean(FILE_WRITE_MODE_PROPERTY);
}
/**
* A {@link File} giving the location to write the difference
* report to.
* @param viewName the view which ran
* @param snapshotName the snapshot which was run against
* @return the location to write the differences report to
* @throws IOException
*/
protected File getDifferencesReportFile(String viewName, String snapshotName) throws IOException {
String tempDir = System.getProperty("java.io.tmpdir");
File regressionDir = new File(tempDir, "regression-report");
if (!regressionDir.exists()) {
Preconditions.checkState(regressionDir.mkdirs(), "Unable to mkdir " + regressionDir.getPath());
}
return new File(regressionDir, viewName + "-" + snapshotName + ".txt");
}
/**
* If true, a report will be written to console.
* @return If defined, will return the value given as a system property by
* {@value #CONSOLE_WRITE_MODE_PROPERTY}. Else defaults to true.
*/
protected boolean isWriteReportToConsole() {
if (System.getProperty(CONSOLE_WRITE_MODE_PROPERTY) != null) {
return Boolean.getBoolean(CONSOLE_WRITE_MODE_PROPERTY);
}
return true;
}
}