blob: 95c07d0a21c17608fe9d61eb0f5e2035a4249623 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Christian Pontesegger 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
*
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
package org.eclipse.ease.modules.unittest.components;
import java.io.File;
import java.util.Collection;
import java.util.Map.Entry;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.ease.ExitException;
import org.eclipse.ease.IScriptEngine;
import org.eclipse.ease.ScriptResult;
import org.eclipse.ease.modules.EnvironmentModule;
import org.eclipse.ease.modules.unittest.Bundle;
import org.eclipse.ease.modules.unittest.modules.UnitTestModule;
import org.eclipse.ease.tools.ResourceTools;
public class TestFile extends TestComposite implements Comparable<TestFile> {
private class TestFileJob extends Job {
public TestFileJob(final String name) {
super(name);
}
@Override
protected IStatus run(final IProgressMonitor monitor) {
final Object testFile = ResourceTools.resolveFile(fFileLocation, getTestSuite().getModel().getFile(), true);
if (testFile == null) {
// no test file available
setStatus(TestStatus.FAILURE);
getTestSuite().addTestResult(TestStatus.FAILURE, "Test file \"" + fFileLocation + "\" not found");
return Status.CANCEL_STATUS;
}
// clear old tests
reset();
setStatus(TestStatus.RUNNING);
// setup engine
setScriptEngine(getTestSuite().createScriptEngine());
// connect output streams
getScriptEngine().setOutputStream(getTestSuite().getOutputStream());
getScriptEngine().setErrorStream(getTestSuite().getErrorStream());
// add variables
getScriptEngine().setTerminateOnIdle(false);
for (final Entry<String, Object> entry : getTestSuite().getVariables().entrySet())
if (!entry.getKey().startsWith(EnvironmentModule.MODULE_PREFIX))
getScriptEngine().setVariable(entry.getKey(), entry.getValue());
getScriptEngine().setVariable(CURRENT_TESTCOMPOSITE, TestFile.this);
// load unit module
// TODO make sure this is compatible with any engine
getScriptEngine().executeAsync("loadModule('" + UnitTestModule.MODULE_NAME + "')");
// start engine
getScriptEngine().schedule();
boolean runTeardown = true;
try {
// check for user abort request
if (monitor.isCanceled()) {
addTestResult(TestStatus.FAILURE, "Test aborted by user");
return Status.CANCEL_STATUS;
}
// testFile setup()
if (!runCodeFragment(TestSuiteModel.CODE_LOCATION_TESTFILE_SETUP, monitor))
return Status.OK_STATUS;
// check for abort request
if (monitor.isCanceled()) {
addTestResult(TestStatus.FAILURE, "Test aborted by user");
return Status.CANCEL_STATUS;
}
// execute test code
final ScriptResult testFileResult = getScriptEngine().executeSync(testFile);
if (testFileResult.hasException()) {
// this is probably an exception due to calling exit()
if (!(testFileResult.getException() instanceof ExitException)) {
// we had a real exception, inform user
addTestResult(TestStatus.FAILURE, TestSuite.getExceptionMessage(testFileResult.getException()));
runTeardown = getTestSuite().getModel().getFlag(TestSuiteModel.FLAG_EXECUTE_TEARDOWN_ON_FAILURE, true);
return Status.OK_STATUS;
}
}
// check for abort request
if (monitor.isCanceled()) {
addTestResult(TestStatus.FAILURE, "Test aborted by user");
return Status.CANCEL_STATUS;
}
} catch (final InterruptedException e) {
runTeardown = getTestSuite().getModel().getFlag(TestSuiteModel.FLAG_EXECUTE_TEARDOWN_ON_FAILURE, true);
return Status.CANCEL_STATUS;
} finally {
// testFile teardown()
if (runTeardown) {
try {
runCodeFragment(TestSuiteModel.CODE_LOCATION_TESTFILE_TEARDOWN, monitor);
} catch (final InterruptedException e) {
// TODO handle this exception (but for now, at least know it happened)
throw new RuntimeException(e);
}
}
// make sure all tests are marked as terminated
// used for badly written test cases and when tests fail by throwing an exception
for (final Test test : getTests())
test.setStatus(TestStatus.PASS);
// clean up havoc engines
if (!getScriptEngine().isFinished())
getScriptEngine().terminate();
setScriptEngine(null);
setStatus(TestStatus.PASS);
}
return Status.OK_STATUS;
}
private boolean runCodeFragment(final String fragmentID, final IProgressMonitor monitor) throws InterruptedException {
final String fragmentCode = getCodeFragment(fragmentID);
if ((fragmentCode != null) && (!fragmentCode.trim().isEmpty())) {
addTest(new Test(TestFile.this, "[" + fragmentID + "]", true));
final ScriptResult setupResult = getScriptEngine().executeSync(fragmentCode);
if (setupResult.hasException()) {
// testFile setup failed
addTestResult(TestStatus.FAILURE, TestSuite.getExceptionMessage(setupResult.getException()));
endTest();
return false;
}
endTest();
}
return true;
}
}
private TestFileJob fJob;
private final String fFileLocation;
public TestFile(final TestSuite suite, final String fileLocation) {
super(suite);
fFileLocation = fileLocation;
}
public void execute() {
fJob = new TestFileJob("TestFile: " + toString());
fJob.schedule();
}
public String getCodeFragment(final String identifier) {
return getTestSuite().getModel().getCodeFragment(identifier);
}
public void terminate() {
if (fJob != null) {
fJob.cancel();
final IScriptEngine engine = getScriptEngine();
if (engine != null)
engine.terminateCurrent();
}
}
public TestSuite getTestSuite() {
return (TestSuite) getParent();
}
@Override
public Collection<? extends TestEntity> getChildren() {
return getTests();
}
@Override
public void reset() {
final IFile parent = (getTestSuite() != null) ? getTestSuite().getModel().getFile() : null;
final Object file = ResourceTools.resolveFile(fFileLocation, parent, true);
if (file instanceof IFile) {
try {
((IFile) file).deleteMarkers(Bundle.PLUGIN_ID + ".scriptassertion", false, IResource.DEPTH_ZERO);
} catch (final CoreException e) {
// TODO handle this exception (but for now, at least know it happened)
throw new RuntimeException(e);
}
}
super.reset();
}
@Override
public int compareTo(final TestFile o) {
return fFileLocation.compareTo(o.fFileLocation);
}
@Override
public Object getFile() {
return ResourceTools.resolveFile(fFileLocation, getTestSuite().getModel().getFile(), true);
}
@Override
public String toString() {
final Object file = getFile();
if (file instanceof IFile)
return ((IFile) file).getName();
if (file instanceof File)
return ((File) file).getName();
return super.toString();
}
}