From b8bed5d119acc4c533afe67aaee0b9a89244e963 Mon Sep 17 00:00:00 2001 From: Vassiliy Kudryashov Date: Mon, 6 Aug 2012 18:35:04 +0400 Subject: [PATCH] Memory leak in AbstractRerunFailedTestsAction --- .../AbstractRerunFailedTestsAction.java | 23 +- .../intellij/execution/junit/TestObject.java | 890 +++++++++--------- .../ui/actions/RerunFailedTestsAction.java | 7 +- .../configuration/TestNGRunnableState.java | 780 +++++++-------- .../ui/actions/RerunFailedTestsAction.java | 7 +- 5 files changed, 856 insertions(+), 851 deletions(-) diff --git a/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java b/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java index 51f2c7e41a77..40a91499fd2a 100644 --- a/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java +++ b/java/execution/impl/src/com/intellij/execution/actions/AbstractRerunFailedTestsAction.java @@ -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 registry = new ArrayList(); +public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate, Disposable { + private static List registry = new CopyOnWriteArrayList(); private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction"); private TestFrameworkRunningModel myModel; private Getter 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, diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 0e692ad1f4ce..c3a1058f0df6 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -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() { - @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.
Please change fork mode to <none> 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 void addClassesListToJavaParameters(Collection elements, Function 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 testNames = new ArrayList(); - 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() { + @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.
Please change fork mode to <none> 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 void addClassesListToJavaParameters(Collection elements, Function 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 testNames = new ArrayList(); + 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; + } +} diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java index b2f086f9122c..836ae9e5ed4e 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java +++ b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java @@ -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 diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index 5917a5563eee..e941dc21f7ad 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -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() { - 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() { + 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); + } +} diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java index 6a2cf15988b7..52fb2bb021f5 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java +++ b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java @@ -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