Memory leak in AbstractRerunFailedTestsAction

This commit is contained in:
Vassiliy Kudryashov
2012-08-06 18:37:29 +04:00
parent 3708632cb5
commit b8bed5d119
5 changed files with 856 additions and 851 deletions
@@ -30,14 +30,13 @@ import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.ui.ComponentContainer;
import com.intellij.openapi.util.*;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -48,9 +47,10 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate {
private static List<AbstractRerunFailedTestsAction> registry = new ArrayList<AbstractRerunFailedTestsAction>();
public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate, Disposable {
private static List<AbstractRerunFailedTestsAction> registry = new CopyOnWriteArrayList<AbstractRerunFailedTestsAction>();
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction");
private TestFrameworkRunningModel myModel;
private Getter<TestFrameworkRunningModel> myModelProvider;
@@ -64,11 +64,16 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
myParent = null;
}
protected AbstractRerunFailedTestsAction(JComponent parent) {
myParent = parent;
protected AbstractRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
myParent = componentContainer.getComponent();
registry.add(this);
Disposer.register(componentContainer, this);
copyFrom(ActionManager.getInstance().getAction("RerunFailedTests"));
registerCustomShortcutSet(getShortcutSet(), parent);
registerCustomShortcutSet(getShortcutSet(), myParent);
}
public void dispose() {
registry.remove(this);
}
public void init(final TestConsoleProperties consoleProperties,
@@ -1,445 +1,445 @@
/*
* Copyright 2000-2011 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.junit;
import com.intellij.ExtensionPoints;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit2.TestProxy;
import com.intellij.execution.junit2.segments.DeferredActionsQueue;
import com.intellij.execution.junit2.segments.DeferredActionsQueueImpl;
import com.intellij.execution.junit2.segments.DispatchListener;
import com.intellij.execution.junit2.segments.Extractor;
import com.intellij.execution.junit2.ui.JUnitTreeConsoleView;
import com.intellij.execution.junit2.ui.TestsPacketsReceiver;
import com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction;
import com.intellij.execution.junit2.ui.model.JUnitRunningModel;
import com.intellij.execution.junit2.ui.model.RootTestInfo;
import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiPackage;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.rt.execution.junit.IDEAJUnitListener;
import com.intellij.rt.execution.junit.JUnitStarter;
import com.intellij.util.Function;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public abstract class TestObject implements JavaCommandLine {
protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject");
private static final String MESSAGE = ExecutionBundle.message("configuration.not.speficied.message");
protected JavaParameters myJavaParameters;
private final Project myProject;
protected final JUnitConfiguration myConfiguration;
private final ExecutionEnvironment myEnvironment;
protected File myTempFile = null;
public File myListenersFile;
public static TestObject fromString(final String id,
final Project project,
final JUnitConfiguration configuration,
ExecutionEnvironment environment) {
if (JUnitConfiguration.TEST_METHOD.equals(id))
return new TestMethod(project, configuration, environment);
if (JUnitConfiguration.TEST_CLASS.equals(id))
return new TestClass(project, configuration, environment);
if (JUnitConfiguration.TEST_PACKAGE.equals(id))
return new TestPackage(project, configuration, environment);
else if (JUnitConfiguration.TEST_DIRECTORY.equals(id)) {
return new TestDirectory(project, configuration, environment);
}
if (JUnitConfiguration.TEST_PATTERN.equals(id)) {
return new TestsPattern(project, configuration, environment);
}
return NOT_CONFIGURED;
}
public Module[] getModulesToCompile() {
final SourceScope sourceScope = getSourceScope();
return sourceScope != null ? sourceScope.getModulesToCompile() : Module.EMPTY_ARRAY;
}
protected TestObject(final Project project,
final JUnitConfiguration configuration,
ExecutionEnvironment environment) {
myProject = project;
myConfiguration = configuration;
myEnvironment = environment;
}
public abstract String suggestActionName();
@Override
public RunnerSettings getRunnerSettings() {
return myEnvironment.getRunnerSettings();
}
@Override
public ConfigurationPerRunnerSettings getConfigurationSettings() {
return myEnvironment.getConfigurationSettings();
}
public abstract RefactoringElementListener getListener(PsiElement element, JUnitConfiguration configuration);
public abstract boolean isConfiguredByElement(JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
PsiPackage testPackage);
protected void configureModule(final JavaParameters parameters, final RunConfigurationModule configurationModule, final String mainClassName)
throws CantRunException {
int classPathType = JavaParametersUtil.getClasspathType(configurationModule, mainClassName, true);
JavaParametersUtil.configureModule(configurationModule, parameters, classPathType,
myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null);
}
private static final TestObject NOT_CONFIGURED = new TestObject(null, null, null) {
@Override
public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
return null;
}
@Override
public String suggestActionName() {
throw new RuntimeException(String.valueOf(myConfiguration));
}
@Override
public boolean isConfiguredByElement(final JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
PsiPackage testPackage) {
return false;
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
throw new RuntimeConfigurationError(MESSAGE);
}
@Override
public JavaParameters getJavaParameters() throws ExecutionException {
throw new ExecutionException(MESSAGE);
}
@Override
protected void initialize() throws ExecutionException {
throw new ExecutionException(MESSAGE);
}
};
public void checkConfiguration() throws RuntimeConfigurationException{
JavaParametersUtil.checkAlternativeJRE(myConfiguration);
ProgramParametersUtil.checkWorkingDirectoryExist(myConfiguration, myConfiguration.getProject(), myConfiguration.getConfigurationModule().getModule());
}
public SourceScope getSourceScope() {
return SourceScope.modulesWithDependencies(myConfiguration.getModules());
}
protected void initialize() throws ExecutionException {
JavaParametersUtil.configureConfiguration(myJavaParameters, myConfiguration);
myJavaParameters.setMainClass(JUnitConfiguration.JUNIT_START_CLASS);
final Module module = myConfiguration.getConfigurationModule().getModule();
if (myJavaParameters.getJdk() == null){
myJavaParameters.setJdk(module != null
? ModuleRootManager.getInstance(module).getSdk()
: ProjectRootManager.getInstance(myProject).getProjectSdk());
}
myJavaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath());
myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(JUnitStarter.class));
myJavaParameters.getProgramParametersList().add(JUnitStarter.IDE_VERSION + JUnitStarter.VERSION);
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
ext.updateJavaParameters(myConfiguration, myJavaParameters, getRunnerSettings());
}
final Object[] listeners = Extensions.getExtensions(IDEAJUnitListener.EP_NAME);
final StringBuilder buf = new StringBuilder();
for (final Object listener : listeners) {
boolean enabled = true;
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
if (ext.isListenerDisabled(myConfiguration, listener, getRunnerSettings())) {
enabled = false;
break;
}
}
if (enabled) {
final Class classListener = listener.getClass();
buf.append(classListener.getName()).append("\n");
myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(classListener));
}
}
if (buf.length() > 0) {
try {
myListenersFile = FileUtil.createTempFile("junit_listeners_", "");
myListenersFile.deleteOnExit();
myJavaParameters.getProgramParametersList().add("@@" + myListenersFile.getPath());
FileUtil.writeToFile(myListenersFile, buf.toString().getBytes());
}
catch (IOException e) {
LOG.error(e);
}
}
}
@Override
public JavaParameters getJavaParameters() throws ExecutionException {
if (myJavaParameters == null) {
myJavaParameters = new JavaParameters();
initialize();
final Module module = myConfiguration.getConfigurationModule().getModule();
final Object[] patchers = Extensions.getExtensions(ExtensionPoints.JUNIT_PATCHER);
for (Object patcher : patchers) {
((JUnitPatcher)patcher).patchJavaParameters(module, myJavaParameters);
}
}
return myJavaParameters;
}
@Override
public ExecutionResult execute(final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
final JUnitProcessHandler handler = createHandler(executor);
final RunnerSettings runnerSettings = getRunnerSettings();
JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(myConfiguration, handler, runnerSettings);
final TestProxy unboundOutputRoot = new TestProxy(new RootTestInfo());
final JUnitConsoleProperties consoleProperties = new JUnitConsoleProperties(myConfiguration, executor);
final JUnitTreeConsoleView consoleView = new JUnitTreeConsoleView(consoleProperties, runnerSettings, getConfigurationSettings(), unboundOutputRoot);
consoleView.initUI();
consoleView.attachToProcess(handler);
unboundOutputRoot.setPrinter(consoleView.getPrinter());
Disposer.register(consoleView, unboundOutputRoot);
final TestsPacketsReceiver packetsReceiver = new TestsPacketsReceiver(consoleView, unboundOutputRoot) {
@Override
public void notifyStart(TestProxy root) {
if (!isRunning()) return;
super.notifyStart(root);
unboundOutputRoot.addChild(root);
if (myConfiguration.isSaveOutputToFile()) {
unboundOutputRoot.setOutputFilePath(myConfiguration.getOutputFilePath());
}
final JUnitRunningModel model = getModel();
if (model != null) {
handler.getOut().setDispatchListener(model.getNotifier());
Disposer.register(model, new Disposable() {
@Override
public void dispose() {
handler.getOut().setDispatchListener(DispatchListener.DEAF);
}
});
consoleView.attachToModel(model);
}
}
};
final DeferredActionsQueue queue = new DeferredActionsQueueImpl();
handler.getOut().setPacketDispatcher(packetsReceiver, queue);
handler.getErr().setPacketDispatcher(packetsReceiver, queue);
handler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
handler.removeProcessListener(this);
if (myTempFile != null) {
FileUtil.delete(myTempFile);
}
if (myListenersFile != null) {
FileUtil.delete(myListenersFile);
}
IJSwingUtilities.invoke(new Runnable() {
@Override
public void run() {
try {
unboundOutputRoot.flush();
packetsReceiver.checkTerminated();
final JUnitRunningModel model = packetsReceiver.getModel();
notifyByBalloon(model, consoleProperties);
}
finally {
if (ApplicationManager.getApplication().isUnitTestMode()) {
Disposer.dispose(consoleView);
}
}
}
});
}
@Override
public void onTextAvailable(final ProcessEvent event, final Key outputType) {
final String text = event.getText();
final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType);
final Printable printable = new Printable() {
@Override
public void printOn(final Printer printer) {
printer.print(text, consoleViewType);
}
};
final Extractor extractor;
if (consoleViewType == ConsoleViewContentType.ERROR_OUTPUT ||
consoleViewType == ConsoleViewContentType.SYSTEM_OUTPUT) {
extractor = handler.getErr();
}
else {
extractor = handler.getOut();
}
extractor.getEventsDispatcher().processOutput(printable);
}
});
if (ApplicationManager.getApplication().isUnitTestMode()) {
return new DefaultExecutionResult(null, handler);
}
final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView.getComponent());
rerunFailedTestsAction.init(consoleProperties, myEnvironment);
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
@Override
public TestFrameworkRunningModel get() {
return packetsReceiver.getModel();
}
});
final DefaultExecutionResult result = new DefaultExecutionResult(consoleView, handler);
result.setRestartActions(rerunFailedTestsAction);
return result;
}
protected void notifyByBalloon(JUnitRunningModel model, JUnitConsoleProperties consoleProperties) {
TestsUIUtil.notifyByBalloon(myProject, model != null ? model.getRoot() : null, consoleProperties);
}
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
appendForkInfo(executor);
return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myProject, true));
}
private void appendForkInfo(Executor executor) throws ExecutionException {
final String forkMode = myConfiguration.getForkMode();
if (Comparing.strEqual(forkMode, "none")) {
return;
}
if (getRunnerSettings().getData() != null) {
final String actionName = executor.getActionName();
throw new CantRunException(actionName + " is disabled in fork mode.<br/>Please change fork mode to &lt;none&gt; to " + actionName.toLowerCase() + ".");
}
final JavaParameters javaParameters = getJavaParameters();
final Sdk jdk = javaParameters.getJdk();
if (jdk == null) {
throw new ExecutionException(ExecutionBundle.message("run.configuration.error.no.jdk.specified"));
}
try {
final File tempFile = FileUtil.createTempFile("command.line", "", true);
final PrintWriter writer = new PrintWriter(tempFile, "UTF-8");
try {
writer.println(((JavaSdkType)jdk.getSdkType()).getVMExecutablePath(jdk));
for (String vmParameter : javaParameters.getVMParametersList().getList()) {
writer.println(vmParameter);
}
writer.println("-classpath");
writer.println(javaParameters.getClassPath().getPathsString());
}
finally {
writer.close();
}
myJavaParameters.getProgramParametersList().add("@@@" + forkMode + ',' + tempFile.getAbsolutePath());
}
catch (Exception e) {
LOG.error(e);
}
}
protected <T> void addClassesListToJavaParameters(Collection<? extends T> elements, Function<T, String> nameFunction, String packageName,
boolean createTempFile,
boolean junit4) {
try {
if (createTempFile) {
myTempFile = FileUtil.createTempFile("idea_junit", ".tmp");
myTempFile.deleteOnExit();
myJavaParameters.getProgramParametersList().add("@" + myTempFile.getAbsolutePath());
}
final PrintWriter writer = new PrintWriter(myTempFile, "UTF-8");
try {
writer.println(packageName);
final List<String> testNames = new ArrayList<String>();
for (final T element : elements) {
final String name = nameFunction.fun(element);
if (name == null) {
LOG.error("invalid element " + element);
return;
}
testNames.add(name);
}
Collections.sort(testNames); //sort tests in FQN order
for (String testName : testNames) {
writer.println(testName);
}
}
finally {
writer.close();
}
}
catch (IOException e) {
LOG.error(e);
}
}
public void clear() {
myJavaParameters = null;
}
}
/*
* Copyright 2000-2011 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.junit;
import com.intellij.ExtensionPoints;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.junit2.TestProxy;
import com.intellij.execution.junit2.segments.DeferredActionsQueue;
import com.intellij.execution.junit2.segments.DeferredActionsQueueImpl;
import com.intellij.execution.junit2.segments.DispatchListener;
import com.intellij.execution.junit2.segments.Extractor;
import com.intellij.execution.junit2.ui.JUnitTreeConsoleView;
import com.intellij.execution.junit2.ui.TestsPacketsReceiver;
import com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction;
import com.intellij.execution.junit2.ui.model.JUnitRunningModel;
import com.intellij.execution.junit2.ui.model.RootTestInfo;
import com.intellij.execution.junit2.ui.properties.JUnitConsoleProperties;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiPackage;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.rt.execution.junit.IDEAJUnitListener;
import com.intellij.rt.execution.junit.JUnitStarter;
import com.intellij.util.Function;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.PathUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public abstract class TestObject implements JavaCommandLine {
protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject");
private static final String MESSAGE = ExecutionBundle.message("configuration.not.speficied.message");
protected JavaParameters myJavaParameters;
private final Project myProject;
protected final JUnitConfiguration myConfiguration;
private final ExecutionEnvironment myEnvironment;
protected File myTempFile = null;
public File myListenersFile;
public static TestObject fromString(final String id,
final Project project,
final JUnitConfiguration configuration,
ExecutionEnvironment environment) {
if (JUnitConfiguration.TEST_METHOD.equals(id))
return new TestMethod(project, configuration, environment);
if (JUnitConfiguration.TEST_CLASS.equals(id))
return new TestClass(project, configuration, environment);
if (JUnitConfiguration.TEST_PACKAGE.equals(id))
return new TestPackage(project, configuration, environment);
else if (JUnitConfiguration.TEST_DIRECTORY.equals(id)) {
return new TestDirectory(project, configuration, environment);
}
if (JUnitConfiguration.TEST_PATTERN.equals(id)) {
return new TestsPattern(project, configuration, environment);
}
return NOT_CONFIGURED;
}
public Module[] getModulesToCompile() {
final SourceScope sourceScope = getSourceScope();
return sourceScope != null ? sourceScope.getModulesToCompile() : Module.EMPTY_ARRAY;
}
protected TestObject(final Project project,
final JUnitConfiguration configuration,
ExecutionEnvironment environment) {
myProject = project;
myConfiguration = configuration;
myEnvironment = environment;
}
public abstract String suggestActionName();
@Override
public RunnerSettings getRunnerSettings() {
return myEnvironment.getRunnerSettings();
}
@Override
public ConfigurationPerRunnerSettings getConfigurationSettings() {
return myEnvironment.getConfigurationSettings();
}
public abstract RefactoringElementListener getListener(PsiElement element, JUnitConfiguration configuration);
public abstract boolean isConfiguredByElement(JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
PsiPackage testPackage);
protected void configureModule(final JavaParameters parameters, final RunConfigurationModule configurationModule, final String mainClassName)
throws CantRunException {
int classPathType = JavaParametersUtil.getClasspathType(configurationModule, mainClassName, true);
JavaParametersUtil.configureModule(configurationModule, parameters, classPathType,
myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null);
}
private static final TestObject NOT_CONFIGURED = new TestObject(null, null, null) {
@Override
public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
return null;
}
@Override
public String suggestActionName() {
throw new RuntimeException(String.valueOf(myConfiguration));
}
@Override
public boolean isConfiguredByElement(final JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
PsiPackage testPackage) {
return false;
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
throw new RuntimeConfigurationError(MESSAGE);
}
@Override
public JavaParameters getJavaParameters() throws ExecutionException {
throw new ExecutionException(MESSAGE);
}
@Override
protected void initialize() throws ExecutionException {
throw new ExecutionException(MESSAGE);
}
};
public void checkConfiguration() throws RuntimeConfigurationException{
JavaParametersUtil.checkAlternativeJRE(myConfiguration);
ProgramParametersUtil.checkWorkingDirectoryExist(myConfiguration, myConfiguration.getProject(), myConfiguration.getConfigurationModule().getModule());
}
public SourceScope getSourceScope() {
return SourceScope.modulesWithDependencies(myConfiguration.getModules());
}
protected void initialize() throws ExecutionException {
JavaParametersUtil.configureConfiguration(myJavaParameters, myConfiguration);
myJavaParameters.setMainClass(JUnitConfiguration.JUNIT_START_CLASS);
final Module module = myConfiguration.getConfigurationModule().getModule();
if (myJavaParameters.getJdk() == null){
myJavaParameters.setJdk(module != null
? ModuleRootManager.getInstance(module).getSdk()
: ProjectRootManager.getInstance(myProject).getProjectSdk());
}
myJavaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath());
myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(JUnitStarter.class));
myJavaParameters.getProgramParametersList().add(JUnitStarter.IDE_VERSION + JUnitStarter.VERSION);
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
ext.updateJavaParameters(myConfiguration, myJavaParameters, getRunnerSettings());
}
final Object[] listeners = Extensions.getExtensions(IDEAJUnitListener.EP_NAME);
final StringBuilder buf = new StringBuilder();
for (final Object listener : listeners) {
boolean enabled = true;
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
if (ext.isListenerDisabled(myConfiguration, listener, getRunnerSettings())) {
enabled = false;
break;
}
}
if (enabled) {
final Class classListener = listener.getClass();
buf.append(classListener.getName()).append("\n");
myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(classListener));
}
}
if (buf.length() > 0) {
try {
myListenersFile = FileUtil.createTempFile("junit_listeners_", "");
myListenersFile.deleteOnExit();
myJavaParameters.getProgramParametersList().add("@@" + myListenersFile.getPath());
FileUtil.writeToFile(myListenersFile, buf.toString().getBytes());
}
catch (IOException e) {
LOG.error(e);
}
}
}
@Override
public JavaParameters getJavaParameters() throws ExecutionException {
if (myJavaParameters == null) {
myJavaParameters = new JavaParameters();
initialize();
final Module module = myConfiguration.getConfigurationModule().getModule();
final Object[] patchers = Extensions.getExtensions(ExtensionPoints.JUNIT_PATCHER);
for (Object patcher : patchers) {
((JUnitPatcher)patcher).patchJavaParameters(module, myJavaParameters);
}
}
return myJavaParameters;
}
@Override
public ExecutionResult execute(final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
final JUnitProcessHandler handler = createHandler(executor);
final RunnerSettings runnerSettings = getRunnerSettings();
JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(myConfiguration, handler, runnerSettings);
final TestProxy unboundOutputRoot = new TestProxy(new RootTestInfo());
final JUnitConsoleProperties consoleProperties = new JUnitConsoleProperties(myConfiguration, executor);
final JUnitTreeConsoleView consoleView = new JUnitTreeConsoleView(consoleProperties, runnerSettings, getConfigurationSettings(), unboundOutputRoot);
consoleView.initUI();
consoleView.attachToProcess(handler);
unboundOutputRoot.setPrinter(consoleView.getPrinter());
Disposer.register(consoleView, unboundOutputRoot);
final TestsPacketsReceiver packetsReceiver = new TestsPacketsReceiver(consoleView, unboundOutputRoot) {
@Override
public void notifyStart(TestProxy root) {
if (!isRunning()) return;
super.notifyStart(root);
unboundOutputRoot.addChild(root);
if (myConfiguration.isSaveOutputToFile()) {
unboundOutputRoot.setOutputFilePath(myConfiguration.getOutputFilePath());
}
final JUnitRunningModel model = getModel();
if (model != null) {
handler.getOut().setDispatchListener(model.getNotifier());
Disposer.register(model, new Disposable() {
@Override
public void dispose() {
handler.getOut().setDispatchListener(DispatchListener.DEAF);
}
});
consoleView.attachToModel(model);
}
}
};
final DeferredActionsQueue queue = new DeferredActionsQueueImpl();
handler.getOut().setPacketDispatcher(packetsReceiver, queue);
handler.getErr().setPacketDispatcher(packetsReceiver, queue);
handler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
handler.removeProcessListener(this);
if (myTempFile != null) {
FileUtil.delete(myTempFile);
}
if (myListenersFile != null) {
FileUtil.delete(myListenersFile);
}
IJSwingUtilities.invoke(new Runnable() {
@Override
public void run() {
try {
unboundOutputRoot.flush();
packetsReceiver.checkTerminated();
final JUnitRunningModel model = packetsReceiver.getModel();
notifyByBalloon(model, consoleProperties);
}
finally {
if (ApplicationManager.getApplication().isUnitTestMode()) {
Disposer.dispose(consoleView);
}
}
}
});
}
@Override
public void onTextAvailable(final ProcessEvent event, final Key outputType) {
final String text = event.getText();
final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType);
final Printable printable = new Printable() {
@Override
public void printOn(final Printer printer) {
printer.print(text, consoleViewType);
}
};
final Extractor extractor;
if (consoleViewType == ConsoleViewContentType.ERROR_OUTPUT ||
consoleViewType == ConsoleViewContentType.SYSTEM_OUTPUT) {
extractor = handler.getErr();
}
else {
extractor = handler.getOut();
}
extractor.getEventsDispatcher().processOutput(printable);
}
});
if (ApplicationManager.getApplication().isUnitTestMode()) {
return new DefaultExecutionResult(null, handler);
}
final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView);
rerunFailedTestsAction.init(consoleProperties, myEnvironment);
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
@Override
public TestFrameworkRunningModel get() {
return packetsReceiver.getModel();
}
});
final DefaultExecutionResult result = new DefaultExecutionResult(consoleView, handler);
result.setRestartActions(rerunFailedTestsAction);
return result;
}
protected void notifyByBalloon(JUnitRunningModel model, JUnitConsoleProperties consoleProperties) {
TestsUIUtil.notifyByBalloon(myProject, model != null ? model.getRoot() : null, consoleProperties);
}
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
appendForkInfo(executor);
return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myProject, true));
}
private void appendForkInfo(Executor executor) throws ExecutionException {
final String forkMode = myConfiguration.getForkMode();
if (Comparing.strEqual(forkMode, "none")) {
return;
}
if (getRunnerSettings().getData() != null) {
final String actionName = executor.getActionName();
throw new CantRunException(actionName + " is disabled in fork mode.<br/>Please change fork mode to &lt;none&gt; to " + actionName.toLowerCase() + ".");
}
final JavaParameters javaParameters = getJavaParameters();
final Sdk jdk = javaParameters.getJdk();
if (jdk == null) {
throw new ExecutionException(ExecutionBundle.message("run.configuration.error.no.jdk.specified"));
}
try {
final File tempFile = FileUtil.createTempFile("command.line", "", true);
final PrintWriter writer = new PrintWriter(tempFile, "UTF-8");
try {
writer.println(((JavaSdkType)jdk.getSdkType()).getVMExecutablePath(jdk));
for (String vmParameter : javaParameters.getVMParametersList().getList()) {
writer.println(vmParameter);
}
writer.println("-classpath");
writer.println(javaParameters.getClassPath().getPathsString());
}
finally {
writer.close();
}
myJavaParameters.getProgramParametersList().add("@@@" + forkMode + ',' + tempFile.getAbsolutePath());
}
catch (Exception e) {
LOG.error(e);
}
}
protected <T> void addClassesListToJavaParameters(Collection<? extends T> elements, Function<T, String> nameFunction, String packageName,
boolean createTempFile,
boolean junit4) {
try {
if (createTempFile) {
myTempFile = FileUtil.createTempFile("idea_junit", ".tmp");
myTempFile.deleteOnExit();
myJavaParameters.getProgramParametersList().add("@" + myTempFile.getAbsolutePath());
}
final PrintWriter writer = new PrintWriter(myTempFile, "UTF-8");
try {
writer.println(packageName);
final List<String> testNames = new ArrayList<String>();
for (final T element : elements) {
final String name = nameFunction.fun(element);
if (name == null) {
LOG.error("invalid element " + element);
return;
}
testNames.add(name);
}
Collections.sort(testNames); //sort tests in FQN order
for (String testName : testNames) {
writer.println(testName);
}
}
finally {
writer.close();
}
}
catch (IOException e) {
LOG.error(e);
}
}
public void clear() {
myJavaParameters = null;
}
}
@@ -24,17 +24,16 @@ import com.intellij.execution.junit.JUnitConfiguration;
import com.intellij.execution.junit.TestMethods;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.ComponentContainer;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
/**
* @author Alexey
*/
public class RerunFailedTestsAction extends AbstractRerunFailedTestsAction {
public RerunFailedTestsAction(JComponent parent) {
super(parent);
public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
super(componentContainer);
}
@Override
@@ -1,390 +1,390 @@
/*
* Copyright 2000-2009 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.
*/
/*
* Created by IntelliJ IDEA.
* User: amrk
* Date: Jul 2, 2005
* Time: 12:22:07 AM
*/
package com.theoryinpractice.testng.configuration;
import com.intellij.ExtensionPoints;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.LanguageLevelUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.PathUtil;
import com.intellij.util.net.NetUtils;
import com.theoryinpractice.testng.model.*;
import com.theoryinpractice.testng.ui.TestNGConsoleView;
import com.theoryinpractice.testng.ui.TestNGResults;
import com.theoryinpractice.testng.ui.actions.RerunFailedTestsAction;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.testng.CommandLineArgs;
import org.testng.IDEATestNGListener;
import org.testng.RemoteTestNGStarter;
import org.testng.annotations.AfterClass;
import org.testng.remote.RemoteArgs;
import org.testng.remote.RemoteTestNG;
import org.testng.remote.strprotocol.MessageHelper;
import org.testng.remote.strprotocol.SerializedMessageSender;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
public class TestNGRunnableState extends JavaCommandLineState {
private static final Logger LOG = Logger.getInstance("TestNG Runner");
private final ConfigurationPerRunnerSettings myConfigurationPerRunnerSettings;
private final TestNGConfiguration config;
private final RunnerSettings runnerSettings;
protected final IDEARemoteTestRunnerClient client;
private int port;
private String debugPort;
private File myTempFile;
private BackgroundableProcessIndicator mySearchForTestIndicator;
private ServerSocket myServerSocket;
public TestNGRunnableState(ExecutionEnvironment environment, TestNGConfiguration config) {
super(environment);
this.runnerSettings = environment.getRunnerSettings();
myConfigurationPerRunnerSettings = environment.getConfigurationSettings();
this.config = config;
//TODO need to narrow this down a bit
//setModulesToCompile(ModuleManager.getInstance(config.getProject()).getModules());
client = new IDEARemoteTestRunnerClient();
// Want debugging?
if (runnerSettings.getData() instanceof DebuggingRunnerData) {
DebuggingRunnerData debuggingRunnerData = ((DebuggingRunnerData)runnerSettings.getData());
debugPort = debuggingRunnerData.getDebugPort();
if (debugPort.length() == 0) {
try {
debugPort = DebuggerUtils.getInstance().findAvailableDebugAddress(true);
}
catch (ExecutionException e) {
LOG.error(e);
}
debuggingRunnerData.setDebugPort(debugPort);
}
debuggingRunnerData.setLocal(true);
}
}
@Override
public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
OSProcessHandler processHandler = startProcess();
final TreeRootNode unboundOutputRoot = new TreeRootNode();
final TestNGConsoleView console = new TestNGConsoleView(config, runnerSettings, myConfigurationPerRunnerSettings, unboundOutputRoot,
executor);
console.initUI();
unboundOutputRoot.setPrinter(console.getPrinter());
Disposer.register(console, unboundOutputRoot);
JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(config, processHandler, runnerSettings);
final SearchingForTestsTask task = createSearchingForTestsTask(myServerSocket, config, myTempFile);
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(final ProcessEvent event) {
unboundOutputRoot.flush();
if (mySearchForTestIndicator != null && !mySearchForTestIndicator.isCanceled()) {
task.finish();
}
final Runnable notificationRunnable = new Runnable() {
public void run() {
final Project project = config.getProject();
if (project.isDisposed()) return;
final TestConsoleProperties consoleProperties = console.getProperties();
if (consoleProperties == null) return;
final String testRunDebugId = consoleProperties.isDebug() ? ToolWindowId.DEBUG : ToolWindowId.RUN;
final TestNGResults resultsView = console.getResultsView();
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
if (!Comparing.strEqual(toolWindowManager.getActiveToolWindowId(), testRunDebugId)) {
final MessageType type = resultsView == null || resultsView.getStatus() == MessageHelper.SKIPPED_TEST
? MessageType.WARNING
: (resultsView.getStatus() == MessageHelper.FAILED_TEST
? MessageType.ERROR
: MessageType.INFO);
final String message = resultsView == null ? "Tests were not started" : resultsView.getStatusLine();
toolWindowManager.notifyByBalloon(testRunDebugId, type, message, null, null);
TestsUIUtil.NOTIFICATION_GROUP.createNotification(message, type).notify(project);
}
}
};
SwingUtilities.invokeLater(notificationRunnable);
}
@Override
public void startNotified(final ProcessEvent event) {
TestNGRemoteListener listener = new TestNGRemoteListener(console, unboundOutputRoot);
if (config.isSaveOutputToFile()) {
unboundOutputRoot.setOutputFilePath(config.getOutputFilePath());
}
client.prepareListening(listener, port);
mySearchForTestIndicator = new BackgroundableProcessIndicator(task);
ProgressManagerImpl.runProcessWithProgressAsynchronously(task, mySearchForTestIndicator);
}
@Override
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
final TestNGResults resultsView = console.getResultsView();
if (resultsView != null) {
resultsView.finish();
}
}
private int myInsertIndex = 0;
@Override
public void onTextAvailable(final ProcessEvent event, final Key outputType) {
final TestProxy currentTest = console.getCurrentTest();
final String text = event.getText();
final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType);
final Printable printable = new Printable() {
public void printOn(final Printer printer) {
printer.print(text, consoleViewType);
}
};
if (currentTest != null) {
currentTest.addLast(printable);
}
else {
unboundOutputRoot.insert(printable, myInsertIndex);
}
myInsertIndex++;
}
});
console.attachToProcess(processHandler);
RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(console.getComponent());
rerunFailedTestsAction.init(console.getProperties(), getEnvironment());
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
public TestFrameworkRunningModel get() {
return console.getResultsView();
}
});
final DefaultExecutionResult result = new DefaultExecutionResult(console, processHandler);
result.setRestartActions(rerunFailedTestsAction);
return result;
}
@Override
protected JavaParameters createJavaParameters() throws ExecutionException {
final Project project = config.getProject();
final JavaParameters javaParameters = new JavaParameters();
javaParameters.setupEnvs(config.getPersistantData().getEnvs(), config.getPersistantData().PASS_PARENT_ENVS);
javaParameters.setMainClass("org.testng.RemoteTestNGStarter");
javaParameters.setWorkingDirectory(config.getWorkingDirectory());
javaParameters.getClassPath().add(PathUtil.getJarPathForClass(RemoteTestNGStarter.class));
//the next few lines are awkward for a reason, using compareTo for some reason causes a JVM class verification error!
Module module = config.getConfigurationModule().getModule();
LanguageLevel effectiveLanguageLevel = module == null
? LanguageLevelProjectExtension.getInstance(project).getLanguageLevel()
: LanguageLevelUtil.getEffectiveLanguageLevel(module);
final boolean is15 = effectiveLanguageLevel != LanguageLevel.JDK_1_4 && effectiveLanguageLevel != LanguageLevel.JDK_1_3;
LOG.info("Language level is " + effectiveLanguageLevel.toString());
LOG.info("is15 is " + is15);
final String pathToBundledJar = PathUtil.getJarPathForClass(AfterClass.class);
// Configure rest of jars
JavaParametersUtil.configureConfiguration(javaParameters, config);
Sdk jdk = module == null ? ProjectRootManager.getInstance(project).getProjectSdk() : ModuleRootManager.getInstance(module).getSdk();
javaParameters.setJdk(jdk);
final Object[] patchers = Extensions.getExtensions(ExtensionPoints.JUNIT_PATCHER);
for (Object patcher : patchers) {
((JUnitPatcher)patcher).patchJavaParameters(module, javaParameters);
}
JavaSdkUtil.addRtJar(javaParameters.getClassPath());
// Append coverage parameters if appropriate
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
ext.updateJavaParameters(config, javaParameters, getRunnerSettings());
}
LOG.info("Test scope is: " + config.getPersistantData().getScope());
if (config.getPersistantData().getScope() == TestSearchScope.WHOLE_PROJECT) {
LOG.info("Configuring for whole project");
JavaParametersUtil.configureProject(config.getProject(), javaParameters, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
config.ALTERNATIVE_JRE_PATH_ENABLED ? config.ALTERNATIVE_JRE_PATH : null);
}
else {
LOG.info("Configuring for module:" + config.getConfigurationModule().getModuleName());
JavaParametersUtil.configureModule(config.getConfigurationModule(), javaParameters, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
config.ALTERNATIVE_JRE_PATH_ENABLED ? config.ALTERNATIVE_JRE_PATH : null);
}
javaParameters.getClassPath().add(pathToBundledJar);
try {
port = NetUtils.findAvailableSocketPort();
}
catch (IOException e) {
throw new ExecutionException("Unable to bind to port " + port, e);
}
final TestData data = config.getPersistantData();
javaParameters.getProgramParametersList().add(supportSerializationProtocol(config) ? RemoteArgs.PORT : CommandLineArgs.PORT, String.valueOf(port));
if (data.getOutputDirectory() != null && !"".equals(data.getOutputDirectory())) {
javaParameters.getProgramParametersList().add(CommandLineArgs.OUTPUT_DIRECTORY, data.getOutputDirectory());
}
javaParameters.getProgramParametersList().add(CommandLineArgs.USE_DEFAULT_LISTENERS, String.valueOf(data.USE_DEFAULT_REPORTERS));
@NonNls final StringBuilder buf = new StringBuilder();
if (data.TEST_LISTENERS != null && !data.TEST_LISTENERS.isEmpty()) {
buf.append(StringUtil.join(data.TEST_LISTENERS, ";"));
}
for (Object o : Extensions.getExtensions(IDEATestNGListener.EP_NAME)) {
boolean enabled = true;
for (RunConfigurationExtension extension : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
if (extension.isListenerDisabled(config, o, getRunnerSettings())) {
enabled = false;
break;
}
}
if (enabled) {
if (buf.length() > 0) buf.append(";");
buf.append(o.getClass().getName());
javaParameters.getClassPath().add(PathUtil.getJarPathForClass(o.getClass()));
}
}
if (buf.length() > 0) javaParameters.getProgramParametersList().add(CommandLineArgs.LISTENER, buf.toString());
/* // Always include the source paths - just makes things easier :)
VirtualFile[] sources;
if ((data.getScope() == TestSearchScope.WHOLE_PROJECT && TestType.PACKAGE.getType().equals(data.TEST_OBJECT)) || module == null) {
sources = ProjectRootManager.getInstance(project).getContentSourceRoots();
}
else {
sources = ModuleRootManager.getInstance(module).getSourceRoots();
}
if (sources.length > 0) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < sources.length; i++) {
VirtualFile source = sources[i];
sb.append(source.getPath());
if (i < sources.length - 1) {
sb.append(';');
}
}
javaParameters.getProgramParametersList().add(TestNGCommandLineArgs.SRC_COMMAND_OPT, sb.toString());
}*/
try {
myServerSocket = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
javaParameters.getProgramParametersList().add("-socket" + myServerSocket.getLocalPort());
myTempFile = FileUtil.createTempFile("idea_testng", ".tmp");
myTempFile.deleteOnExit();
javaParameters.getProgramParametersList().add("-temp", myTempFile.getAbsolutePath());
}
catch (IOException e) {
LOG.error(e);
}
// Configure for debugging
if (runnerSettings.getData() instanceof DebuggingRunnerData) {
ParametersList params = javaParameters.getVMParametersList();
String hostname = "localhost";
try {
hostname = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e) {
}
params.add("-Xdebug");
params.add("-Xrunjdwp:transport=dt_socket,address=" + hostname + ':' + debugPort + ",suspend=y,server=n");
// params.add(debugPort);
}
return javaParameters;
}
protected SearchingForTestsTask createSearchingForTestsTask(ServerSocket serverSocket,
final TestNGConfiguration config,
final File tempFile) {
return new SearchingForTestsTask(serverSocket, config, tempFile, client);
}
public static boolean supportSerializationProtocol(TestNGConfiguration config) {
final Project project = config.getProject();
final GlobalSearchScope scopeToDetermineTestngIn;
if (config.getPersistantData().getScope() == TestSearchScope.WHOLE_PROJECT) {
scopeToDetermineTestngIn = GlobalSearchScope.allScope(project);
}
else {
scopeToDetermineTestngIn = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(config.getConfigurationModule().getModule());
}
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiClass aClass = facade.findClass(SerializedMessageSender.class.getName(), scopeToDetermineTestngIn);
if (aClass == null) return false;
final PsiClass[] starters = facade.findClasses(RemoteTestNG.class.getName(), scopeToDetermineTestngIn);
for (PsiClass starter : starters) {
if (starter.findFieldByName("m_serPort", false) == null) {
LOG.info("Multiple TestNG versions found");
return false;
}
}
return Registry.is("testng.serialized.protocol.enabled") && !TestNGVersionChecker.isVersionIncompatible(project, scopeToDetermineTestngIn);
}
}
/*
* Copyright 2000-2009 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.
*/
/*
* Created by IntelliJ IDEA.
* User: amrk
* Date: Jul 2, 2005
* Time: 12:22:07 AM
*/
package com.theoryinpractice.testng.configuration;
import com.intellij.ExtensionPoints;
import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.execution.*;
import com.intellij.execution.configurations.*;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.testframework.*;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.LanguageLevelUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
import com.intellij.openapi.progress.impl.ProgressManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.PathUtil;
import com.intellij.util.net.NetUtils;
import com.theoryinpractice.testng.model.*;
import com.theoryinpractice.testng.ui.TestNGConsoleView;
import com.theoryinpractice.testng.ui.TestNGResults;
import com.theoryinpractice.testng.ui.actions.RerunFailedTestsAction;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.testng.CommandLineArgs;
import org.testng.IDEATestNGListener;
import org.testng.RemoteTestNGStarter;
import org.testng.annotations.AfterClass;
import org.testng.remote.RemoteArgs;
import org.testng.remote.RemoteTestNG;
import org.testng.remote.strprotocol.MessageHelper;
import org.testng.remote.strprotocol.SerializedMessageSender;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
public class TestNGRunnableState extends JavaCommandLineState {
private static final Logger LOG = Logger.getInstance("TestNG Runner");
private final ConfigurationPerRunnerSettings myConfigurationPerRunnerSettings;
private final TestNGConfiguration config;
private final RunnerSettings runnerSettings;
protected final IDEARemoteTestRunnerClient client;
private int port;
private String debugPort;
private File myTempFile;
private BackgroundableProcessIndicator mySearchForTestIndicator;
private ServerSocket myServerSocket;
public TestNGRunnableState(ExecutionEnvironment environment, TestNGConfiguration config) {
super(environment);
this.runnerSettings = environment.getRunnerSettings();
myConfigurationPerRunnerSettings = environment.getConfigurationSettings();
this.config = config;
//TODO need to narrow this down a bit
//setModulesToCompile(ModuleManager.getInstance(config.getProject()).getModules());
client = new IDEARemoteTestRunnerClient();
// Want debugging?
if (runnerSettings.getData() instanceof DebuggingRunnerData) {
DebuggingRunnerData debuggingRunnerData = ((DebuggingRunnerData)runnerSettings.getData());
debugPort = debuggingRunnerData.getDebugPort();
if (debugPort.length() == 0) {
try {
debugPort = DebuggerUtils.getInstance().findAvailableDebugAddress(true);
}
catch (ExecutionException e) {
LOG.error(e);
}
debuggingRunnerData.setDebugPort(debugPort);
}
debuggingRunnerData.setLocal(true);
}
}
@Override
public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
OSProcessHandler processHandler = startProcess();
final TreeRootNode unboundOutputRoot = new TreeRootNode();
final TestNGConsoleView console = new TestNGConsoleView(config, runnerSettings, myConfigurationPerRunnerSettings, unboundOutputRoot,
executor);
console.initUI();
unboundOutputRoot.setPrinter(console.getPrinter());
Disposer.register(console, unboundOutputRoot);
JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(config, processHandler, runnerSettings);
final SearchingForTestsTask task = createSearchingForTestsTask(myServerSocket, config, myTempFile);
processHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(final ProcessEvent event) {
unboundOutputRoot.flush();
if (mySearchForTestIndicator != null && !mySearchForTestIndicator.isCanceled()) {
task.finish();
}
final Runnable notificationRunnable = new Runnable() {
public void run() {
final Project project = config.getProject();
if (project.isDisposed()) return;
final TestConsoleProperties consoleProperties = console.getProperties();
if (consoleProperties == null) return;
final String testRunDebugId = consoleProperties.isDebug() ? ToolWindowId.DEBUG : ToolWindowId.RUN;
final TestNGResults resultsView = console.getResultsView();
final ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
if (!Comparing.strEqual(toolWindowManager.getActiveToolWindowId(), testRunDebugId)) {
final MessageType type = resultsView == null || resultsView.getStatus() == MessageHelper.SKIPPED_TEST
? MessageType.WARNING
: (resultsView.getStatus() == MessageHelper.FAILED_TEST
? MessageType.ERROR
: MessageType.INFO);
final String message = resultsView == null ? "Tests were not started" : resultsView.getStatusLine();
toolWindowManager.notifyByBalloon(testRunDebugId, type, message, null, null);
TestsUIUtil.NOTIFICATION_GROUP.createNotification(message, type).notify(project);
}
}
};
SwingUtilities.invokeLater(notificationRunnable);
}
@Override
public void startNotified(final ProcessEvent event) {
TestNGRemoteListener listener = new TestNGRemoteListener(console, unboundOutputRoot);
if (config.isSaveOutputToFile()) {
unboundOutputRoot.setOutputFilePath(config.getOutputFilePath());
}
client.prepareListening(listener, port);
mySearchForTestIndicator = new BackgroundableProcessIndicator(task);
ProgressManagerImpl.runProcessWithProgressAsynchronously(task, mySearchForTestIndicator);
}
@Override
public void processWillTerminate(ProcessEvent event, boolean willBeDestroyed) {
final TestNGResults resultsView = console.getResultsView();
if (resultsView != null) {
resultsView.finish();
}
}
private int myInsertIndex = 0;
@Override
public void onTextAvailable(final ProcessEvent event, final Key outputType) {
final TestProxy currentTest = console.getCurrentTest();
final String text = event.getText();
final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType);
final Printable printable = new Printable() {
public void printOn(final Printer printer) {
printer.print(text, consoleViewType);
}
};
if (currentTest != null) {
currentTest.addLast(printable);
}
else {
unboundOutputRoot.insert(printable, myInsertIndex);
}
myInsertIndex++;
}
});
console.attachToProcess(processHandler);
RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(console);
rerunFailedTestsAction.init(console.getProperties(), getEnvironment());
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
public TestFrameworkRunningModel get() {
return console.getResultsView();
}
});
final DefaultExecutionResult result = new DefaultExecutionResult(console, processHandler);
result.setRestartActions(rerunFailedTestsAction);
return result;
}
@Override
protected JavaParameters createJavaParameters() throws ExecutionException {
final Project project = config.getProject();
final JavaParameters javaParameters = new JavaParameters();
javaParameters.setupEnvs(config.getPersistantData().getEnvs(), config.getPersistantData().PASS_PARENT_ENVS);
javaParameters.setMainClass("org.testng.RemoteTestNGStarter");
javaParameters.setWorkingDirectory(config.getWorkingDirectory());
javaParameters.getClassPath().add(PathUtil.getJarPathForClass(RemoteTestNGStarter.class));
//the next few lines are awkward for a reason, using compareTo for some reason causes a JVM class verification error!
Module module = config.getConfigurationModule().getModule();
LanguageLevel effectiveLanguageLevel = module == null
? LanguageLevelProjectExtension.getInstance(project).getLanguageLevel()
: LanguageLevelUtil.getEffectiveLanguageLevel(module);
final boolean is15 = effectiveLanguageLevel != LanguageLevel.JDK_1_4 && effectiveLanguageLevel != LanguageLevel.JDK_1_3;
LOG.info("Language level is " + effectiveLanguageLevel.toString());
LOG.info("is15 is " + is15);
final String pathToBundledJar = PathUtil.getJarPathForClass(AfterClass.class);
// Configure rest of jars
JavaParametersUtil.configureConfiguration(javaParameters, config);
Sdk jdk = module == null ? ProjectRootManager.getInstance(project).getProjectSdk() : ModuleRootManager.getInstance(module).getSdk();
javaParameters.setJdk(jdk);
final Object[] patchers = Extensions.getExtensions(ExtensionPoints.JUNIT_PATCHER);
for (Object patcher : patchers) {
((JUnitPatcher)patcher).patchJavaParameters(module, javaParameters);
}
JavaSdkUtil.addRtJar(javaParameters.getClassPath());
// Append coverage parameters if appropriate
for (RunConfigurationExtension ext : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
ext.updateJavaParameters(config, javaParameters, getRunnerSettings());
}
LOG.info("Test scope is: " + config.getPersistantData().getScope());
if (config.getPersistantData().getScope() == TestSearchScope.WHOLE_PROJECT) {
LOG.info("Configuring for whole project");
JavaParametersUtil.configureProject(config.getProject(), javaParameters, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
config.ALTERNATIVE_JRE_PATH_ENABLED ? config.ALTERNATIVE_JRE_PATH : null);
}
else {
LOG.info("Configuring for module:" + config.getConfigurationModule().getModuleName());
JavaParametersUtil.configureModule(config.getConfigurationModule(), javaParameters, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
config.ALTERNATIVE_JRE_PATH_ENABLED ? config.ALTERNATIVE_JRE_PATH : null);
}
javaParameters.getClassPath().add(pathToBundledJar);
try {
port = NetUtils.findAvailableSocketPort();
}
catch (IOException e) {
throw new ExecutionException("Unable to bind to port " + port, e);
}
final TestData data = config.getPersistantData();
javaParameters.getProgramParametersList().add(supportSerializationProtocol(config) ? RemoteArgs.PORT : CommandLineArgs.PORT, String.valueOf(port));
if (data.getOutputDirectory() != null && !"".equals(data.getOutputDirectory())) {
javaParameters.getProgramParametersList().add(CommandLineArgs.OUTPUT_DIRECTORY, data.getOutputDirectory());
}
javaParameters.getProgramParametersList().add(CommandLineArgs.USE_DEFAULT_LISTENERS, String.valueOf(data.USE_DEFAULT_REPORTERS));
@NonNls final StringBuilder buf = new StringBuilder();
if (data.TEST_LISTENERS != null && !data.TEST_LISTENERS.isEmpty()) {
buf.append(StringUtil.join(data.TEST_LISTENERS, ";"));
}
for (Object o : Extensions.getExtensions(IDEATestNGListener.EP_NAME)) {
boolean enabled = true;
for (RunConfigurationExtension extension : Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
if (extension.isListenerDisabled(config, o, getRunnerSettings())) {
enabled = false;
break;
}
}
if (enabled) {
if (buf.length() > 0) buf.append(";");
buf.append(o.getClass().getName());
javaParameters.getClassPath().add(PathUtil.getJarPathForClass(o.getClass()));
}
}
if (buf.length() > 0) javaParameters.getProgramParametersList().add(CommandLineArgs.LISTENER, buf.toString());
/* // Always include the source paths - just makes things easier :)
VirtualFile[] sources;
if ((data.getScope() == TestSearchScope.WHOLE_PROJECT && TestType.PACKAGE.getType().equals(data.TEST_OBJECT)) || module == null) {
sources = ProjectRootManager.getInstance(project).getContentSourceRoots();
}
else {
sources = ModuleRootManager.getInstance(module).getSourceRoots();
}
if (sources.length > 0) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < sources.length; i++) {
VirtualFile source = sources[i];
sb.append(source.getPath());
if (i < sources.length - 1) {
sb.append(';');
}
}
javaParameters.getProgramParametersList().add(TestNGCommandLineArgs.SRC_COMMAND_OPT, sb.toString());
}*/
try {
myServerSocket = new ServerSocket(0, 0, InetAddress.getByName("127.0.0.1"));
javaParameters.getProgramParametersList().add("-socket" + myServerSocket.getLocalPort());
myTempFile = FileUtil.createTempFile("idea_testng", ".tmp");
myTempFile.deleteOnExit();
javaParameters.getProgramParametersList().add("-temp", myTempFile.getAbsolutePath());
}
catch (IOException e) {
LOG.error(e);
}
// Configure for debugging
if (runnerSettings.getData() instanceof DebuggingRunnerData) {
ParametersList params = javaParameters.getVMParametersList();
String hostname = "localhost";
try {
hostname = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e) {
}
params.add("-Xdebug");
params.add("-Xrunjdwp:transport=dt_socket,address=" + hostname + ':' + debugPort + ",suspend=y,server=n");
// params.add(debugPort);
}
return javaParameters;
}
protected SearchingForTestsTask createSearchingForTestsTask(ServerSocket serverSocket,
final TestNGConfiguration config,
final File tempFile) {
return new SearchingForTestsTask(serverSocket, config, tempFile, client);
}
public static boolean supportSerializationProtocol(TestNGConfiguration config) {
final Project project = config.getProject();
final GlobalSearchScope scopeToDetermineTestngIn;
if (config.getPersistantData().getScope() == TestSearchScope.WHOLE_PROJECT) {
scopeToDetermineTestngIn = GlobalSearchScope.allScope(project);
}
else {
scopeToDetermineTestngIn = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(config.getConfigurationModule().getModule());
}
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiClass aClass = facade.findClass(SerializedMessageSender.class.getName(), scopeToDetermineTestngIn);
if (aClass == null) return false;
final PsiClass[] starters = facade.findClasses(RemoteTestNG.class.getName(), scopeToDetermineTestngIn);
for (PsiClass starter : starters) {
if (starter.findFieldByName("m_serPort", false) == null) {
LOG.info("Multiple TestNG versions found");
return false;
}
}
return Registry.is("testng.serialized.protocol.enabled") && !TestNGVersionChecker.isVersionIncompatible(project, scopeToDetermineTestngIn);
}
}
@@ -10,6 +10,7 @@ import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.ComponentContainer;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
@@ -18,7 +19,6 @@ import com.theoryinpractice.testng.configuration.TestNGConfiguration;
import com.theoryinpractice.testng.configuration.TestNGRunnableState;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.io.File;
import java.net.ServerSocket;
import java.util.ArrayList;
@@ -27,8 +27,9 @@ import java.util.List;
import java.util.Map;
public class RerunFailedTestsAction extends AbstractRerunFailedTestsAction {
public RerunFailedTestsAction(JComponent parent) {
super(parent);
public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
super(componentContainer);
}
@Override