2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.execution.testframework.autotest;
18 import com.intellij.execution.DelayedDocumentWatcher;
19 import com.intellij.execution.ExecutionManager;
20 import com.intellij.execution.process.ProcessAdapter;
21 import com.intellij.execution.process.ProcessEvent;
22 import com.intellij.execution.process.ProcessHandler;
23 import com.intellij.execution.process.ProcessListener;
24 import com.intellij.execution.runners.ExecutionEnvironment;
25 import com.intellij.execution.runners.ExecutionUtil;
26 import com.intellij.execution.ui.RunContentDescriptor;
27 import com.intellij.execution.ui.RunContentManager;
28 import com.intellij.ide.DataManager;
29 import com.intellij.ide.scratch.ScratchFileService;
30 import com.intellij.ide.util.PropertiesComponent;
31 import com.intellij.openapi.actionSystem.LangDataKeys;
32 import com.intellij.openapi.application.ApplicationManager;
33 import com.intellij.openapi.application.ModalityState;
34 import com.intellij.openapi.components.ServiceManager;
35 import com.intellij.openapi.fileEditor.FileEditorManager;
36 import com.intellij.openapi.project.Project;
37 import com.intellij.openapi.util.Condition;
38 import com.intellij.openapi.util.Key;
39 import com.intellij.openapi.vfs.VirtualFile;
40 import com.intellij.ui.content.Content;
41 import com.intellij.util.Consumer;
42 import org.jetbrains.annotations.NotNull;
43 import org.jetbrains.annotations.Nullable;
50 public class AutoTestManager {
51 private static final String AUTO_TEST_MANAGER_DELAY = "auto.test.manager.delay";
52 private static final int AUTO_TEST_MANAGER_DELAY_DEFAULT = 3000;
54 private static final Key<ProcessListener> ON_TERMINATION_RESTARTER_KEY = Key.create("auto.test.manager.on.termination.restarter");
55 private static final Key<ExecutionEnvironment> EXECUTION_ENVIRONMENT_KEY = Key.create("auto.test.manager.execution.environment");
57 private final Project myProject;
58 private int myDelayMillis;
59 private DelayedDocumentWatcher myDocumentWatcher;
62 public static AutoTestManager getInstance(Project project) {
63 return ServiceManager.getService(project, AutoTestManager.class);
66 public AutoTestManager(@NotNull Project project) {
68 myDelayMillis = PropertiesComponent.getInstance(project).getInt(AUTO_TEST_MANAGER_DELAY, AUTO_TEST_MANAGER_DELAY_DEFAULT);
69 myDocumentWatcher = createWatcher();
73 private DelayedDocumentWatcher createWatcher() {
74 return new DelayedDocumentWatcher(myProject, myDelayMillis, new Consumer<Integer>() {
76 public void consume(Integer modificationStamp) {
77 restartAllAutoTests(modificationStamp);
79 }, new Condition<VirtualFile>() {
81 public boolean value(VirtualFile file) {
82 if (ScratchFileService.getInstance().getRootType(file) != null) {
85 // Vladimir.Krivosheev - I don't know, why AutoTestManager checks it, but old behavior is preserved
86 return FileEditorManager.getInstance(myProject).isFileOpen(file);
91 public void setAutoTestEnabled(@NotNull RunContentDescriptor descriptor, @NotNull ExecutionEnvironment environment, boolean enabled) {
92 Content content = descriptor.getAttachedContent();
93 if (content != null) {
95 EXECUTION_ENVIRONMENT_KEY.set(content, environment);
96 myDocumentWatcher.activate();
99 EXECUTION_ENVIRONMENT_KEY.set(content, null);
100 if (!hasEnabledAutoTests()) {
101 myDocumentWatcher.deactivate();
103 ProcessHandler processHandler = descriptor.getProcessHandler();
104 if (processHandler != null) {
105 clearRestarterListener(processHandler);
111 private boolean hasEnabledAutoTests() {
112 RunContentManager contentManager = ExecutionManager.getInstance(myProject).getContentManager();
113 for (RunContentDescriptor descriptor : contentManager.getAllDescriptors()) {
114 if (isAutoTestEnabledForDescriptor(descriptor)) {
121 public boolean isAutoTestEnabled(@NotNull RunContentDescriptor descriptor) {
122 return isAutoTestEnabledForDescriptor(descriptor);
125 private static boolean isAutoTestEnabledForDescriptor(@NotNull RunContentDescriptor descriptor) {
126 Content content = descriptor.getAttachedContent();
127 if (content != null) {
128 ExecutionEnvironment watched = EXECUTION_ENVIRONMENT_KEY.get(content);
129 if (watched != null) {
130 ExecutionEnvironment current = getCurrentEnvironment(content);
131 boolean result = current != null && equals(current, watched);
133 // let GC do its work
134 EXECUTION_ENVIRONMENT_KEY.set(content, null);
143 private static ExecutionEnvironment getCurrentEnvironment(@NotNull Content content) {
144 JComponent component = content.getComponent();
145 if (component == null) {
148 return LangDataKeys.EXECUTION_ENVIRONMENT.getData(DataManager.getInstance().getDataContext(component));
151 private static boolean equals(@NotNull ExecutionEnvironment env1, @NotNull ExecutionEnvironment env2) {
152 return env1.getRunProfile() == env2.getRunProfile() &&
153 env1.getRunner() == env2.getRunner() &&
154 env1.getExecutor() == env2.getExecutor() &&
155 env1.getExecutionTarget() == env2.getExecutionTarget();
158 private static void clearRestarterListener(@NotNull ProcessHandler processHandler) {
159 ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler, null);
160 if (restarterListener != null) {
161 processHandler.removeProcessListener(restarterListener);
162 ON_TERMINATION_RESTARTER_KEY.set(processHandler, null);
166 private void restartAllAutoTests(int modificationStamp) {
167 RunContentManager contentManager = ExecutionManager.getInstance(myProject).getContentManager();
168 boolean active = false;
169 for (RunContentDescriptor descriptor : contentManager.getAllDescriptors()) {
170 if (isAutoTestEnabledForDescriptor(descriptor)) {
171 restartAutoTest(descriptor, modificationStamp, myDocumentWatcher);
176 myDocumentWatcher.deactivate();
180 private static void restartAutoTest(@NotNull RunContentDescriptor descriptor,
181 int modificationStamp,
182 @NotNull DelayedDocumentWatcher documentWatcher) {
183 ProcessHandler processHandler = descriptor.getProcessHandler();
184 if (processHandler != null && !processHandler.isProcessTerminated()) {
185 scheduleRestartOnTermination(descriptor, processHandler, modificationStamp, documentWatcher);
192 private static void scheduleRestartOnTermination(@NotNull final RunContentDescriptor descriptor,
193 @NotNull final ProcessHandler processHandler,
194 final int modificationStamp,
195 @NotNull final DelayedDocumentWatcher documentWatcher) {
196 ProcessListener restarterListener = ON_TERMINATION_RESTARTER_KEY.get(processHandler);
197 if (restarterListener != null) {
198 clearRestarterListener(processHandler);
200 restarterListener = new ProcessAdapter() {
202 public void processTerminated(ProcessEvent event) {
203 clearRestarterListener(processHandler);
204 ApplicationManager.getApplication().invokeLater(new Runnable() {
207 if (isAutoTestEnabledForDescriptor(descriptor) && documentWatcher.isUpToDate(modificationStamp)) {
211 }, ModalityState.any());
214 ON_TERMINATION_RESTARTER_KEY.set(processHandler, restarterListener);
215 processHandler.addProcessListener(restarterListener);
218 private static void restart(@NotNull RunContentDescriptor descriptor) {
219 descriptor.setActivateToolWindowWhenAdded(false);
220 descriptor.setReuseToolWindowActivation(true);
221 ExecutionUtil.restart(descriptor);
225 return myDelayMillis;
228 void setDelay(int delay) {
229 myDelayMillis = delay;
230 myDocumentWatcher.deactivate();
231 myDocumentWatcher = createWatcher();
232 if (hasEnabledAutoTests()) {
233 myDocumentWatcher.activate();
235 PropertiesComponent.getInstance(myProject).setValue(AUTO_TEST_MANAGER_DELAY, myDelayMillis, AUTO_TEST_MANAGER_DELAY_DEFAULT);