diff --git a/.idea/libraries/Coverage.xml b/.idea/libraries/Coverage.xml
deleted file mode 100644
index 3585b430326d..000000000000
--- a/.idea/libraries/Coverage.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/libraries/intellij_coverage.xml b/.idea/libraries/intellij_coverage.xml
new file mode 100644
index 000000000000..0821d76efd40
--- /dev/null
+++ b/.idea/libraries/intellij_coverage.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/intellij_test_discovery.xml b/.idea/libraries/intellij_test_discovery.xml
new file mode 100644
index 000000000000..e6082b6fe695
--- /dev/null
+++ b/.idea/libraries/intellij_test_discovery.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java/execution/impl/intellij.java.execution.impl.iml b/java/execution/impl/intellij.java.execution.impl.iml
index 029f0ba24a68..5bafa0222a4a 100644
--- a/java/execution/impl/intellij.java.execution.impl.iml
+++ b/java/execution/impl/intellij.java.execution.impl.iml
@@ -18,7 +18,8 @@
-
+
+
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/IdeaSocketTestDiscoveryDataReader.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/IdeaSocketTestDiscoveryDataReader.java
new file mode 100644
index 000000000000..a05b01429fd1
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/IdeaSocketTestDiscoveryDataReader.java
@@ -0,0 +1,56 @@
+// 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.rt.coverage.data.SocketTestDataReader;
+import com.intellij.util.containers.MultiMap;
+import gnu.trove.TIntObjectHashMap;
+import org.jetbrains.annotations.NotNull;
+
+class IdeaSocketTestDiscoveryDataReader extends SocketTestDataReader {
+ private static final Logger LOG = Logger.getInstance(IdeaSocketTestDiscoveryDataReader.class);
+
+ @NotNull
+ private final TIntObjectHashMap myTestExecutionNameEnumerator;
+
+ //test data
+ private String myTestName;
+ private final MultiMap myUsedMethods = new MultiMap<>();
+
+ IdeaSocketTestDiscoveryDataReader(@NotNull TIntObjectHashMap testExecutionNameEnumerator) {
+ myTestExecutionNameEnumerator = testExecutionNameEnumerator;
+ }
+
+ @NotNull
+ String getTestName() {
+ return myTestName;
+ }
+
+ @NotNull
+ MultiMap getUsedMethods() {
+ return myUsedMethods;
+ }
+
+
+ @Override
+ protected void processTestName(int testClassId, int testMethodId) {
+ myTestName = myTestExecutionNameEnumerator.get(testClassId) + "-" + myTestExecutionNameEnumerator.get(testMethodId);
+ }
+
+ @Override
+ protected void processEnumeratedName(int id, String name) {
+ String previousName = myTestExecutionNameEnumerator.put(id, name);
+ LOG.assertTrue(previousName == null || previousName.equals(name));
+ }
+
+ @Override
+ protected void processUsedMethod(int classInternalId, int methodInternalId) {
+ String className = myTestExecutionNameEnumerator.get(classInternalId);
+ String methodName = myTestExecutionNameEnumerator.get(methodInternalId);
+ if (className == null || methodName == null) {
+ LOG.error("Inconsistent state");
+ return;
+ }
+ myUsedMethods.putValue(className, methodName);
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/IdeaTrFileTestDataReader.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/IdeaTrFileTestDataReader.java
new file mode 100644
index 000000000000..6d6d79736784
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/IdeaTrFileTestDataReader.java
@@ -0,0 +1,57 @@
+// 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.rt.coverage.data.SingleTrFileReader;
+import com.intellij.util.containers.MultiMap;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+
+class IdeaTrFileTestDataReader extends SingleTrFileReader {
+ private String myCurrentClassName;
+ private MultiMap myUsedMethods = new MultiMap<>();
+
+ private final TestDiscoveryIndex myIndex;
+ private final String myModuleName;
+ private final String myFrameworkPrefix;
+
+ public IdeaTrFileTestDataReader(@NotNull File file,
+ @NotNull TestDiscoveryIndex index,
+ @NotNull String moduleName,
+ @NotNull String frameworkPrefix) {
+ super(file);
+ myIndex = index;
+ myModuleName = moduleName;
+ myFrameworkPrefix = frameworkPrefix;
+ }
+
+ @Override
+ protected void testProcessingFinished(String testName) {
+ // flush
+ try {
+ int separatorIndex = testName.lastIndexOf('.');
+ testName = testName.substring(0, separatorIndex) + "-" + testName.substring(separatorIndex + 1);
+ myIndex.updateFromData(testName, myUsedMethods, myModuleName, myFrameworkPrefix);
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ myUsedMethods.clear();
+ }
+
+ @Override
+ protected void classProcessingFinished(String className) {
+ myCurrentClassName = null;
+ }
+
+ @Override
+ protected void processMethodName(String methodName) {
+ myUsedMethods.putValue(myCurrentClassName, methodName);
+ }
+
+ @Override
+ protected void classProcessingStarted(String className) {
+ myCurrentClassName = className;
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryConfigurationProducer.java
index a7845c73b615..5c1d8aaa04f0 100644
--- a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryConfigurationProducer.java
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryConfigurationProducer.java
@@ -65,9 +65,8 @@ public abstract class TestDiscoveryConfigurationProducer extends JavaRunConfigur
try {
final Project project = configuration.getProject();
final TestDiscoveryIndex testDiscoveryIndex = TestDiscoveryIndex.getInstance(project);
- final Collection testsByMethodName = testDiscoveryIndex.getTestsByMethodName(position.first, position.second);
- if (testsByMethodName == null ||
- ContainerUtil.filter(testsByMethodName, s -> s.startsWith(configuration.getFrameworkPrefix())).isEmpty()) {
+ final Collection testsByMethodName = testDiscoveryIndex.getTestsByMethodName(position.first, position.second, configuration.getFrameworkPrefix());
+ if (ContainerUtil.isEmpty(testsByMethodName)) {
return false;
}
setPosition(configuration, new PsiLocation<>(sourceMethod));
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryDataSocketListener.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryDataSocketListener.java
new file mode 100644
index 000000000000..9f963081c627
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryDataSocketListener.java
@@ -0,0 +1,129 @@
+// 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.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.rt.coverage.data.SocketTestDataReader;
+import com.intellij.rt.coverage.data.SocketTestDiscoveryProtocolDataListener;
+import com.intellij.rt.coverage.data.TestDiscoveryProtocolDataListener;
+import com.intellij.util.TimeoutUtil;
+import gnu.trove.TIntObjectHashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+public class TestDiscoveryDataSocketListener {
+ private static final Logger LOG = Logger.getInstance(TestDiscoveryDataSocketListener.class);
+
+ private final @Nullable String myModuleName;
+ private final @NotNull String myFrameworkPrefix;
+ private final ServerSocket myServer;
+ private final int myPort;
+ private final TestDiscoveryIndex myTestDiscoveryIndex;
+ private final TIntObjectHashMap myTestExecutionNameEnumerator = new TIntObjectHashMap<>();
+ private volatile boolean myCloseForcibly;
+ private volatile boolean myStarted;
+
+ public TestDiscoveryDataSocketListener(@NotNull Project project,
+ @Nullable String moduleName,
+ @NotNull String frameworkPrefix) throws IOException {
+ myTestDiscoveryIndex = TestDiscoveryIndex.getInstance(project);
+ myModuleName = moduleName;
+ myFrameworkPrefix = frameworkPrefix;
+ myServer = new ServerSocket(0);
+ myPort = myServer.getLocalPort();
+
+ ApplicationManager.getApplication().executeOnPooledThread(() -> {
+ Socket socket;
+ myStarted = true;
+ while (true) {
+ if (myCloseForcibly) {
+ return;
+ }
+ try {
+ socket = myServer.accept();
+ if (socket != null) {
+ break;
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ return;
+ }
+ TimeoutUtil.sleep(10);
+ }
+
+ try {
+ listenForFinishedTests(socket);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ });
+
+ while (!myStarted) {
+ TimeoutUtil.sleep(10);
+ }
+ }
+
+ private void listenForFinishedTests(@NotNull Socket socket) throws IOException {
+ InputStream testDataStream = socket.getInputStream();
+
+ while (true) {
+ byte msgType = (byte)testDataStream.read();
+ switch (msgType) {
+ case TestDiscoveryProtocolDataListener.START_MARKER:
+ int version = testDataStream.read();
+ LOG.assertTrue(version == SocketTestDiscoveryProtocolDataListener.VERSION);
+ LOG.debug("test discovery started");
+ break;
+ case TestDiscoveryProtocolDataListener.FINISH_MARKER:
+ LOG.debug("test discovery finished");
+ socket.close();
+ myServer.close();
+ return;
+ case TestDiscoveryProtocolDataListener.NAMES_DICTIONARY_PART_MARKER:
+ LOG.info("name enumerator part received");
+ SocketTestDataReader.readDictionary(new DataInputStream(testDataStream), new SocketTestDataReader() {
+ @Override
+ protected void processTestName(int testClassId, int testMethodId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void processUsedMethod(int classId, int methodId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void processEnumeratedName(int id, String name) {
+ String previousName = myTestExecutionNameEnumerator.put(id, name);
+ LOG.assertTrue(previousName == null || name.equals(previousName));
+ }
+ });
+ break;
+ case TestDiscoveryProtocolDataListener.TEST_FINISHED_MARKER:
+ LOG.info("test data received");
+ IdeaSocketTestDiscoveryDataReader reader = new IdeaSocketTestDiscoveryDataReader(myTestExecutionNameEnumerator);
+ SocketTestDataReader.readTestData(new DataInputStream(testDataStream), reader);
+ myTestDiscoveryIndex.updateFromData(reader.getTestName(), reader.getUsedMethods(), myModuleName, myFrameworkPrefix);
+ break;
+ }
+ }
+
+ }
+
+ public int getPort() {
+ return myPort;
+ }
+
+ public void closeForcibly() {
+ //myCloseForcibly = true;
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryExtension.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryExtension.java
index 5f26df25af32..f22f821d62c0 100644
--- a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryExtension.java
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryExtension.java
@@ -1,18 +1,4 @@
-/*
- * Copyright 2000-2017 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.
- */
+// 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.execution.JavaTestConfigurationBase;
@@ -22,7 +8,6 @@ import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.testframework.JavaTestLocator;
import com.intellij.execution.testframework.sm.runner.SMTRunnerEventsAdapter;
import com.intellij.execution.testframework.sm.runner.SMTRunnerEventsListener;
import com.intellij.execution.testframework.sm.runner.SMTestProxy;
@@ -32,14 +17,17 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
-import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.rt.coverage.data.SingleTrFileDiscoveryProtocolDataListener;
+import com.intellij.rt.coverage.data.SocketTestDiscoveryProtocolDataListener;
import com.intellij.rt.coverage.data.TestDiscoveryProjectData;
+import com.intellij.rt.coverage.main.CoveragePremain;
import com.intellij.util.Alarm;
-import com.intellij.util.ArrayUtil;
import com.intellij.util.PathUtil;
+import com.intellij.util.SystemProperties;
import com.intellij.util.messages.MessageBusConnection;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -48,10 +36,11 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
public class TestDiscoveryExtension extends RunConfigurationExtension {
+ private static final boolean USE_SOCKET = SystemProperties.getBooleanProperty("test.discovery.use.socket", false);
+ private static final Key SOCKET_LISTENER_KEY = Key.create("test.discovery.socket.data.listener");
+
private static final Logger LOG = Logger.getInstance(TestDiscoveryExtension.class);
@NotNull
@@ -65,42 +54,24 @@ public class TestDiscoveryExtension extends RunConfigurationExtension {
@NotNull final ProcessHandler handler,
@Nullable RunnerSettings runnerSettings) {
if (runnerSettings == null && isApplicableFor(configuration)) {
- final String frameworkPrefix = ((JavaTestConfigurationBase)configuration).getFrameworkPrefix();
- final String moduleName = ((JavaTestConfigurationBase)configuration).getConfigurationModule().getModuleName();
-
Disposable disposable = Disposer.newDisposable();
final Alarm processTracesAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, disposable);
final MessageBusConnection connection = configuration.getProject().getMessageBus().connect();
- connection.subscribe(SMTRunnerEventsListener.TEST_STATUS, new SMTRunnerEventsAdapter() {
- private final List myCompletedMethodNames = new ArrayList<>();
- @Override
- public void onTestFinished(@NotNull SMTestProxy test) {
- final SMTestProxy.SMRootTestProxy root = test.getRoot();
- if ((root == null || root.getHandler() == handler)) {
- final String fullTestName = test.getLocationUrl();
- if (fullTestName != null && fullTestName.startsWith(JavaTestLocator.TEST_PROTOCOL)) {
- myCompletedMethodNames.add(frameworkPrefix + fullTestName.substring(JavaTestLocator.TEST_PROTOCOL.length() + 3));
- if (myCompletedMethodNames.size() > 50) {
- final String[] fullTestNames = ArrayUtil.toStringArray(myCompletedMethodNames);
- myCompletedMethodNames.clear();
- processTracesAlarm.addRequest(() -> processAvailableTraces(fullTestNames,
- getTracesDirectory(configuration), moduleName, frameworkPrefix,
- TestDiscoveryIndex.getInstance(configuration.getProject())
- ), 100);
- }
- }
- }
- }
+ TestDiscoveryDataSocketListener listener = SOCKET_LISTENER_KEY.get(configuration);
+ connection.subscribe(SMTRunnerEventsListener.TEST_STATUS, new SMTRunnerEventsAdapter() {
@Override
public void onTestingFinished(@NotNull SMTestProxy.SMRootTestProxy testsRoot) {
- if (testsRoot.getHandler() == handler) {
+ if (testsRoot.getHandler() != handler) return;
+ if (listener == null) {
processTracesAlarm.cancelAllRequests();
processTracesAlarm.addRequest(() -> {
- processAvailableTraces(configuration);
+ processTracesFile((JavaTestConfigurationBase)configuration);
Disposer.dispose(disposable);
}, 0);
connection.disconnect();
+ } else {
+ listener.closeForcibly();
}
}
});
@@ -117,12 +88,21 @@ public class TestDiscoveryExtension extends RunConfigurationExtension {
argument.append(agentPath);
params.getVMParametersList().add(argument.toString());
params.getClassPath().add(agentPath);
- params.getVMParametersList().addProperty(TestDiscoveryProjectData.TRACE_DIR, getTracesDirectory(configuration));
+ params.getClassPath().add(PathUtil.getJarPathForClass(CoveragePremain.class));
+ TestDiscoveryDataSocketListener listener = tryInstallSocketListener(configuration);
+ if (listener != null) {
+ params.getVMParametersList().addProperty(SocketTestDiscoveryProtocolDataListener.PORT_PROP, Integer.toString(listener.getPort()));
+ params.getVMParametersList().addProperty(SocketTestDiscoveryProtocolDataListener.HOST_PROP, "127.0.0.1");
+ params.getVMParametersList().addProperty(TestDiscoveryProjectData.TEST_DISCOVERY_DATA_LISTENER_PROP, SocketTestDiscoveryProtocolDataListener.class.getName());
+ } else {
+ params.getVMParametersList().addProperty(SingleTrFileDiscoveryProtocolDataListener.TRACE_FILE, getTraceFilePath(configuration));
+ params.getVMParametersList().addProperty(TestDiscoveryProjectData.TEST_DISCOVERY_DATA_LISTENER_PROP, SingleTrFileDiscoveryProtocolDataListener.class.getName());
+ }
}
@NotNull
- private static String getTracesDirectory(RunConfigurationBase configuration) {
- return baseTestDiscoveryPathForProject(configuration.getProject()) + File.separator + configuration.getUniqueID();
+ private static String getTraceFilePath(RunConfigurationBase configuration) {
+ return baseTestDiscoveryPathForProject(configuration.getProject()) + File.separator + configuration.getUniqueID() + ".tr";
}
@Override
@@ -148,58 +128,60 @@ public class TestDiscoveryExtension extends RunConfigurationExtension {
return ProjectUtil.getProjectCachePath(project, "testDiscovery", true);
}
+ @Override
+ public void cleanUserData(RunConfigurationBase runConfigurationBase) {
+ TestDiscoveryDataSocketListener listener = runConfigurationBase.getUserData(SOCKET_LISTENER_KEY);
+ if (listener != null) {
+ listener.closeForcibly();
+ runConfigurationBase.putUserData(SOCKET_LISTENER_KEY, null);
+ }
+ }
+
private static final Object ourTracesLock = new Object();
- private static void processAvailableTraces(RunConfigurationBase configuration) {
- final String tracesDirectory = getTracesDirectory(configuration);
- final TestDiscoveryIndex coverageIndex = TestDiscoveryIndex.getInstance(configuration.getProject());
- synchronized (ourTracesLock) {
- final File tracesDirectoryFile = new File(tracesDirectory);
- final File[] testMethodTraces = tracesDirectoryFile.listFiles((dir, name) -> name.endsWith(".tr"));
- if (testMethodTraces != null) {
- for (File testMethodTrace : testMethodTraces) {
- try {
- coverageIndex.updateFromTestTrace(testMethodTrace, ((JavaTestConfigurationBase)configuration).getConfigurationModule().getModuleName(),
- ((JavaTestConfigurationBase)configuration).getFrameworkPrefix());
- FileUtil.delete(testMethodTrace);
- }
- catch (IOException e) {
- LOG.error("Can not load " + testMethodTrace, e);
- }
- }
+ private static void processTracesFile(JavaTestConfigurationBase configuration) {
+ final String tracesFilePath = getTraceFilePath(configuration);
+ final TestDiscoveryIndex testDiscoveryIndex = TestDiscoveryIndex.getInstance(configuration.getProject());
+ String moduleName = getConfigurationModuleName(configuration);
+ String frameworkPrefix = configuration.getFrameworkPrefix();
+ processTracesFile(tracesFilePath, moduleName, frameworkPrefix, testDiscoveryIndex);
+ }
- final String[] filesInTracedDirectories = tracesDirectoryFile.list();
- if (filesInTracedDirectories == null || filesInTracedDirectories.length == 0) {
- FileUtil.delete(tracesDirectoryFile);
- }
+ @SuppressWarnings("WeakerAccess") // called via reflection from com.intellij.InternalTestDiscoveryListener.flushCurrentTraces()
+ public static void processTracesFile(String tracesFilePath,
+ String moduleName,
+ String frameworkPrefix,
+ TestDiscoveryIndex discoveryIndex) {
+ final File tracesFile = new File(tracesFilePath);
+ synchronized (ourTracesLock) {
+ try {
+ new IdeaTrFileTestDataReader(tracesFile, discoveryIndex, moduleName, frameworkPrefix).read();
+ }
+ catch (IOException e) {
+ LOG.error("Can not load " + tracesFilePath, e);
+ } finally {
+ FileUtil.delete(tracesFile);
}
}
}
- @SuppressWarnings("WeakerAccess") // called via reflection from com.intellij.InternalTestDiscoveryListener.flushCurrentTraces()
- public static void processAvailableTraces(final String[] fullTestNames,
- final String tracesDirectory,
- final String moduleName,
- final String frameworkPrefix,
- final TestDiscoveryIndex discoveryIndex) {
- synchronized (ourTracesLock) {
- for (String fullTestName : fullTestNames) {
- final String className = StringUtil.getPackageName(fullTestName);
- final String methodName = StringUtil.getShortName(fullTestName);
- if (!StringUtil.isEmptyOrSpaces(className) && !StringUtil.isEmptyOrSpaces(methodName)) {
- final File testMethodTrace = new File(tracesDirectory, className + "-" + methodName + ".tr");
- if (testMethodTrace.exists()) {
- try {
- discoveryIndex.updateFromTestTrace(testMethodTrace, moduleName, frameworkPrefix);
- FileUtil.delete(testMethodTrace);
- }
- catch (Throwable e) {
- LOG.error("Can not load " + testMethodTrace, e);
- }
- }
- }
- }
+ @NotNull
+ private static String getConfigurationModuleName(JavaTestConfigurationBase configuration) {
+ return configuration.getConfigurationModule().getModuleName();
+ }
+
+ @Nullable
+ private static TestDiscoveryDataSocketListener tryInstallSocketListener(@NotNull RunConfigurationBase configuration) {
+ TestDiscoveryDataSocketListener listener = null;
+ if (USE_SOCKET) {
+ try {
+ JavaTestConfigurationBase javaTestConfigurationBase = (JavaTestConfigurationBase)configuration;
+ listener = new TestDiscoveryDataSocketListener(configuration.getProject(), getConfigurationModuleName(javaTestConfigurationBase), javaTestConfigurationBase.getFrameworkPrefix());
+ configuration.putUserData(SOCKET_LISTENER_KEY, listener);
+ } catch (IOException e) {
+ LOG.error(e);
+ }
}
-
+ return listener;
}
}
\ No newline at end of file
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryIndex.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryIndex.java
index 8531808a6046..6e761baf1c51 100644
--- a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryIndex.java
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoveryIndex.java
@@ -1,18 +1,4 @@
-/*
- * Copyright 2000-2017 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.
- */
+// 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.Disposable;
@@ -21,9 +7,9 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.ThrowableNotNullFunction;
import com.intellij.util.ThrowableConvertor;
-import com.intellij.util.io.DataInputOutputUtil;
-import com.intellij.util.io.IOUtil;
+import com.intellij.util.containers.MultiMap;
import com.intellij.util.io.PathKt;
import gnu.trove.THashSet;
import gnu.trove.TIntArrayList;
@@ -31,13 +17,10 @@ import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.io.*;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
/**
* @author Maxim.Mossienko on 7/9/2015.
@@ -97,7 +80,8 @@ public class TestDiscoveryIndex implements Disposable {
// todo: should we remove our local run data ?
}
- public Collection getTestsByMethodName(@NotNull String classFQName, @NotNull String methodName) throws IOException {
+ public Collection getTestsByMethodName(@NotNull String classFQName, @NotNull String methodName, String frameworkPrefix) throws IOException {
+ //TODO support framework prefix again
return myLocalTestRunDataController.withTestDataHolder(new ThrowableConvertor, IOException>() {
@Override
public Collection convert(TestInfoHolder localHolder) throws IOException {
@@ -263,18 +247,31 @@ public class TestDiscoveryIndex implements Disposable {
myRemoteTestRunDataController.dispose();
}
- public void updateFromTestTrace(@NotNull File file,
- @Nullable final String moduleName,
- @NotNull final String frameworkPrefix) throws IOException {
- int fileNameDotIndex = file.getName().lastIndexOf('.');
- final String testName = fileNameDotIndex != -1 ? file.getName().substring(0, fileNameDotIndex) : file.getName();
- doUpdateFromTestTrace(file, testName, moduleName != null ? frameworkPrefix + moduleName : null);
+ public void updateFromData(@NotNull String testName,
+ @NotNull MultiMap usedMethods,
+ @Nullable String moduleName,
+ @NotNull String frameworkPrefix) throws IOException {
+ doUpdateFromTestTrace(testName, holder -> {
+ TIntObjectHashMap result = new TIntObjectHashMap<>();
+ for (Map.Entry> e : usedMethods.entrySet()) {
+ int classId = holder.myClassEnumeratorCache.enumerate(e.getKey());
+ TIntArrayList methodIds = new TIntArrayList();
+ result.put(classId, methodIds);
+ for (String methodName : e.getValue()) {
+ methodIds.add(holder.myMethodEnumeratorCache.enumerate(methodName));
+ }
+ }
+ return result;
+ }, moduleName, frameworkPrefix);
}
- private void doUpdateFromTestTrace(File file, final String testName, @Nullable final String moduleName) throws IOException {
- myLocalTestRunDataController.withTestDataHolder((ThrowableConvertor)localHolder -> {
+ private void doUpdateFromTestTrace(@NotNull String testName,
+ @NotNull ThrowableNotNullFunction, IOException> classDataExtractor,
+ @Nullable String moduleName,
+ @NotNull String frameworkPrefix) throws IOException {
+ myLocalTestRunDataController.withTestDataHolder(localHolder -> {
final int testNameId = localHolder.myTestNameEnumerator.enumerate(testName);
- TIntObjectHashMap classData = loadClassAndMethodsMap(file, localHolder);
+ TIntObjectHashMap classData = classDataExtractor.fun(localHolder);
TIntObjectHashMap previousClassData = localHolder.myTestNameToUsedClassesAndMethodMap.get(testNameId);
if (previousClassData == null) {
previousClassData = myRemoteTestRunDataController.withTestDataHolder(
@@ -304,36 +301,9 @@ public class TestDiscoveryIndex implements Disposable {
});
}
- localHolder.doUpdateFromDiff(testNameId, classData, previousClassData, moduleName != null ? localHolder.myModuleNameEnumerator.enumerate(moduleName) : null);
+ String moduleId = moduleName == null ? null : moduleName + frameworkPrefix;
+ localHolder.doUpdateFromDiff(testNameId, classData, previousClassData, moduleId != null ? localHolder.myModuleNameEnumerator.enumerate(moduleId) : null);
return null;
});
}
-
- @NotNull
- private static TIntObjectHashMap loadClassAndMethodsMap(File file, TestInfoHolder holder) throws IOException {
- DataInputStream inputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(file), 64 * 1024));
- byte[] buffer = IOUtil.allocReadWriteUTFBuffer();
-
- try {
- int numberOfClasses = DataInputOutputUtil.readINT(inputStream);
- TIntObjectHashMap classData = new TIntObjectHashMap<>(numberOfClasses);
- while (numberOfClasses-- > 0) {
- String classQName = IOUtil.readUTFFast(buffer, inputStream);
- int classId = holder.myClassEnumeratorCache.enumerate(classQName);
- int numberOfMethods = DataInputOutputUtil.readINT(inputStream);
- TIntArrayList methodsList = new TIntArrayList(numberOfMethods);
-
- while (numberOfMethods-- > 0) {
- String methodName = IOUtil.readUTFFast(buffer, inputStream);
- methodsList.add(holder.myMethodEnumeratorCache.enumerate(methodName));
- }
-
- classData.put(classId, methodsList);
- }
- return classData;
- }
- finally {
- inputStream.close();
- }
- }
}
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java
index 1b8a94121cc3..1f374a60b369 100644
--- a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestDiscoverySearchHelper.java
@@ -86,7 +86,7 @@ public class TestDiscoverySearchHelper {
try {
if (classQualifiedName != null &&
(position == null && TestFrameworks.detectFramework(containingClass) != null ||
- position != null && !discoveryIndex.hasTestTrace(frameworkPrefix + classQualifiedName + "-" + changedMethodName))) {
+ position != null && !discoveryIndex.hasTestTrace(classQualifiedName + "-" + changedMethodName))) {
patterns.add(classQualifiedName + "," + changedMethodName);
}
}
@@ -112,10 +112,10 @@ public class TestDiscoverySearchHelper {
final String methodName,
final String frameworkId) throws IOException {
final TestDiscoveryIndex discoveryIndex = TestDiscoveryIndex.getInstance(project);
- final Collection testsByMethodName = discoveryIndex.getTestsByMethodName(classFQName, methodName);
+ final Collection testsByMethodName = discoveryIndex.getTestsByMethodName(classFQName, methodName, frameworkId);
if (testsByMethodName != null) {
- for (String pattern : ContainerUtil.filter(testsByMethodName, s -> s.startsWith(frameworkId))) {
- patterns.add(pattern.substring(frameworkId.length()).replace('-', ','));
+ for (String pattern : testsByMethodName) {
+ patterns.add(pattern.replace('-', ','));
}
}
}
diff --git a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestInfoHolder.java b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestInfoHolder.java
index d54aebb4dd71..f6e99a50c518 100644
--- a/java/execution/impl/src/com/intellij/execution/testDiscovery/TestInfoHolder.java
+++ b/java/execution/impl/src/com/intellij/execution/testDiscovery/TestInfoHolder.java
@@ -47,7 +47,7 @@ final class TestInfoHolder {
private boolean myDisposed;
private final Object myLock;
- private static final int VERSION = 4;
+ private static final int VERSION = 5;
TestInfoHolder(@NotNull Path basePath, boolean readOnly, Object lock) {
myLock = lock;
diff --git a/java/java-runtime/src/com/intellij/execution/TestDiscoveryListener.java b/java/java-runtime/src/com/intellij/execution/TestDiscoveryListener.java
index 3411748d7076..cbeea8979ce4 100644
--- a/java/java-runtime/src/com/intellij/execution/TestDiscoveryListener.java
+++ b/java/java-runtime/src/com/intellij/execution/TestDiscoveryListener.java
@@ -22,8 +22,8 @@ public abstract class TestDiscoveryListener {
public void testStarted(String className, String methodName) {
try {
final Object data = getData();
- Method testStarted = data.getClass().getMethod("testDiscoveryStarted", new Class[] {String.class});
- testStarted.invoke(data, new Object[] {className + "-" + methodName});
+ Method testStarted = data.getClass().getMethod("testDiscoveryStarted", new Class[] {String.class, String.class});
+ testStarted.invoke(data, new Object[] {className, methodName});
} catch (Throwable t) {
t.printStackTrace();
}
@@ -33,8 +33,8 @@ public abstract class TestDiscoveryListener {
if (succeed) {
try {
final Object data = getData();
- Method testEnded = data.getClass().getMethod("testDiscoveryEnded", new Class[] {String.class});
- testEnded.invoke(data, new Object[] {getFrameworkId() + className + "-" + methodName});
+ Method testEnded = data.getClass().getMethod("testDiscoveryEnded", new Class[] {String.class, String.class});
+ testEnded.invoke(data, new Object[] {className, methodName});
} catch (Throwable t) {
t.printStackTrace();
}
diff --git a/lib/test-discovery-agent.jar b/lib/test-discovery-agent.jar
old mode 100755
new mode 100644
index 68da6db00609..904fd7739123
Binary files a/lib/test-discovery-agent.jar and b/lib/test-discovery-agent.jar differ
diff --git a/lib/test-discovery-instrumenter.jar b/lib/test-discovery-instrumenter.jar
deleted file mode 100755
index 4adff197c39f..000000000000
Binary files a/lib/test-discovery-instrumenter.jar and /dev/null differ
diff --git a/platform/testFramework/src/com/intellij/InternalTestDiscoveryListener.java b/platform/testFramework/src/com/intellij/InternalTestDiscoveryListener.java
index ca6029a05d39..80d168f08777 100644
--- a/platform/testFramework/src/com/intellij/InternalTestDiscoveryListener.java
+++ b/platform/testFramework/src/com/intellij/InternalTestDiscoveryListener.java
@@ -19,7 +19,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.ArrayUtil;
-import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.io.ZipUtil;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
@@ -27,12 +26,8 @@ import junit.framework.TestListener;
import java.io.Closeable;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipOutputStream;
/**
* Used in TestAll to collect data in command line
@@ -40,17 +35,16 @@ import java.util.zip.ZipOutputStream;
@SuppressWarnings({"unused", "UseOfSystemOutOrSystemErr", "CallToPrintStackTrace"})
public class InternalTestDiscoveryListener implements TestListener, Closeable {
private final String myModuleName;
- private final String myTracesDirectory;
- private final List myCompletedMethodNames = new ArrayList<>();
- private final boolean myCompactResults;
+ private final String myTracesFile;
private Object myDiscoveryIndex;
private Class> myDiscoveryIndexClass;
public InternalTestDiscoveryListener() {
- myTracesDirectory = System.getProperty("org.jetbrains.instrumentation.trace.dir");
+ myTracesFile = System.getProperty("org.jetbrains.instrumentation.trace.file");
+ if (myTracesFile == null) throw new IllegalArgumentException();
myModuleName = System.getProperty("org.jetbrains.instrumentation.main.module");
- myCompactResults = Boolean.parseBoolean(System.getProperty("org.jetbrains.instrumentation.compact.traces", "true"));
- System.out.println(getClass().getSimpleName() + " instantiated with module='" + myModuleName + "' , directory='" + myTracesDirectory + "'");
+ if (myModuleName == null) throw new IllegalArgumentException();
+ System.out.println(getClass().getSimpleName() + " instantiated with module='" + myModuleName + "' , directory='" + myTracesFile + "'");
}
private Object getIndex() {
@@ -60,7 +54,7 @@ public class InternalTestDiscoveryListener implements TestListener, Closeable {
myDiscoveryIndexClass = Class.forName("com.intellij.execution.testDiscovery.TestDiscoveryIndex");
myDiscoveryIndex = myDiscoveryIndexClass
.getConstructor(Project.class, String.class)
- .newInstance(project, myTracesDirectory);
+ .newInstance(project, myTracesFile);
}
catch (Throwable e) {
e.printStackTrace();
@@ -82,37 +76,12 @@ public class InternalTestDiscoveryListener implements TestListener, Closeable {
try {
Object data = getData();
- Method testEnded = data.getClass().getMethod("testDiscoveryEnded", String.class);
- testEnded.invoke(data, "j" + className + "-" + methodName);
+ Method testEnded = data.getClass().getMethod("testDiscoveryEnded", String.class, String.class);
+ testEnded.invoke(data, className, methodName);
}
catch (Throwable t) {
t.printStackTrace();
}
-
- myCompletedMethodNames.add("j" + className + "." + methodName);
-
- if (myCompletedMethodNames.size() > 50) {
- final String[] fullTestNames = ArrayUtil.toStringArray(myCompletedMethodNames);
- myCompletedMethodNames.clear();
- AppExecutorUtil.getAppExecutorService().execute(() -> flushCurrentTraces(fullTestNames));
- }
- }
-
- protected void flushCurrentTraces(final String[] fullTestNames) {
- if (!myCompactResults) return;
- System.out.println("Start compacting to index");
- try {
- Object index = getIndex();
- Method method = Class.forName("com.intellij.execution.testDiscovery.TestDiscoveryExtension")
- .getMethod("processAvailableTraces", fullTestNames.getClass(), myTracesDirectory.getClass(), String.class,
- String.class,
- myDiscoveryIndexClass);
- method.invoke(null, fullTestNames, myTracesDirectory, myModuleName, "j", index);
- System.out.println("Compacting done.");
- }
- catch (Throwable e) {
- e.printStackTrace();
- }
}
private static String getMethodName(Test test) {
@@ -131,8 +100,8 @@ public class InternalTestDiscoveryListener implements TestListener, Closeable {
public void startTest(Test test) {
try {
Object data = getData();
- Method testStarted = data.getClass().getMethod("testDiscoveryStarted", String.class);
- testStarted.invoke(data, getClassName(test) + "-" + getMethodName(test));
+ Method testStarted = data.getClass().getMethod("testDiscoveryStarted", String.class, String.class);
+ testStarted.invoke(data, getClassName(test), getMethodName(test));
}
catch (Throwable t) {
t.printStackTrace();
@@ -140,39 +109,40 @@ public class InternalTestDiscoveryListener implements TestListener, Closeable {
}
protected Object getData() throws Exception {
- return Class.forName("com.intellij.rt.coverage.data.ProjectData")
+ return Class.forName("com.intellij.rt.coverage.data.TestDiscoveryProjectData")
.getMethod("getProjectData", ArrayUtil.EMPTY_CLASS_ARRAY)
.invoke(null, ArrayUtil.EMPTY_OBJECT_ARRAY);
}
@Override
public void close() throws IOException {
- final String[] fullTestNames = ArrayUtil.toStringArray(myCompletedMethodNames);
- myCompletedMethodNames.clear();
- flushCurrentTraces(fullTestNames);
- zipOutput(myTracesDirectory);
+ System.out.println("Start compacting to index");
+ try {
+ Object index = getIndex();
+ Method method = Class.forName("com.intellij.execution.testDiscovery.TestDiscoveryExtension")
+ .getMethod("processTracesFile", String.class, String.class, String.class, myDiscoveryIndexClass);
+ method.invoke(null, myTracesFile, myModuleName, "j", index);
+ System.out.println("Compacting done.");
+ }
+ catch (Throwable e) {
+ e.printStackTrace();
+ }
+ zipOutput(myTracesFile);
}
- private static void zipOutput(String tracesDirectory) {
- final String zipName = "out.zip";
- final File[] files = new File(tracesDirectory).listFiles((dir, name) -> name != null && !name.equalsIgnoreCase(zipName));
- if (files == null) {
- System.out.println("No traces found.");
- return;
- }
+ private static void zipOutput(String traceFilePath) {
+ File traceFile = new File(traceFilePath);
+ File parent = traceFile.getParentFile();
+ String zipName = traceFile.getName() + ".zip";
System.out.println("Preparing zip.");
- try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(new File(tracesDirectory, zipName)))) {
- for (File file : files) {
- ZipUtil.addFileToZip(zipOutputStream, file, "/" + file.getName(), null, null);
- }
- System.out.println("Zip prepared.");
-
- for (File file : files) {
- FileUtil.delete(file);
- }
+ try {
+ File zipFile = new File(parent, zipName);
+ ZipUtil.compressFile(traceFile, zipFile);
+ FileUtil.delete(traceFile);
+ System.out.println("archive " + zipFile.getPath() + " prepared");
}
- catch (Throwable ex) {
- ex.printStackTrace();
+ catch (IOException e) {
+ e.printStackTrace();
}
}
}
diff --git a/platform/testFramework/src/com/intellij/TestAll.java b/platform/testFramework/src/com/intellij/TestAll.java
index d8623303569e..14b47634accd 100644
--- a/platform/testFramework/src/com/intellij/TestAll.java
+++ b/platform/testFramework/src/com/intellij/TestAll.java
@@ -275,6 +275,7 @@ public class TestAll implements Test {
}
private static TestListener loadDiscoveryListener() {
+ // com.intellij.InternalTestDiscoveryListener
final String discoveryListener = System.getProperty("test.discovery.listener");
if (discoveryListener != null) {
try {
diff --git a/plugins/coverage-common/intellij.platform.coverage.iml b/plugins/coverage-common/intellij.platform.coverage.iml
index 9aabc3aebfe7..1c09f8f4c313 100644
--- a/plugins/coverage-common/intellij.platform.coverage.iml
+++ b/plugins/coverage-common/intellij.platform.coverage.iml
@@ -13,7 +13,8 @@
-
+
+
diff --git a/plugins/coverage/coverage_rt/intellij.java.coverage.rt.iml b/plugins/coverage/coverage_rt/intellij.java.coverage.rt.iml
index 657a814f9d2e..3be4291b0267 100644
--- a/plugins/coverage/coverage_rt/intellij.java.coverage.rt.iml
+++ b/plugins/coverage/coverage_rt/intellij.java.coverage.rt.iml
@@ -10,6 +10,7 @@
-
+
+
\ No newline at end of file
diff --git a/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java b/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java
index 252e948f15b3..58aeac2bd310 100644
--- a/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java
+++ b/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java
@@ -18,8 +18,8 @@ package com.intellij.coverage;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.rt.coverage.instrumentation.SourceLineCounter;
-import gnu.trove.TIntObjectHashMap;
-import org.jetbrains.org.objectweb.asm.ClassReader;
+import org.jetbrains.coverage.gnu.trove.TIntObjectHashMap;
+import org.jetbrains.coverage.org.objectweb.asm.ClassReader;
import java.util.HashSet;
import java.util.List;
@@ -36,7 +36,7 @@ public class SourceLineCounterUtil {
SourceLineCounter counter = new SourceLineCounter(null, excludeLines, null);
reader.accept(counter, 0);
Set