collect discovery data inside TestAll

(cherry picked from commit df6e8fb)
This commit is contained in:
Anna Kozlova
2016-06-15 16:08:41 +03:00
parent 02e10c0042
commit 5b3c24f6f1
4 changed files with 199 additions and 29 deletions
@@ -0,0 +1,134 @@
/*
* Copyright 2000-2016 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.intellij.execution.testDiscovery;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestListener;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Used in TestAll to collect data in command line
*/
@SuppressWarnings("unused")
public class InternalTestDiscoveryListener implements TestListener, Closeable {
private List<String> myCompletedMethodNames = new ArrayList<String>();
private String myTracesDirectory;
private final Alarm myProcessTracesAlarm;
private TestDiscoveryIndex myDiscoveryIndex;
public InternalTestDiscoveryListener() {
myProcessTracesAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, null);
myTracesDirectory = System.getProperty("org.jetbrains.instrumentation.trace.dir");
}
private TestDiscoveryIndex getIndex() {
if (myDiscoveryIndex == null) {
final Project project = ProjectManager.getInstance().getDefaultProject();
try {
myDiscoveryIndex = (TestDiscoveryIndex)Class.forName(TestDiscoveryIndex.class.getName())
.getConstructor(Project.class, String.class)
.newInstance(project, myTracesDirectory);
}
catch (Throwable e) {
e.printStackTrace();
}
}
return myDiscoveryIndex;
}
@Override
public void addError(Test test, Throwable t) {}
@Override
public void addFailure(Test test, AssertionFailedError t) {}
@Override
public void endTest(Test test) {
final String className = getClassName(test);
final String methodName = getMethodName(test);
try {
final Object data = getData();
Method testEnded = data.getClass().getMethod("testDiscoveryEnded", new Class[] {String.class});
testEnded.invoke(data, new Object[] {"j" + className + "-" + methodName});
} catch (Throwable t) {
t.printStackTrace();
}
myCompletedMethodNames.add("j" + className + "." + methodName);
if (myCompletedMethodNames.size() > 50) {
flushCurrentTraces();
}
}
protected void flushCurrentTraces() {
final String[] fullTestNames = ArrayUtil.toStringArray(myCompletedMethodNames);
myCompletedMethodNames.clear();
myProcessTracesAlarm.addRequest(() -> {
TestDiscoveryExtension.processAvailableTraces(fullTestNames, myTracesDirectory, null, getIndex());
}, 100);
}
private static String getMethodName(Test test) {
final String toString = test.toString();
final int braceIdx = toString.indexOf("(");
return braceIdx > 0 ? toString.substring(0, braceIdx) : toString;
}
private static String getClassName(Test test) {
final String toString = test.toString();
final int braceIdx = toString.indexOf("(");
return braceIdx > 0 && toString.endsWith(")") ? toString.substring(braceIdx + 1, toString.length() - 1) : null;
}
@Override
public void startTest(Test test) {
try {
final Object data = getData();
Method testStarted = data.getClass().getMethod("testDiscoveryStarted", new Class[] {String.class});
testStarted.invoke(data, new Object[] {getClassName(test) + "-" + getMethodName(test)});
} catch (Throwable t) {
t.printStackTrace();
}
}
protected Object getData() throws Exception {
return Class.forName("com.intellij.rt.coverage.data.ProjectData")
.getMethod("getProjectData", new Class[0])
.invoke(null, new Object[0]);
}
@Override
public void close() throws IOException {
myProcessTracesAlarm.cancelAllRequests();
myProcessTracesAlarm.addRequest(() -> {
flushCurrentTraces();
Disposer.dispose(myProcessTracesAlarm);
}, 0);
}
}
@@ -88,7 +88,10 @@ public class TestDiscoveryExtension extends RunConfigurationExtension {
if (myCompletedMethodNames.size() > 50) {
final String[] fullTestNames = ArrayUtil.toStringArray(myCompletedMethodNames);
myCompletedMethodNames.clear();
processTracesAlarm.addRequest(() -> processAvailableTraces(configuration, fullTestNames), 100);
processTracesAlarm.addRequest(() -> processAvailableTraces(fullTestNames,
getTracesDirectory(configuration), configuration,
TestDiscoveryIndex.getInstance(configuration.getProject())
), 100);
}
}
}
@@ -175,9 +178,10 @@ public class TestDiscoveryExtension extends RunConfigurationExtension {
}
}
private static void processAvailableTraces(RunConfigurationBase configuration, String[] fullTestNames) {
final String tracesDirectory = getTracesDirectory(configuration);
final TestDiscoveryIndex coverageIndex = TestDiscoveryIndex.getInstance(configuration.getProject());
public static void processAvailableTraces(final String[] fullTestNames,
final String tracesDirectory,
RunConfigurationBase configuration,
final TestDiscoveryIndex discoveryIndex) {
synchronized (ourTracesLock) {
for (String fullTestName : fullTestNames) {
final String className = StringUtil.getPackageName(fullTestName);
@@ -186,7 +190,7 @@ public class TestDiscoveryExtension extends RunConfigurationExtension {
final File testMethodTrace = new File(tracesDirectory, className + "-" + methodName + ".tr");
if (testMethodTrace.exists()) {
try {
coverageIndex.updateFromTestTrace(testMethodTrace, (JavaTestConfigurationBase)configuration);
discoveryIndex.updateFromTestTrace(testMethodTrace, (JavaTestConfigurationBase)configuration);
FileUtil.delete(testMethodTrace);
}
catch (IOException e) {
@@ -45,14 +45,18 @@ public class TestDiscoveryIndex implements ProjectComponent {
private static final int REMOVED_MARKER = -1;
private final Object ourLock = new Object();
private final Project myProject;
private final String myBasePath;
private volatile Holder myHolder;
public TestDiscoveryIndex(Project project) {
this(project, TestDiscoveryExtension.baseTestDiscoveryPathForProject(project));
}
public TestDiscoveryIndex(final Project project, final String basePath) {
myProject = project;
String path = TestDiscoveryExtension.baseTestDiscoveryPathForProject(myProject);
if (new File(path).exists()) {
myBasePath = basePath;
if (new File(basePath).exists()) {
StartupManager.getInstance(project).registerPostStartupActivity(() -> ApplicationManager.getApplication().executeOnPooledThread(() -> {
getHolder(); // proactively init with maybe io costly compact
}));
@@ -204,22 +208,26 @@ public class TestDiscoveryIndex implements ProjectComponent {
private boolean myDisposed;
Holder() {
String path = TestDiscoveryExtension.baseTestDiscoveryPathForProject(myProject);
final File versionFile = getVersionFile(path);
final File versionFile = getVersionFile(myBasePath);
versionFile.getParentFile().mkdirs();
final File methodQNameToTestNameFile = new File(path + File.separator + "methodQNameToTestName.data");
final File testNameToUsedClassesAndMethodMapFile = new File(path + File.separator + "testToCalledMethodNames.data");
final File classNameEnumeratorFile = new File(path + File.separator + "classNameEnumerator.data");
final File methodNameEnumeratorFile = new File(path + File.separator + "methodNameEnumerator.data");
final File testNameEnumeratorFile = new File(path + File.separator + "testNameEnumerator.data");
final File moduleNameEnumeratorFile = new File(path + File.separator + "moduleNameEnumerator.data");
final File testNameToNearestModuleFile = new File(path + File.separator + "testNameToNearestModule.data");
final File methodQNameToTestNameFile = new File(myBasePath + File.separator + "methodQNameToTestName.data");
final File testNameToUsedClassesAndMethodMapFile = new File(myBasePath + File.separator + "testToCalledMethodNames.data");
final File classNameEnumeratorFile = new File(myBasePath + File.separator + "classNameEnumerator.data");
final File methodNameEnumeratorFile = new File(myBasePath + File.separator + "methodNameEnumerator.data");
final File testNameEnumeratorFile = new File(myBasePath + File.separator + "testNameEnumerator.data");
final File moduleNameEnumeratorFile = new File(myBasePath + File.separator + "moduleNameEnumerator.data");
final File testNameToNearestModuleFile = new File(myBasePath + File.separator + "testNameToNearestModule.data");
try {
int version = readVersion(versionFile);
if (version != VERSION) {
LOG.info("TestDiscoveryIndex was rewritten due to version change");
deleteAllIndexDataFiles(methodQNameToTestNameFile, testNameToUsedClassesAndMethodMapFile, classNameEnumeratorFile, methodNameEnumeratorFile, testNameEnumeratorFile);
deleteAllIndexDataFiles(methodQNameToTestNameFile,
testNameToUsedClassesAndMethodMapFile,
classNameEnumeratorFile,
methodNameEnumeratorFile,
testNameEnumeratorFile, moduleNameEnumeratorFile,
testNameToNearestModuleFile);
writeVersion(versionFile);
}
@@ -276,7 +284,7 @@ public class TestDiscoveryIndex implements ProjectComponent {
myConstructedDataFiles.clear();
deleteAllIndexDataFiles(methodQNameToTestNameFile, testNameToUsedClassesAndMethodMapFile, classNameEnumeratorFile, methodNameEnumeratorFile,
testNameEnumeratorFile);
testNameEnumeratorFile, moduleNameEnumeratorFile, testNameToNearestModuleFile);
// try another time
}
@@ -327,14 +335,10 @@ public class TestDiscoveryIndex implements ProjectComponent {
}
}
private void deleteAllIndexDataFiles(File methodQNameToTestNameFile,
File testNameToUsedClassesAndMethodMapFile,
File classNameEnumeratorFile, File methodNameEnumeratorFile, File testNameEnumeratorFile) {
IOUtil.deleteAllFilesStartingWith(methodQNameToTestNameFile);
IOUtil.deleteAllFilesStartingWith(testNameToUsedClassesAndMethodMapFile);
IOUtil.deleteAllFilesStartingWith(classNameEnumeratorFile);
IOUtil.deleteAllFilesStartingWith(methodNameEnumeratorFile);
IOUtil.deleteAllFilesStartingWith(testNameEnumeratorFile);
private void deleteAllIndexDataFiles(File... files) {
for (File file : files) {
IOUtil.deleteAllFilesStartingWith(file);
}
}
private void writeVersion(File versionFile) throws IOException {
@@ -465,10 +469,10 @@ public class TestDiscoveryIndex implements ProjectComponent {
}
}
public void updateFromTestTrace(@NotNull File file, JavaTestConfigurationBase configurationBase) throws IOException {
public void updateFromTestTrace(@NotNull File file, @Nullable JavaTestConfigurationBase configurationBase) throws IOException {
int fileNameDotIndex = file.getName().lastIndexOf('.');
final String testName = fileNameDotIndex != -1 ? file.getName().substring(0, fileNameDotIndex) : file.getName();
final Module module = configurationBase.getConfigurationModule().getModule();
final Module module = configurationBase != null ? configurationBase.getConfigurationModule().getModule() : null;
doUpdateFromTestTrace(file, testName, module != null ? configurationBase.getFrameworkPrefix() + module.getName() : null);
}