mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-17378: Rerun fix for PyTests:
* Full path is calculated on helper side * Calculating test path for subtests (yielding) on java side
This commit is contained in:
@@ -9,6 +9,11 @@ from pycharm_run_utils import adjust_sys_path
|
||||
|
||||
adjust_sys_path(False)
|
||||
|
||||
# Directory where test script exist
|
||||
CURRENT_DIR_NAME = ""
|
||||
if sys.argv:
|
||||
CURRENT_DIR_NAME = os.path.dirname(sys.argv[-1])
|
||||
|
||||
messages = TeamcityServiceMessages(prepend_linebreak=True)
|
||||
messages.testMatrixEntered()
|
||||
try:
|
||||
@@ -31,7 +36,7 @@ if PYVERSION > [1, 4, 0]:
|
||||
current_file_suite = None
|
||||
|
||||
def pytest_runtest_logstart(nodeid, location):
|
||||
path = "file://" + os.path.realpath(location[0])
|
||||
path = "file://" + os.path.realpath(os.path.join(CURRENT_DIR_NAME, location[0]))
|
||||
if location[1]:
|
||||
path += ":" +str(location[1] + 1)
|
||||
global current_suite, current_file, current_file_suite
|
||||
@@ -45,7 +50,7 @@ if PYVERSION > [1, 4, 0]:
|
||||
messages.testSuiteFinished(current_file_suite)
|
||||
current_file_suite = file_suite
|
||||
if current_file_suite:
|
||||
messages.testSuiteStarted(current_file_suite, location="file://" + os.path.realpath(location[0]))
|
||||
messages.testSuiteStarted(current_file_suite, location=path)
|
||||
|
||||
if location[2].find(".") != -1:
|
||||
suite = location[2].split(".")[0]
|
||||
@@ -69,7 +74,7 @@ if PYVERSION > [1, 4, 0]:
|
||||
messages.testSuiteFinished(current_suite)
|
||||
current_suite = suite
|
||||
if current_suite:
|
||||
messages.testSuiteStarted(current_suite, location="file://" + os.path.realpath(location[0]))
|
||||
messages.testSuiteStarted(current_suite, location=path)
|
||||
messages.testStarted(name, location=path)
|
||||
items[nodeid] = name
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.execution.Location;
|
||||
import com.intellij.execution.configuration.AbstractRunConfiguration;
|
||||
import com.intellij.execution.configuration.EnvironmentVariablesComponent;
|
||||
import com.intellij.execution.configurations.*;
|
||||
import com.intellij.execution.testframework.AbstractTestProxy;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.module.ModuleType;
|
||||
@@ -59,6 +60,11 @@ import java.util.Map;
|
||||
*/
|
||||
public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfiguration> extends AbstractRunConfiguration
|
||||
implements LocatableConfiguration, AbstractPythonRunConfigurationParams, CommandLinePatcher {
|
||||
/**
|
||||
* When passing path to test to runners, you should join parts with this char.
|
||||
* I.e.: file.py::PyClassTest::test_method
|
||||
*/
|
||||
public static final String TEST_NAME_PARTS_SPLITTER = "::";
|
||||
private String myInterpreterOptions = "";
|
||||
private String myWorkingDirectory = "";
|
||||
private String mySdkHome = "";
|
||||
@@ -406,7 +412,14 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getTestSpec(Location location) {
|
||||
/**
|
||||
* Create test spec (string to be passed to runner, probably glued with {@link #TEST_NAME_PARTS_SPLITTER})
|
||||
* @param location test location as reported by runner
|
||||
* @param failedTest failed test
|
||||
* @return string spec or null if spec calculation is impossible
|
||||
*/
|
||||
@Nullable
|
||||
public String getTestSpec(@NotNull final Location<?> location, @NotNull final AbstractTestProxy failedTest) {
|
||||
PsiElement element = location.getPsiElement();
|
||||
PyClass pyClass = PsiTreeUtil.getParentOfType(element, PyClass.class, false);
|
||||
PyFunction pyFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class, false);
|
||||
@@ -414,10 +427,10 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
|
||||
if (virtualFile != null) {
|
||||
String path = virtualFile.getCanonicalPath();
|
||||
if (pyClass != null) {
|
||||
path += "::" + pyClass.getName();
|
||||
path += TEST_NAME_PARTS_SPLITTER + pyClass.getName();
|
||||
}
|
||||
if (pyFunction != null) {
|
||||
path += "::" + pyFunction.getName();
|
||||
path += TEST_NAME_PARTS_SPLITTER + pyFunction.getName();
|
||||
}
|
||||
return path;
|
||||
}
|
||||
@@ -440,7 +453,7 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
Module module = getModule();
|
||||
return module != null? module.getName() : null;
|
||||
return module != null ? module.getName() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -110,9 +110,9 @@ public class PyRerunFailedTestsAction extends AbstractRerunFailedTestsAction {
|
||||
List<AbstractTestProxy> failedTests = getFailedTests(myProject);
|
||||
for (AbstractTestProxy failedTest : failedTests) {
|
||||
if (failedTest.isLeaf()) {
|
||||
final Location location = failedTest.getLocation(myProject, myConsoleProperties.getScope());
|
||||
final Location<?> location = failedTest.getLocation(myProject, myConsoleProperties.getScope());
|
||||
if (location != null) {
|
||||
String spec = getConfiguration().getTestSpec(location);
|
||||
final String spec = getConfiguration().getTestSpec(location, failedTest);
|
||||
if (spec != null && !specs.contains(spec)) {
|
||||
specs.add(spec);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ import java.util.Map;
|
||||
public abstract class PythonTestCommandLineStateBase extends PythonCommandLineState {
|
||||
protected final AbstractPythonRunConfiguration myConfiguration;
|
||||
|
||||
public AbstractPythonRunConfiguration getConfiguration() {
|
||||
public AbstractPythonRunConfiguration<?> getConfiguration() {
|
||||
return myConfiguration;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package com.jetbrains.python.testing.pytest;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.Location;
|
||||
import com.intellij.execution.configurations.*;
|
||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||
import com.intellij.execution.testframework.AbstractTestProxy;
|
||||
import com.intellij.openapi.components.PathMacroManager;
|
||||
import com.intellij.openapi.options.SettingsEditor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -27,12 +30,17 @@ import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMExternalizerUtil;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.sdk.PythonSdkType;
|
||||
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
|
||||
import com.jetbrains.python.testing.VFSTestFrameworkListener;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -73,8 +81,9 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i
|
||||
}
|
||||
|
||||
public String getKeywords() {
|
||||
if (useKeyword)
|
||||
if (useKeyword) {
|
||||
return myKeywords;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -87,8 +96,9 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i
|
||||
}
|
||||
|
||||
public String getParams() {
|
||||
if (useParam)
|
||||
if (useParam) {
|
||||
return myParams;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -136,8 +146,9 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i
|
||||
throw new RuntimeConfigurationError("Please specify target folder or script");
|
||||
}
|
||||
Sdk sdkPath = PythonSdkType.findSdkByPath(getInterpreterPath());
|
||||
if (sdkPath != null && !VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdkPath))
|
||||
if (sdkPath != null && !VFSTestFrameworkListener.getInstance().isPyTestInstalled(sdkPath)) {
|
||||
throw new RuntimeConfigurationWarning(PyBundle.message("runcfg.testing.no.test.framework", "py.test"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,4 +165,31 @@ public class PyTestRunConfiguration extends AbstractPythonTestRunConfiguration i
|
||||
protected String getPluralTitle() {
|
||||
return myPluralTitle;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public final String getTestSpec(@NotNull final Location location, @NotNull final AbstractTestProxy failedTest) {
|
||||
/**
|
||||
* PyTest supports subtests (with yielding). Such tests are reported as _test_name[index] and location does not point to actual test.
|
||||
* We need to get rid of braces and calculate name manually, since location is incorrect.
|
||||
* Test path starts from file.
|
||||
*/
|
||||
final int indexOfBrace = failedTest.getName().indexOf('[');
|
||||
if (indexOfBrace == -1) {
|
||||
return super.getTestSpec(location, failedTest);
|
||||
}
|
||||
final List<String> testNameParts = new ArrayList<String>();
|
||||
final VirtualFile file = location.getVirtualFile();
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
final String fileName = file.getName();
|
||||
|
||||
testNameParts.add(failedTest.getName().substring(0, indexOfBrace));
|
||||
for (AbstractTestProxy test = failedTest.getParent(); test != null && !test.getName().equals(fileName); test = test.getParent()) {
|
||||
testNameParts.add(test.getName());
|
||||
}
|
||||
testNameParts.add(file.getCanonicalPath());
|
||||
return StringUtil.join(Lists.reverse(testNameParts), TEST_NAME_PARTS_SPLITTER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class PythonPyTestingTest extends PyEnvTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected PyTestTestProcessRunner createProcessRunner() throws Exception {
|
||||
return new PyTestTestProcessRunner(getTestDataPath() + "/testRunner/env/pytest", "test2.py", 0);
|
||||
return new PyTestTestProcessRunner(getTestDataPath() + "/testRunner/env/pytest", "test2.py", 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,6 +57,15 @@ public class PythonPyTestingTest extends PyEnvTestCase {
|
||||
@NotNull final String stdout,
|
||||
@NotNull final String stderr,
|
||||
@NotNull final String all) {
|
||||
if (runner.getCurrentRerunStep() > 0) {
|
||||
/**
|
||||
* We can't rerun one subtest (yield), so we rerun whole "test_even"
|
||||
*/
|
||||
assertEquals(7, runner.getAllTestsCount());
|
||||
assertEquals(3, runner.getPassedTestsCount());
|
||||
assertEquals(4, runner.getFailedTestsCount());
|
||||
return;
|
||||
}
|
||||
assertEquals(9, runner.getAllTestsCount());
|
||||
assertEquals(5, runner.getPassedTestsCount());
|
||||
assertEquals(4, runner.getFailedTestsCount());
|
||||
|
||||
Reference in New Issue
Block a user