auto test manager: rerun on process termination if changes were made during test run

This commit is contained in:
Sergey Simonchik
2015-01-27 17:24:37 +03:00
parent d8a3fee2ff
commit b646e6022f
2 changed files with 74 additions and 22 deletions
@@ -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<Set<VirtualFile>> myConsumer;
private final Consumer<Integer> myModificationStampConsumer;
private final Condition<VirtualFile> myChangedFileFilter;
private final MyDocumentAdapter myListener;
private final Runnable myAlarmRunnable;
@@ -63,16 +62,16 @@ public class DelayedDocumentWatcher {
private final Set<VirtualFile> myChangedFiles = new THashSet<VirtualFile>();
private boolean myDocumentSavingInProgress = false;
private MessageBusConnection myConnection;
private int myEventCount = 0;
private int myModificationStamp = 0;
public DelayedDocumentWatcher(@NotNull Project project,
int delayMillis,
@NotNull Consumer<Set<VirtualFile>> consumer,
@NotNull Consumer<Integer> modificationStampConsumer,
@Nullable Condition<VirtualFile> 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<VirtualFile> copy = ImmutableSet.copyOf(myChangedFiles);
asyncCheckErrors(copy, new Consumer<Boolean>() {
final int oldModificationStamp = myModificationStamp;
asyncCheckErrors(myChangedFiles, new Consumer<Boolean>() {
@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);
}
}
@@ -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<Boolean> AUTOTESTABLE = Key.create("auto.test.manager.supported");
public static final String AUTO_TEST_MANAGER_DELAY = "auto.test.manager.delay";
private static final Key<ProcessListener> 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<Set<VirtualFile>>() {
return new DelayedDocumentWatcher(myProject, myDelay, new Consumer<Integer>() {
@Override
public void consume(Set<VirtualFile> files) {
public void consume(Integer modificationStamp) {
for (Content content : myEnabledDescriptors) {
runAutoTest(content);
runAutoTest(content, modificationStamp, myDocumentWatcher);
}
}
}, new Condition<VirtualFile>() {
@@ -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;
}