blob: 550ca6690cfdef7be6b15bbe70a31234ade33eeb [file] [log] [blame]
package com.jetbrains.env.ut;
import com.google.common.collect.Lists;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunManagerEx;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.Filter;
import com.intellij.execution.testframework.sm.runner.SMTestProxy;
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView;
import com.intellij.execution.testframework.sm.runner.ui.TestResultsViewer;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Key;
import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.XDebuggerTestUtil;
import com.jetbrains.env.PyExecutionFixtureTestTask;
import com.jetbrains.python.sdk.PythonEnvUtil;
import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
import com.jetbrains.python.testing.PythonTestConfigurationType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
/**
* Tasks to run unit test configurations.
* You should extend it either implementing {@link #after()} and {@link #before()} or implement {@link #runTestOn(String)}
* yourself and use {@link #runConfiguration(com.intellij.execution.configurations.ConfigurationFactory, String, com.intellij.openapi.project.Project)}
* or {@link #runConfiguration(com.intellij.execution.RunnerAndConfigurationSettings, com.intellij.execution.configurations.RunConfiguration)} .
* Use {@link #myDescriptor} and {@link #myConsoleView} to check output
*
* @author traff
*/
public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
protected ProcessHandler myProcessHandler;
private boolean shouldPrintOutput = false;
/**
* Test root node
*/
protected SMTestProxy.SMRootTestProxy myTestProxy;
/**
* Output test console
*/
protected SMTRunnerConsoleView myConsoleView;
/**
* Test run descriptor
*/
protected RunContentDescriptor myDescriptor;
private StringBuilder myOutput;
private boolean mySetUp = false;
public PyUnitTestTask() {
}
public PyUnitTestTask(String workingFolder, String scriptName, String scriptParameters) {
setWorkingFolder(getTestDataPath() + workingFolder);
setScriptName(scriptName);
setScriptParameters(scriptParameters);
}
public PyUnitTestTask(String workingFolder, String scriptName) {
this(workingFolder, scriptName, null);
}
@Override
public void setUp(final String testName) throws Exception {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
try {
if (myFixture == null) {
PyUnitTestTask.super.setUp(testName);
mySetUp = true;
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
});
}
@NotNull
protected String output() {
return myOutput.toString();
}
@Override
public void tearDown() throws Exception {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
try {
if (mySetUp) {
if (myConsoleView != null) {
Disposer.dispose(myConsoleView);
myConsoleView = null;
}
if (myDescriptor != null) {
Disposer.dispose(myDescriptor);
myDescriptor = null;
}
PyUnitTestTask.super.tearDown();
mySetUp = false;
}
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
);
}
@Override
public void runTestOn(String sdkHome) throws Exception {
final Project project = getProject();
final ConfigurationFactory factory = PythonTestConfigurationType.getInstance().PY_UNITTEST_FACTORY;
runConfiguration(factory, sdkHome, project);
}
protected void runConfiguration(ConfigurationFactory factory, String sdkHome, final Project project) throws Exception {
final RunnerAndConfigurationSettings settings =
RunManager.getInstance(project).createRunConfiguration("test", factory);
AbstractPythonTestRunConfiguration config = (AbstractPythonTestRunConfiguration)settings.getConfiguration();
config.setSdkHome(sdkHome);
config.setScriptName(getScriptPath());
config.setWorkingDirectory(getWorkingFolder());
PythonSdkFlavor sdk = PythonSdkFlavor.getFlavor(sdkHome);
if (sdk instanceof JythonSdkFlavor) {
config.setInterpreterOptions(JythonSdkFlavor.getPythonPathCmdLineArgument(Lists.<String>newArrayList(getWorkingFolder())));
}
else {
PythonEnvUtil.addToPythonPath(config.getEnvs(), getWorkingFolder());
}
configure(config);
new WriteAction() {
@Override
protected void run(@NotNull Result result) throws Throwable {
RunManagerEx.getInstanceEx(project).addConfiguration(settings, false);
RunManagerEx.getInstanceEx(project).setSelectedConfiguration(settings);
Assert.assertSame(settings, RunManagerEx.getInstanceEx(project).getSelectedConfiguration());
}
}.execute();
runConfiguration(settings, config);
}
/**
* Run configuration.
*
* @param settings settings (if have any, null otherwise)
* @param config configuration to run
* @throws Exception
*/
protected void runConfiguration(@Nullable final RunnerAndConfigurationSettings settings,
@NotNull final RunConfiguration config) throws Exception {
final ExecutionEnvironment environment;
if (settings == null) {
environment = ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), config).build();
}
else {
environment = ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), settings).build();
}
//noinspection ConstantConditions
Assert.assertTrue(environment.getRunner().canRun(DefaultRunExecutor.EXECUTOR_ID, config));
before();
final com.intellij.util.concurrency.Semaphore s = new com.intellij.util.concurrency.Semaphore();
s.down();
myOutput = new StringBuilder();
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
try {
environment.getRunner().execute(environment, new ProgramRunner.Callback() {
@Override
public void processStarted(RunContentDescriptor descriptor) {
myDescriptor = descriptor;
myProcessHandler = myDescriptor.getProcessHandler();
myProcessHandler.addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
myOutput.append(event.getText());
}
});
myConsoleView = (SMTRunnerConsoleView)descriptor.getExecutionConsole();
myTestProxy = myConsoleView.getResultsViewer().getTestsRootNode();
myConsoleView.getResultsViewer().addEventsListener(new TestResultsViewer.SMEventsAdapter() {
@Override
public void onTestingFinished(TestResultsViewer sender) {
s.up();
}
});
}
});
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
});
Assert.assertTrue(s.waitFor(getTestTimeout()));
XDebuggerTestUtil.waitForSwing();
assertFinished();
Assert.assertTrue(output(), allTestsCount() > 0);
after();
disposeProcess(myProcessHandler);
}
protected int getTestTimeout() {
return 60000;
}
protected void configure(AbstractPythonTestRunConfiguration config) {
}
public void allTestsPassed() {
Assert.assertEquals(output(), 0, myTestProxy.getChildren(Filter.NOT_PASSED).size());
Assert.assertEquals(output(), 0, failedTestsCount());
}
public int failedTestsCount() {
return myTestProxy.collectChildren(NOT_SUIT.and(Filter.FAILED_OR_INTERRUPTED)).size();
}
public int passedTestsCount() {
return myTestProxy.collectChildren(NOT_SUIT.and(Filter.PASSED)).size();
}
public void assertFinished() {
Assert.assertTrue("State is " + myTestProxy.getMagnitudeInfo().getTitle() + "\n" + output(),
myTestProxy.wasLaunched() && !myTestProxy.wasTerminated());
}
public int allTestsCount() {
return myTestProxy.collectChildren(NOT_SUIT).size();
}
public static final Filter<SMTestProxy> NOT_SUIT = new Filter<SMTestProxy>() {
@Override
public boolean shouldAccept(SMTestProxy test) {
return !test.isSuite();
}
};
}