From 5cdf67d588d87322f2d1d471fd52eb614f59bc89 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 16 Jul 2015 10:18:56 +0300 Subject: [PATCH] test discovery for testng tests --- ...sk.java => TestDiscoverySearchHelper.java} | 42 +++------ .../JUnitTestDiscoveryConfiguration.java | 11 ++- plugins/testng/src/META-INF/plugin.xml | 6 ++ .../configuration/TestNGRunnableState.java | 5 +- .../TestNGTestDiscoveryConfiguration.java | 89 +++++++++++++++++++ ...tNGTestDiscoveryConfigurationProducer.java | 25 ++++++ .../TestNGTestDiscoveryConfigurationType.java | 71 +++++++++++++++ .../testng/model/TestNGTestPattern.java | 33 ++++--- .../testng/TestNGTestDiscoveryListener.java | 48 ++++++++++ 9 files changed, 280 insertions(+), 50 deletions(-) rename java/execution/impl/src/com/intellij/execution/testDiscovery/{TestDiscoverySearchTask.java => TestDiscoverySearchHelper.java} (80%) create mode 100644 plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java create mode 100644 plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationProducer.java create mode 100644 plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationType.java create mode 100644 plugins/testng_rt/src/org/testng/TestNGTestDiscoveryListener.java diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchTask.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java similarity index 80% rename from java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchTask.java rename to java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java index fc6a1035b6ec..d852e5b20d57 100644 --- a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchTask.java +++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java @@ -16,8 +16,6 @@ package com.intellij.execution.testDiscovery; import com.intellij.codeInsight.actions.FormatChangedTextUtil; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.testframework.SearchForTestsTask; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; @@ -34,29 +32,15 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.net.ServerSocket; import java.util.*; -public abstract class TestDiscoverySearchTask extends SearchForTestsTask { - private final Pair myPosition; - private final String myChangeList; - - public TestDiscoverySearchTask(Project project, ServerSocket socket, Pair position, String changeList) { - super(project, socket); - myPosition = position; - myChangeList = changeList; - } - - protected abstract void writeFoundPatterns(Set patterns) throws ExecutionException; - - @Override - protected void search() throws ExecutionException { - final Project project = getProject(); +public class TestDiscoverySearchHelper { + public static Set search(final Project project, final Pair position, final String changeList) { final Set patterns = new LinkedHashSet(); - if (myPosition != null) { + if (position != null) { try { final Collection testsByMethodName = TestDiscoveryIndex - .getInstance(project).getTestsByMethodName(myPosition.first, myPosition.second); + .getInstance(project).getTestsByMethodName(position.first, position.second); if (testsByMethodName != null) { for (String pattern : testsByMethodName) { patterns.add(pattern.replace('-', ',')); @@ -67,7 +51,7 @@ public abstract class TestDiscoverySearchTask extends SearchForTestsTask { } } else { - final List files = getAffectedFiles(); + final List files = getAffectedFiles(changeList, project); final PsiManager psiManager = PsiManager.getInstance(project); for (final VirtualFile file : files) { @@ -103,16 +87,16 @@ public abstract class TestDiscoverySearchTask extends SearchForTestsTask { }); } } - writeFoundPatterns(patterns); + return patterns; } @NotNull - private List getAffectedFiles() { - final ChangeListManager changeListManager = ChangeListManager.getInstance(getProject()); - if (myChangeList == null) { + private static List getAffectedFiles(String changeListName, Project project) { + final ChangeListManager changeListManager = ChangeListManager.getInstance(project); + if (changeListName == null) { return changeListManager.getAffectedFiles(); } - final LocalChangeList changeList = changeListManager.findChangeList(myChangeList); + final LocalChangeList changeList = changeListManager.findChangeList(changeListName); if (changeList != null) { List files = new ArrayList(); for (Change change : changeList.getChanges()) { @@ -130,12 +114,8 @@ public abstract class TestDiscoverySearchTask extends SearchForTestsTask { return Collections.emptyList(); } - @Override - protected void onFound() { - } - @Nullable - protected static LinkedHashSet collectPatterns(PsiMethod psiMethod) { + private static LinkedHashSet collectPatterns(PsiMethod psiMethod) { LinkedHashSet patterns = new LinkedHashSet(); final PsiClass containingClass = psiMethod.getContainingClass(); if (containingClass != null) { diff --git a/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfiguration.java index 25d1c237cbd6..5d4fbdc3993a 100644 --- a/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfiguration.java +++ b/plugins/junit/src/com/intellij/execution/junit/testDiscovery/JUnitTestDiscoveryConfiguration.java @@ -23,9 +23,8 @@ import com.intellij.execution.junit.JUnitConfigurationType; import com.intellij.execution.junit.TestObject; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.testDiscovery.TestDiscoveryConfiguration; -import com.intellij.execution.testDiscovery.TestDiscoverySearchTask; +import com.intellij.execution.testDiscovery.TestDiscoverySearchHelper; import com.intellij.execution.testframework.SearchForTestsTask; -import com.intellij.execution.testframework.TestSearchScope; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.refactoring.listeners.RefactoringElementListener; @@ -69,11 +68,15 @@ public class JUnitTestDiscoveryConfiguration extends TestDiscoveryConfiguration @Override public SearchForTestsTask createSearchingForTestsTask() { - return new TestDiscoverySearchTask(getProject(), myServerSocket, getPosition(), getChangeList()) { + return new SearchForTestsTask(getProject(), myServerSocket) { @Override - protected void writeFoundPatterns(Set patterns) throws ExecutionException { + protected void search() throws ExecutionException { + final Set patterns = TestDiscoverySearchHelper.search(getProject(), getPosition(), getChangeList()); addClassesListToJavaParameters(patterns, FunctionUtil.id(), "", false, getJavaParameters()); } + + @Override + protected void onFound() {} }; } diff --git a/plugins/testng/src/META-INF/plugin.xml b/plugins/testng/src/META-INF/plugin.xml index 87693d48e73e..10adc1cb4357 100644 --- a/plugins/testng/src/META-INF/plugin.xml +++ b/plugins/testng/src/META-INF/plugin.xml @@ -74,7 +74,13 @@ implementationClass="com.theoryinpractice.testng.inspection.TestNGDataProviderInspection" displayName="Data provider problems" groupName="TestNG" enabledByDefault="true" level="WARNING"/> + + + + + diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 790271264e94..409084ce294c 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -23,10 +23,7 @@ import com.intellij.execution.configurations.ParametersList; import com.intellij.execution.process.*; import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.runners.ProgramRunner; -import com.intellij.execution.testframework.Printable; -import com.intellij.execution.testframework.Printer; -import com.intellij.execution.testframework.TestFrameworkRunningModel; -import com.intellij.execution.testframework.TestSearchScope; +import com.intellij.execution.testframework.*; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java new file mode 100644 index 000000000000..d6234376b4df --- /dev/null +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfiguration.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.theoryinpractice.testng.configuration.testDiscovery; + +import com.intellij.execution.CantRunException; +import com.intellij.execution.ExecutionException; +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.*; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.execution.testDiscovery.TestDiscoveryConfiguration; +import com.intellij.execution.testDiscovery.TestDiscoverySearchHelper; +import com.intellij.execution.testframework.TestSearchScope; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.refactoring.listeners.RefactoringElementListener; +import com.theoryinpractice.testng.configuration.SearchingForTestsTask; +import com.theoryinpractice.testng.configuration.TestNGConfiguration; +import com.theoryinpractice.testng.configuration.TestNGConfigurationType; +import com.theoryinpractice.testng.configuration.TestNGRunnableState; +import com.theoryinpractice.testng.model.TestNGTestPattern; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +public class TestNGTestDiscoveryConfiguration extends TestDiscoveryConfiguration { + + public TestNGTestDiscoveryConfiguration(String name, Project project, ConfigurationFactory factory) { + super(name, new JavaRunConfigurationModule(project, false), factory, + new TestNGConfiguration("", project, TestNGConfigurationType.getInstance().getConfigurationFactories()[0])); + } + + @Override + protected ModuleBasedConfiguration createInstance() { + final TestNGTestDiscoveryConfigurationType configurationType = + ConfigurationTypeUtil.findConfigurationType(TestNGTestDiscoveryConfigurationType.class); + final ConfigurationFactory[] factories = configurationType.getConfigurationFactories(); + return new TestNGTestDiscoveryConfiguration(getName(), getProject(), factories[0]); + } + + @Nullable + @Override + public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException { + return new TestNGTestDiscoveryRunnableState(environment); + } + + @Nullable + @Override + public RefactoringElementListener getRefactoringElementListener(PsiElement element) { + return null; + } + + private class TestNGTestDiscoveryRunnableState extends TestNGRunnableState { + public TestNGTestDiscoveryRunnableState(ExecutionEnvironment environment) { + super(environment, ((TestNGConfiguration)myDelegate)); + } + + @Override + public SearchingForTestsTask createSearchingForTestsTask() { + return new SearchingForTestsTask(myServerSocket, getConfiguration(), myTempFile, client) { + @Override + protected void search() throws CantRunException { + myClasses.clear(); + final Set patterns = TestDiscoverySearchHelper.search(getProject(), getPosition(), getChangeList()); + final Module module = getConfigurationModule().getModule(); + final GlobalSearchScope searchScope = + module != null ? GlobalSearchScope.moduleWithDependenciesScope(module) : GlobalSearchScope.projectScope(getProject()); + TestNGTestPattern.fillTestObjects(myClasses, patterns, TestSearchScope.MODULE_WITH_DEPENDENCIES, + TestNGTestDiscoveryConfiguration.this, searchScope); + } + }; + } + } +} diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationProducer.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationProducer.java new file mode 100644 index 000000000000..8d1e95bf00d6 --- /dev/null +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationProducer.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.theoryinpractice.testng.configuration.testDiscovery; + +import com.intellij.execution.configurations.ConfigurationTypeUtil; +import com.intellij.execution.testDiscovery.TestDiscoveryConfigurationProducer; + +public class TestNGTestDiscoveryConfigurationProducer extends TestDiscoveryConfigurationProducer { + protected TestNGTestDiscoveryConfigurationProducer() { + super(ConfigurationTypeUtil.findConfigurationType(TestNGTestDiscoveryConfigurationType.class)); + } +} diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationType.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationType.java new file mode 100644 index 000000000000..1a80550ec633 --- /dev/null +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/testDiscovery/TestNGTestDiscoveryConfigurationType.java @@ -0,0 +1,71 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.theoryinpractice.testng.configuration.testDiscovery; + +import com.intellij.execution.configuration.ConfigurationFactoryEx; +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.ModuleBasedConfiguration; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.project.Project; +import icons.TestngIcons; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class TestNGTestDiscoveryConfigurationType implements ConfigurationType { + private final ConfigurationFactory myFactory; + + public TestNGTestDiscoveryConfigurationType() { + myFactory = new ConfigurationFactoryEx(this) { + public RunConfiguration createTemplateConfiguration(Project project) { + return new TestNGTestDiscoveryConfiguration("", project, this); + } + + @Override + public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) { + ((ModuleBasedConfiguration)configuration).onNewConfigurationCreated(); + } + }; + } + + @Override + public String getDisplayName() { + return "TestNG Test Discovery"; + } + + @Override + public String getConfigurationTypeDescription() { + return "Runs TestNG tests which passed changed code"; + } + + @Override + public Icon getIcon() { + return TestngIcons.TestNG; + } + + @NotNull + @Override + public String getId() { + return "TestNGTestDiscovery"; + } + + @Override + public ConfigurationFactory[] getConfigurationFactories() { + return new ConfigurationFactory[] {myFactory}; + } +} diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGTestPattern.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGTestPattern.java index d691d8085580..9c12ea076883 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/model/TestNGTestPattern.java +++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestNGTestPattern.java @@ -16,6 +16,7 @@ package com.theoryinpractice.testng.model; import com.intellij.execution.CantRunException; +import com.intellij.execution.configurations.ModuleBasedConfiguration; import com.intellij.execution.configurations.RuntimeConfigurationException; import com.intellij.execution.configurations.RuntimeConfigurationWarning; import com.intellij.execution.testframework.SourceScope; @@ -51,7 +52,16 @@ public class TestNGTestPattern extends TestNGTestObject { public void fillTestObjects(Map>> classes) throws CantRunException { final TestData data = myConfig.getPersistantData(); - for (final String pattern : data.getPatterns()) { + final Set patterns = data.getPatterns(); + fillTestObjects(classes, patterns, myConfig.getPersistantData().getScope(), myConfig, getSearchScope()); + } + + public static void fillTestObjects(final Map>> classes, + final Set patterns, + final TestSearchScope testSearchScope, + final ModuleBasedConfiguration config, + final GlobalSearchScope searchScope) throws CantRunException { + for (final String pattern : patterns) { final String className; final String methodName; if (pattern.contains(",")) { @@ -66,7 +76,8 @@ public class TestNGTestPattern extends TestNGTestObject { @Nullable @Override public PsiClass compute() { - return ClassUtil.findPsiClass(PsiManager.getInstance(myConfig.getProject()), className.replace('/', '.'), null, true, getSearchScope()); + return ClassUtil + .findPsiClass(PsiManager.getInstance(config.getProject()), className.replace('/', '.'), null, true, searchScope); } }); if (psiClass != null) { @@ -78,20 +89,19 @@ public class TestNGTestPattern extends TestNGTestObject { }); if (hasTest) { if (StringUtil.isEmpty(methodName)) { - calculateDependencies(null, classes, getSearchScope(), psiClass); + calculateDependencies(null, classes, searchScope, psiClass); } else { - collectTestMethods(classes, psiClass, methodName, getSearchScope()); + collectTestMethods(classes, psiClass, methodName, searchScope); } } else { throw new CantRunException("No tests found in class " + className); } } } - if (classes.size() != data.getPatterns().size()) { - TestSearchScope scope = myConfig.getPersistantData().getScope(); + if (classes.size() != patterns.size()) { final List compilePatterns = new ArrayList(); - for (String p : data.getPatterns()) { + for (String p : patterns) { final Pattern compilePattern; try { compilePattern = Pattern.compile(p); @@ -101,9 +111,10 @@ public class TestNGTestPattern extends TestNGTestObject { } compilePatterns.add(compilePattern); } - final SourceScope sourceScope = scope.getSourceScope(myConfig); + final SourceScope sourceScope = testSearchScope.getSourceScope(config); TestClassFilter projectFilter = - new TestClassFilter(sourceScope != null ? sourceScope.getGlobalSearchScope() : GlobalSearchScope.allScope(myConfig.getProject()), myConfig.getProject(), true, true){ + new TestClassFilter(sourceScope != null ? sourceScope.getGlobalSearchScope() : GlobalSearchScope.allScope(config.getProject()), + config.getProject(), true, true){ @Override public boolean isAccepted(PsiClass psiClass) { if (super.isAccepted(psiClass)) { @@ -116,9 +127,9 @@ public class TestNGTestPattern extends TestNGTestObject { return false; } }; - calculateDependencies(null, classes, getSearchScope(), TestNGUtil.getAllTestClasses(projectFilter, false)); + calculateDependencies(null, classes, searchScope, TestNGUtil.getAllTestClasses(projectFilter, false)); if (classes.size() == 0) { - throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(data.getPatterns(), " || ") + '\"'); + throw new CantRunException("No tests found in for patterns \"" + StringUtil.join(patterns, " || ") + '\"'); } } } diff --git a/plugins/testng_rt/src/org/testng/TestNGTestDiscoveryListener.java b/plugins/testng_rt/src/org/testng/TestNGTestDiscoveryListener.java new file mode 100644 index 000000000000..6e2b2ff5469b --- /dev/null +++ b/plugins/testng_rt/src/org/testng/TestNGTestDiscoveryListener.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.testng; + +import com.intellij.execution.TestDiscoveryListener; + +public class TestNGTestDiscoveryListener extends TestDiscoveryListener implements IDEATestNGListener { + public void onTestStart(ITestResult result) { + testStarted(result.getTestClass().getName(), result.getTestName()); + } + + public void onTestSuccess(ITestResult result) { + onTestEnded(result); + } + + public void onTestFailure(ITestResult result) { + onTestEnded(result); + } + + public void onTestSkipped(ITestResult result) { + onTestEnded(result); + } + + public void onTestFailedButWithinSuccessPercentage(ITestResult result) { + onTestEnded(result); + } + + public void onStart(ITestContext context) {} + + public void onFinish(ITestContext context) {} + + private void onTestEnded(ITestResult result) { + testFinished(result.getTestClass().getName(), result.getName()); + } +}