mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
introduce test discovery producer API
This commit is contained in:
+2
-117
@@ -1,10 +1,6 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.execution.testDiscovery;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.intellij.codeInsight.navigation.ListBackgroundUpdaterTask;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.actions.ConfigurationContext;
|
||||
@@ -20,14 +16,12 @@ import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ReadAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.popup.IconButton;
|
||||
import com.intellij.openapi.ui.popup.JBPopup;
|
||||
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -38,27 +32,15 @@ import com.intellij.ui.popup.AbstractPopup;
|
||||
import com.intellij.ui.popup.HintUpdateSupply;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.PsiNavigateUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.io.RequestBuilder;
|
||||
import com.intellij.util.ui.EdtInvocationManager;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.intellij.openapi.actionSystem.CommonDataKeys.EDITOR;
|
||||
import static com.intellij.openapi.actionSystem.CommonDataKeys.PSI_FILE;
|
||||
|
||||
public class FindTestsInTestDiscoveryServerAction extends AnAction {
|
||||
private static final Logger LOG = Logger.getInstance(FindTestsInTestDiscoveryServerAction.class);
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
Editor editor = e.getData(EDITOR);
|
||||
@@ -157,10 +139,9 @@ public class FindTestsInTestDiscoveryServerAction extends AnAction {
|
||||
loadTestsTask.init((AbstractPopup)popup, list, new Ref<>());
|
||||
|
||||
ApplicationManager.getApplication().executeOnPooledThread(() -> {
|
||||
Map<String, String> map = fetchDataFromDiscoveryServer(fqn, methodName);
|
||||
map.forEach((classFqn, testMethodName) -> {
|
||||
TestDiscoveryProducer.consumeTestClassesAndMethods(project, fqn, methodName, "j", (testClassFqn, testMethodName) -> {
|
||||
PsiMethod psiMethod = ReadAction.compute(() -> {
|
||||
PsiClass cc = classFqn == null ? null : javaFacade.findClass(classFqn, scope);
|
||||
PsiClass cc = testClassFqn == null ? null : javaFacade.findClass(testClassFqn, scope);
|
||||
return cc == null ? null : ArrayUtil.getFirstElement(cc.findMethodsByName(testMethodName, false));
|
||||
});
|
||||
if (psiMethod != null) {
|
||||
@@ -174,100 +155,4 @@ public class FindTestsInTestDiscoveryServerAction extends AnAction {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static final String INTELLIJ_TEST_DISCOVERY_HOST = "http://intellij-test-discovery";
|
||||
|
||||
private static Map<String, String> fetchDataFromDiscoveryServer(@NotNull String classFQName, @NotNull String methodName) {
|
||||
String methodFqn = classFQName + "." + methodName;
|
||||
RequestBuilder r = HttpRequests.request(INTELLIJ_TEST_DISCOVERY_HOST + "/search/tests/by-method/" + methodFqn);
|
||||
|
||||
try {
|
||||
return r.connect(request -> {
|
||||
Map<String, String> map = ContainerUtil.newLinkedHashMap();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
TestsSearchResult result = mapper.readValue(request.getInputStream(), TestsSearchResult.class);
|
||||
|
||||
result.getTests().forEach(s -> {
|
||||
|
||||
s = s.length() > 1 && s.charAt(0) == 'j' ? s.substring(1) : s;
|
||||
String classFqn = StringUtil.substringBefore(s, "-");
|
||||
String testMethodName = StringUtil.substringAfter(s, "-");
|
||||
|
||||
map.put(classFqn, testMethodName);
|
||||
});
|
||||
return map;
|
||||
});
|
||||
}
|
||||
catch (HttpRequests.HttpStatusException http) {
|
||||
LOG.debug("No tests found for " + methodFqn);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public static class TestsSearchResult {
|
||||
@Nullable
|
||||
private String method;
|
||||
|
||||
@SerializedName("class")
|
||||
@JsonProperty("class")
|
||||
@Nullable
|
||||
private String className;
|
||||
|
||||
private int found;
|
||||
|
||||
@NotNull
|
||||
private List<String> tests = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
private String message;
|
||||
|
||||
@Nullable
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public TestsSearchResult setMethod(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public TestsSearchResult setClassName(String name) {
|
||||
this.className = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFound() {
|
||||
return found;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getTests() {
|
||||
return tests;
|
||||
}
|
||||
|
||||
public TestsSearchResult setTests(List<String> tests) {
|
||||
this.tests = tests;
|
||||
this.found = tests.size();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public TestsSearchResult setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.execution.testDiscovery;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.HttpRequests;
|
||||
import com.intellij.util.io.RequestBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class IntellijTestDiscoveryProducer implements TestDiscoveryProducer {
|
||||
private static final String INTELLIJ_TEST_DISCOVERY_HOST = "http://intellij-test-discovery";
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<String, String> getTestClassesAndMethodNames(Project project, String classFQName, String methodName, String frameworkId) {
|
||||
String methodFqn = classFQName + "." + methodName;
|
||||
RequestBuilder r = HttpRequests.request(INTELLIJ_TEST_DISCOVERY_HOST + "/search/tests/by-method/" + methodFqn);
|
||||
|
||||
try {
|
||||
return r.connect(request -> {
|
||||
Map<String, String> map = ContainerUtil.newLinkedHashMap();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
TestsSearchResult result = mapper.readValue(request.getInputStream(), TestsSearchResult.class);
|
||||
|
||||
result.getTests().forEach(s -> {
|
||||
s = s.length() > 1 && s.charAt(0) == 'j' ? s.substring(1) : s;
|
||||
String classFqn = StringUtil.substringBefore(s, "-");
|
||||
String testMethodName = StringUtil.substringAfter(s, "-");
|
||||
map.put(classFqn, testMethodName);
|
||||
});
|
||||
return map;
|
||||
});
|
||||
}
|
||||
catch (HttpRequests.HttpStatusException http) {
|
||||
LOG.debug("No tests found for " + methodFqn);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public static class TestsSearchResult {
|
||||
@Nullable
|
||||
private String method;
|
||||
|
||||
@SerializedName("class")
|
||||
@JsonProperty("class")
|
||||
@Nullable
|
||||
private String className;
|
||||
|
||||
private int found;
|
||||
|
||||
@NotNull
|
||||
private List<String> tests = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
private String message;
|
||||
|
||||
@Nullable
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public TestsSearchResult setMethod(String method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
public TestsSearchResult setClassName(String name) {
|
||||
this.className = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFound() {
|
||||
return found;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getTests() {
|
||||
return tests;
|
||||
}
|
||||
|
||||
public TestsSearchResult setTests(List<String> tests) {
|
||||
this.tests = tests;
|
||||
this.found = tests.size();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public TestsSearchResult setMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.execution.testDiscovery;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class LocalTestDiscoveryProducer implements TestDiscoveryProducer {
|
||||
@Override
|
||||
@NotNull
|
||||
public Map<String, String> getTestClassesAndMethodNames(@NotNull Project project,
|
||||
@NotNull String classFQName,
|
||||
@NotNull String methodName,
|
||||
@NotNull String frameworkId) {
|
||||
try {
|
||||
Map<String, String> map = ContainerUtil.newLinkedHashMap();
|
||||
TestDiscoveryIndex discoveryIndex = TestDiscoveryIndex.getInstance(project);
|
||||
Collection<String> testsByMethodName = discoveryIndex.getTestsByMethodName(classFQName, methodName, frameworkId);
|
||||
if (testsByMethodName != null) {
|
||||
for (String pattern : testsByMethodName) { // todo[batkovich]: filter by framework id
|
||||
List<String> split = StringUtil.split(pattern, "-");
|
||||
if (split.size() == 2) {
|
||||
map.put(split.get(0), split.get(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
catch (IOException io) {
|
||||
TestDiscoveryProducer.LOG.warn(io);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.execution.testDiscovery;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@ApiStatus.Experimental
|
||||
public interface TestDiscoveryProducer {
|
||||
Logger LOG = Logger.getInstance(LocalTestDiscoveryProducer.class);
|
||||
|
||||
@NotNull
|
||||
Map<String, String> getTestClassesAndMethodNames(Project project,
|
||||
String classFQName,
|
||||
String methodName,
|
||||
String frameworkId);
|
||||
|
||||
ExtensionPointName<TestDiscoveryProducer> EP = ExtensionPointName.create("com.intellij.testDiscoveryProducer");
|
||||
|
||||
static void consumeTestClassesAndMethods(@NotNull Project project,
|
||||
@NotNull String classFQName,
|
||||
@NotNull String methodName,
|
||||
@NotNull String frameworkId,
|
||||
@NotNull BiConsumer<String, String> consumer) {
|
||||
for (TestDiscoveryProducer producer : EP.getExtensions()) {
|
||||
producer.getTestClassesAndMethodNames(project, classFQName, methodName, frameworkId).forEach(consumer);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-25
@@ -20,7 +20,6 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.diff.FilesTooBigForDiffException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
@@ -32,11 +31,7 @@ public class TestDiscoverySearchHelper {
|
||||
final String frameworkPrefix) {
|
||||
final Set<String> patterns = new LinkedHashSet<>();
|
||||
if (position != null) {
|
||||
try {
|
||||
collectPatterns(project, patterns, position.first, position.second, frameworkPrefix);
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
collectPatterns(project, patterns, position.first, position.second, frameworkPrefix);
|
||||
}
|
||||
final List<VirtualFile> files = getAffectedFiles(changeList, project);
|
||||
final PsiManager psiManager = PsiManager.getInstance(project);
|
||||
@@ -92,18 +87,12 @@ public class TestDiscoverySearchHelper {
|
||||
return new HashSet<>(ContainerUtil.filter(patterns, fqn -> ReadAction.compute(() -> psiFacade.findClass(StringUtil.getPackageName(fqn, ','), searchScope) != null)));
|
||||
}
|
||||
|
||||
private static void collectPatterns(final Project project,
|
||||
final Set<String> patterns,
|
||||
final String classFQName,
|
||||
final String methodName,
|
||||
final String frameworkId) throws IOException {
|
||||
final TestDiscoveryIndex discoveryIndex = TestDiscoveryIndex.getInstance(project);
|
||||
final Collection<String> testsByMethodName = discoveryIndex.getTestsByMethodName(classFQName, methodName, frameworkId);
|
||||
if (testsByMethodName != null) {
|
||||
for (String pattern : testsByMethodName) {
|
||||
patterns.add(pattern.replace('-', ','));
|
||||
}
|
||||
}
|
||||
private static void collectPatterns(@NotNull Project project,
|
||||
@NotNull Set<String> patterns,
|
||||
@NotNull String classFQName,
|
||||
@NotNull String methodName,
|
||||
@NotNull String frameworkId) {
|
||||
TestDiscoveryProducer.consumeTestClassesAndMethods(project, classFQName, methodName, frameworkId, (c, m) -> patterns.add(c + "," + m));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -130,19 +119,14 @@ public class TestDiscoverySearchHelper {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
private static LinkedHashSet<String> collectPatterns(PsiMethod psiMethod, String frameworkId) {
|
||||
LinkedHashSet<String> patterns = new LinkedHashSet<>();
|
||||
final PsiClass containingClass = psiMethod.getContainingClass();
|
||||
if (containingClass != null) {
|
||||
final String qualifiedName = containingClass.getQualifiedName();
|
||||
if (qualifiedName != null) {
|
||||
try {
|
||||
collectPatterns(psiMethod.getProject(), patterns, qualifiedName, psiMethod.getName(), frameworkId);
|
||||
}
|
||||
catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
collectPatterns(psiMethod.getProject(), patterns, qualifiedName, psiMethod.getName(), frameworkId);
|
||||
}
|
||||
}
|
||||
return patterns;
|
||||
|
||||
@@ -77,6 +77,8 @@
|
||||
<codeInsight.externalLibraryResolver implementation="com.intellij.execution.junit.codeInsight.JUnit5ExternalLibraryResolver"/>
|
||||
<junitListener implementation="com.intellij.junit4.JUnitTestDiscoveryListener"/>
|
||||
<runConfigurationProducer implementation="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer"/>
|
||||
<testDiscoveryProducer implementation="com.intellij.execution.testDiscovery.LocalTestDiscoveryProducer"/>
|
||||
<testDiscoveryProducer implementation="com.intellij.execution.testDiscovery.IntellijTestDiscoveryProducer"/>
|
||||
<implicitUsageProvider implementation="com.intellij.execution.junit2.inspection.JUnitImplicitUsageProvider"/>
|
||||
<predefinedMigrationMapProvider implementation="com.intellij.execution.junit2.refactoring.JUnit5Migration"/>
|
||||
<psi.referenceContributor implementation="com.intellij.execution.junit.codeInsight.references.JUnitReferenceContributor"/>
|
||||
@@ -95,6 +97,7 @@
|
||||
|
||||
<extensionPoints>
|
||||
<extensionPoint qualifiedName="com.intellij.junitListener" interface="com.intellij.rt.execution.junit.IDEAJUnitListener"/>
|
||||
<extensionPoint qualifiedName="com.intellij.testDiscoveryProducer" interface="com.intellij.execution.testDiscovery.TestDiscoveryProducer"/>
|
||||
</extensionPoints>
|
||||
|
||||
<actions>
|
||||
|
||||
Reference in New Issue
Block a user