PY-19738: test added

Run tests, then delete files, and try to rerun it. Message and exc. should be displayed
This commit is contained in:
Ilya.Kazakevich
2016-06-22 22:08:59 +03:00
parent 7392dfe9b7
commit 80ee4d0b71
5 changed files with 193 additions and 11 deletions
+14
View File
@@ -0,0 +1,14 @@
__author__ = 'Ilya.Kazakevich'
import unittest
import time
class TestMe2(unittest.TestCase):
def test_pass(self):
time.sleep(1)
def test_raise(self):
raise ValueError
class TestMe(unittest.TestCase):
def test_pass2(self):
pass
@@ -52,7 +52,7 @@ import java.util.List;
* you need to implement {@link #getEnvironmentToRerun(RunContentDescriptor)}, accept last run descriptor and return
* {@link ExecutionEnvironment} to rerun (probably obtained from descriptor).
* <p/>
* It also has {@link #getAvailableRunnersForLastRun()} with list of strings that represents runner ids available for last run.
* It also has {@link #getAvailableRunnersForLastRun()} with list of runners that represents runner ids available for last run.
*
* @param <CONF_T> configuration class this runner supports
* @author Ilya.Kazakevich
@@ -65,7 +65,7 @@ public abstract class ConfigurationBasedProcessRunner<CONF_T extends AbstractPyt
private final Class<CONF_T> myExpectedConfigurationType;
@NotNull
private final List<String> myAvailableRunnersForLastRun = new ArrayList<String>();
private final List<ProgramRunner<?>> myAvailableRunnersForLastRun = new ArrayList<>();
/**
* Environment to be used to run instead of factory. Used to rerun
@@ -75,7 +75,7 @@ public abstract class ConfigurationBasedProcessRunner<CONF_T extends AbstractPyt
/**
* Process descriptor of last run
*/
private RunContentDescriptor myLastProcessDescriptor;
protected RunContentDescriptor myLastProcessDescriptor;
/**
* @param configurationFactory factory tp create configurations
@@ -114,7 +114,7 @@ public abstract class ConfigurationBasedProcessRunner<CONF_T extends AbstractPyt
for (final ProgramRunner<?> runner : ProgramRunner.PROGRAM_RUNNER_EP.getExtensions()) {
for (final Executor executor : Executor.EXECUTOR_EXTENSION_NAME.getExtensions()) {
if (runner.canRun(executor.getId(), executionEnvironment.getRunProfile())) {
myAvailableRunnersForLastRun.add(runner.getRunnerId());
myAvailableRunnersForLastRun.add(runner);
}
}
}
@@ -222,7 +222,7 @@ public abstract class ConfigurationBasedProcessRunner<CONF_T extends AbstractPyt
* Use it to check if desired runner (like debugger) exists
*/
@NotNull
public final List<String> getAvailableRunnersForLastRun() {
public final List<ProgramRunner<?>> getAvailableRunnersForLastRun() {
return Collections.unmodifiableList(myAvailableRunnersForLastRun);
}
}
@@ -1,8 +1,11 @@
package com.jetbrains.env;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.ConfigurationFactory;
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.execution.testframework.Filter;
import com.intellij.execution.testframework.actions.RerunFailedActionsTestTools;
@@ -12,12 +15,14 @@ import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Ref;
import com.jetbrains.python.run.AbstractPythonRunConfigurationParams;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
import javax.swing.*;
import java.util.List;
/**
* Runner for tests. Provides access to test console and test results.
@@ -170,4 +175,32 @@ public class PyAbstractTestProcessRunner<CONF_T extends AbstractPythonRunConfigu
public int getCurrentRerunStep() {
return myCurrentRerunStep;
}
/**
* Rerun current tests. Make sure there is at least one failed test.
* <strong>Run in AWT thread only!</strong>
*/
public void rerunFailedTests() {
assert getFailedTestsCount() > 0 : "No failed tests. What you want to rerun?";
assert myLastProcessDescriptor != null : "No last run descriptor. First run tests at least one time";
final List<ProgramRunner<?>> run = getAvailableRunnersForLastRun();
Assert.assertFalse("No runners to rerun", run.isEmpty());
final ProgramRunner<?> runner = run.get(0);
final ExecutionEnvironment restartAction = RerunFailedActionsTestTools.findRestartAction(myLastProcessDescriptor);
Assert.assertNotNull("No restart action", restartAction);
final Ref<ProcessHandler> handlerRef = new Ref<>();
try {
runner.execute(restartAction, descriptor -> handlerRef.set(descriptor.getProcessHandler()));
}
catch (final ExecutionException e) {
throw new AssertionError("ExecutionException can't be thrown in tests. Probably, API changed. Got: " + e);
}
final ProcessHandler handler = handlerRef.get();
if (handler == null) {
return;
}
handler.waitFor();
}
}
+77 -5
View File
@@ -5,9 +5,13 @@ import com.intellij.execution.ExecutionException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TestDialog;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.testFramework.LoggedErrorProcessor;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SystemProperties;
@@ -25,9 +29,7 @@ import org.junit.runner.Description;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.*;
/**
* @author traff
@@ -48,6 +50,12 @@ public abstract class PyEnvTestCase {
private static final boolean STAGING_ENV = SystemProperties.getBooleanProperty("pycharm.staging_env", false);
/**
* Logger to be used with {@link #startMessagesCapture()}
*/
private PyTestMessagesLogger myLogger;
/**
* Tags that should exist between all tags, available on all interpreters for test to run.
* See {@link #PyEnvTestCase(String...)}
@@ -150,8 +158,6 @@ public abstract class PyEnvTestCase {
}
protected boolean runInDispatchThread() {
return false;
}
@@ -285,5 +291,71 @@ public abstract class PyEnvTestCase {
public static String joinStrings(Collection<String> roots, String rootsName) {
return roots.size() > 0 ? rootsName + StringUtil.join(roots, ", ") + "\n" : "";
}
/**
* Capture all messages and error logs and store them to be obtained with {@link #getCapturesMessages()}
* and stopped with {@link #stopMessageCapture()}
*/
protected final void startMessagesCapture() {
myLogger = new PyTestMessagesLogger();
LoggedErrorProcessor.setNewInstance(myLogger);
Messages.setTestDialog(myLogger);
}
/**
* @return captures messages (first start with {@link #startMessagesCapture()}).
* Logged exceptions -- list of messages to be displayed (never null)
*/
@NotNull
protected final Pair<List<Throwable>, List<String>> getCapturesMessages() {
assert myLogger != null : "Capturing not enabled";
return Pair.create(Collections.unmodifiableList(myLogger.myExceptions), Collections.unmodifiableList(myLogger.myMessages));
}
/**
* Stop message capturing started with {@link #startMessagesCapture()}
*/
protected final void stopMessageCapture() {
LoggedErrorProcessor.restoreDefaultProcessor();
Messages.setTestDialog(TestDialog.DEFAULT);
myLogger = null;
}
/**
* Always call parrent when overwrite
*/
@After
public void tearDown() throws Exception {
// We can stop message capturing even if it was not started as cleanup process.
stopMessageCapture();
}
/**
* Logger to be used with {@link #startMessagesCapture()}
*/
private static final class PyTestMessagesLogger extends LoggedErrorProcessor implements TestDialog {
private final List<String> myMessages = new ArrayList<>();
private final List<Throwable> myExceptions = new ArrayList<>();
@Override
public int show(final String message) {
myMessages.add(message);
return 0;
}
@Override
public void processWarn(final String message, final Throwable t, @NotNull final org.apache.log4j.Logger logger) {
myExceptions.add(t);
}
@Override
public void processError(final String message,
final Throwable t,
final String[] details,
@NotNull final org.apache.log4j.Logger logger) {
myExceptions.add(t);
}
}
}
@@ -1,9 +1,15 @@
package com.jetbrains.env.python.testing;
import com.intellij.execution.ExecutionException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.EdtTestUtil;
import com.intellij.testFramework.fixtures.CodeInsightTestFixture;
import com.jetbrains.env.PyEnvTestCase;
import com.jetbrains.env.Staging;
import com.jetbrains.env.ut.PyUnitTestProcessRunner;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.testing.PythonTestConfigurationsModel;
import com.jetbrains.python.testing.unittest.PythonUnitTestConfigurationProducer;
@@ -12,8 +18,10 @@ import org.jetbrains.annotations.NotNull;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
/**
@@ -67,6 +75,62 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
});
}
/**
* Run tests, delete file and click "rerun" should throw exception and display error since test ids do not point to correct PSI
* from that moment
*/
@Test
public void testCantRerun() throws Exception {
startMessagesCapture();
runPythonTest(new PyUnitTestProcessWithConsoleTestTask("/testRunner/env/unit", "test_with_skips_and_errors.py") {
@Override
protected void checkTestResults(@NotNull final PyUnitTestProcessRunner runner,
@NotNull final String stdout,
@NotNull final String stderr,
@NotNull final String all) {
assert runner.getFailedTestsCount() > 0 : "We need failed tests to test broken rerun";
startMessagesCapture();
EdtTestUtil.runInEdtAndWait((Runnable)() -> {
deleteAllTestFiles(myFixture);
runner.rerunFailedTests();
});
final List<Throwable> throwables = getCapturesMessages().first;
Assert.assertThat("Exception shall be thrown", throwables, not(emptyCollectionOf(Throwable.class)));
final Throwable exception = throwables.get(0);
Assert.assertThat("ExecutionException should be thrown", exception, instanceOf(ExecutionException.class));
Assert.assertThat("Wrong text", exception.getMessage(), equalTo(PyBundle.message("runcfg.tests.cant_rerun")));
Assert.assertThat("No messages displayed for exception", getCapturesMessages().second, not(emptyCollectionOf(String.class)));
stopMessageCapture();
}
});
}
/**
* Deletes all files in temp. folder
*/
private static void deleteAllTestFiles(@NotNull final CodeInsightTestFixture fixture) {
ApplicationManager.getApplication().runWriteAction(() -> {
final VirtualFile testRoot = fixture.getTempDirFixture().getFile(".");
assert testRoot != null : "No temp path?";
try {
for (final VirtualFile child : testRoot.getChildren()) {
child.delete(null);
}
}
catch (final IOException e) {
throw new AssertionError(String.format("Failed to delete files in %s : %s", testRoot, e));
}
});
}
/**
* Ensures that skipped and erroneous tests do not lead to suite ignorance
*/
@@ -227,5 +291,4 @@ public final class PythonUnitTestingTest extends PyEnvTestCase {
}
});
}
}