From b646e6022f45f5d3f5dc4c48e2a8c242d172095b Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Tue, 27 Jan 2015 17:24:37 +0300 Subject: [PATCH] auto test manager: rerun on process termination if changes were made during test run --- .../execution/DelayedDocumentWatcher.java | 25 +++---- .../autotest/AutoTestManager.java | 71 ++++++++++++++++--- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java b/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java index b8e17ea3eded..822a69e3b227 100644 --- a/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java +++ b/platform/platform-impl/src/com/intellij/execution/DelayedDocumentWatcher.java @@ -15,7 +15,6 @@ */ package com.intellij.execution; -import com.google.common.collect.ImmutableSet; import com.intellij.AppTopics; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; @@ -55,7 +54,7 @@ public class DelayedDocumentWatcher { private final Project myProject; private final Alarm myAlarm; private final int myDelayMillis; - private final Consumer> myConsumer; + private final Consumer myModificationStampConsumer; private final Condition myChangedFileFilter; private final MyDocumentAdapter myListener; private final Runnable myAlarmRunnable; @@ -63,16 +62,16 @@ public class DelayedDocumentWatcher { private final Set myChangedFiles = new THashSet(); private boolean myDocumentSavingInProgress = false; private MessageBusConnection myConnection; - private int myEventCount = 0; + private int myModificationStamp = 0; public DelayedDocumentWatcher(@NotNull Project project, int delayMillis, - @NotNull Consumer> consumer, + @NotNull Consumer modificationStampConsumer, @Nullable Condition changedFileFilter) { myProject = project; myAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD, myProject); myDelayMillis = delayMillis; - myConsumer = consumer; + myModificationStampConsumer = modificationStampConsumer; myChangedFileFilter = changedFileFilter; myListener = new MyDocumentAdapter(); myAlarmRunnable = new MyRunnable(); @@ -110,6 +109,10 @@ public class DelayedDocumentWatcher { } } + public boolean isUpToDate(int modificationStamp) { + return myModificationStamp == modificationStamp; + } + private class MyDocumentAdapter extends DocumentAdapter { @Override public void documentChanged(DocumentEvent event) { @@ -136,19 +139,18 @@ public class DelayedDocumentWatcher { myAlarm.cancelRequest(myAlarmRunnable); myAlarm.addRequest(myAlarmRunnable, myDelayMillis); - myEventCount++; + myModificationStamp++; } } private class MyRunnable implements Runnable { @Override public void run() { - final int oldEventCount = myEventCount; - final Set copy = ImmutableSet.copyOf(myChangedFiles); - asyncCheckErrors(copy, new Consumer() { + final int oldModificationStamp = myModificationStamp; + asyncCheckErrors(myChangedFiles, new Consumer() { @Override public void consume(Boolean errorsFound) { - if (myEventCount != oldEventCount) { + if (myModificationStamp != oldModificationStamp) { // 'documentChanged' event was raised during async checking files for errors // Do nothing in that case, this method will be invoked subsequently. return; @@ -159,7 +161,7 @@ public class DelayedDocumentWatcher { return; } myChangedFiles.clear(); - myConsumer.consume(copy); + myModificationStampConsumer.consume(myModificationStamp); } }); } @@ -218,5 +220,4 @@ public class DelayedDocumentWatcher { } return WolfTheProblemSolver.getInstance(myProject).hasSyntaxErrors(file); } - } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java index 14e0cf32ef62..c0993f9449a2 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/autotest/AutoTestManager.java @@ -16,13 +16,18 @@ package com.intellij.execution.testframework.autotest; import com.intellij.execution.DelayedDocumentWatcher; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.process.ProcessListener; import com.intellij.execution.runners.ExecutionUtil; import com.intellij.execution.ui.RunContentDescriptor; import com.intellij.ide.DataManager; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; @@ -32,6 +37,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.content.Content; import com.intellij.util.Consumer; import com.intellij.util.containers.WeakHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collections; @@ -43,6 +50,7 @@ import java.util.Set; public class AutoTestManager { static final Key AUTOTESTABLE = Key.create("auto.test.manager.supported"); public static final String AUTO_TEST_MANAGER_DELAY = "auto.test.manager.delay"; + private static final Key ON_TERMINATION_RESTARTER_KEY = Key.create("auto.test.manager.on.termination.restarter"); private final Project myProject; @@ -63,11 +71,11 @@ public class AutoTestManager { } private DelayedDocumentWatcher createWatcher() { - return new DelayedDocumentWatcher(myProject, myDelay, new Consumer>() { + return new DelayedDocumentWatcher(myProject, myDelay, new Consumer() { @Override - public void consume(Set files) { + public void consume(Integer modificationStamp) { for (Content content : myEnabledDescriptors) { - runAutoTest(content); + runAutoTest(content, modificationStamp, myDocumentWatcher); } } }, new Condition() { @@ -79,13 +87,14 @@ public class AutoTestManager { }); } - public void setAutoTestEnabled(RunContentDescriptor descriptor, boolean enabled) { + public void setAutoTestEnabled(@NotNull RunContentDescriptor descriptor, boolean enabled) { Content content = descriptor.getAttachedContent(); if (enabled) { myEnabledDescriptors.add(content); myDocumentWatcher.activate(); } else { + clearRestarterListener(descriptor.getProcessHandler()); myEnabledDescriptors.remove(content); if (myEnabledDescriptors.isEmpty()) { myDocumentWatcher.deactivate(); @@ -93,11 +102,21 @@ public class AutoTestManager { } } + private static void clearRestarterListener(@Nullable ProcessHandler processHandler) { + if (processHandler != null) { + ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler, null); + if (restarterListener != null) { + processHandler.removeProcessListener(restarterListener); + ON_TERMINATION_RESTARTER_KEY.set(processHandler, null); + } + } + } + public boolean isAutoTestEnabled(RunContentDescriptor descriptor) { return myEnabledDescriptors.contains(descriptor.getAttachedContent()); } - private static void runAutoTest(Content content) { + private static void runAutoTest(@NotNull Content content, int modificationStamp, @NotNull DelayedDocumentWatcher documentWatcher) { JComponent component = content.getComponent(); if (component != null) { DataContext dataContext = DataManager.getInstance().getDataContext(component); @@ -105,16 +124,48 @@ public class AutoTestManager { if (descriptor != null) { ProcessHandler processHandler = descriptor.getProcessHandler(); if (processHandler != null && !processHandler.isProcessTerminated()) { - return; + scheduleRestartOnTermination(descriptor, content, processHandler, modificationStamp, documentWatcher); + } + else { + restart(descriptor, content); } - - descriptor.setActivateToolWindowWhenAdded(false); - descriptor.setReuseToolWindowActivation(true); - ExecutionUtil.restart(content); } } } + private static void scheduleRestartOnTermination(@NotNull final RunContentDescriptor descriptor, + @NotNull final Content content, + @NotNull final ProcessHandler processHandler, + final int modificationStamp, + @NotNull final DelayedDocumentWatcher documentWatcher) { + ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler); + if (restarterListener != null) { + return; + } + restarterListener = new ProcessAdapter() { + @Override + public void processTerminated(ProcessEvent event) { + clearRestarterListener(processHandler); + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + if (documentWatcher.isUpToDate(modificationStamp)) { + restart(descriptor, content); + } + } + }, ModalityState.any()); + } + }; + ON_TERMINATION_RESTARTER_KEY.set(processHandler, restarterListener); + processHandler.addProcessListener(restarterListener); + } + + private static void restart(@NotNull RunContentDescriptor descriptor, @NotNull Content content) { + descriptor.setActivateToolWindowWhenAdded(false); + descriptor.setReuseToolWindowActivation(true); + ExecutionUtil.restart(content); + } + int getDelay() { return myDelay; }