notifications about tests passed/finished in SM runner. Balloon will be shown only...
[fedora-idea.git] / platform / smRunner / src / com / intellij / execution / testframework / sm / runner / GeneralToSMTRunnerEventsConvertor.java
blob61664dff66f337cb479212e479e6b2664e1f240a
1 package com.intellij.execution.testframework.sm.runner;
3 import com.intellij.execution.process.ProcessOutputTypes;
4 import com.intellij.execution.testframework.AbstractTestProxy;
5 import com.intellij.execution.testframework.sm.SMRunnerUtil;
6 import com.intellij.openapi.application.Application;
7 import com.intellij.openapi.application.ApplicationManager;
8 import com.intellij.openapi.diagnostic.Logger;
9 import com.intellij.openapi.util.Key;
10 import org.jetbrains.annotations.NotNull;
11 import org.jetbrains.annotations.Nullable;
12 import org.jetbrains.annotations.TestOnly;
14 import java.util.*;
16 /**
17 * @author: Roman Chernyatchik
19 * This class fires events to RTestUnitEventsListener in EventDispatch thread
21 public class GeneralToSMTRunnerEventsConvertor implements GeneralTestEventsProcessor {
22 private static final Logger LOG = Logger.getInstance(GeneralToSMTRunnerEventsConvertor.class.getName());
24 private final Map<String, SMTestProxy> myRunningTestsFullNameToProxy = new HashMap<String, SMTestProxy>();
26 private final Set<AbstractTestProxy> myFailedTestsSet = new HashSet<AbstractTestProxy>();
28 private final TestSuiteStack mySuitesStack = new TestSuiteStack();
29 private final List<SMTRunnerEventsListener> myEventsListeners = new ArrayList<SMTRunnerEventsListener>();
30 private final SMTestProxy myTestsRootNode;
31 private boolean myIsTestingFinished;
33 public GeneralToSMTRunnerEventsConvertor(@NotNull final SMTestProxy testsRootNode) {
34 myTestsRootNode = testsRootNode;
37 public void addEventsListener(final SMTRunnerEventsListener listener) {
38 myEventsListeners.add(listener);
41 public void onStartTesting() {
42 SMRunnerUtil.addToInvokeLater(new Runnable() {
43 public void run() {
44 mySuitesStack.pushSuite(myTestsRootNode);
45 myTestsRootNode.setStarted();
47 //fire
48 fireOnTestingStarted();
50 });
53 public void onFinishTesting() {
54 SMRunnerUtil.addToInvokeLater(new Runnable() {
55 public void run() {
56 if (myIsTestingFinished) {
57 // has been already invoked!
58 return;
60 myIsTestingFinished = true;
62 // We don't know whether process was destroyed by user
63 // or it finished after all tests have been run
64 // Lets assume, if at finish all suites except root suite are passed
65 // then all is ok otherwise process was terminated by user
66 if (!myTestsRootNode.equals(mySuitesStack.getCurrentSuite())) {
67 myTestsRootNode.setTerminated();
68 myRunningTestsFullNameToProxy.clear();
70 mySuitesStack.clear();
71 myTestsRootNode.setFinished();
74 //fire events
75 fireOnTestingFinished();
77 });
80 public void onTestStarted(final String testName, final String locationUrl) {
81 SMRunnerUtil.addToInvokeLater(new Runnable() {
82 public void run() {
83 final String fullName = getFullTestName(testName);
85 if (myRunningTestsFullNameToProxy.containsKey(fullName)) {
86 //Dublicated event
87 LOG.warn("Test [" + fullName + "] has been already started");
88 return;
91 final SMTestProxy parentSuite = getCurrentSuite();
93 // creates test
94 final SMTestProxy testProxy = new SMTestProxy(testName, false, locationUrl);
95 parentSuite.addChild(testProxy);
96 // adds to running tests map
97 myRunningTestsFullNameToProxy.put(fullName, testProxy);
99 //Progress started
100 testProxy.setStarted();
102 //fire events
103 fireOnTestStarted(testProxy);
108 public void onSuiteStarted(final String suiteName, final String locationUrl) {
109 SMRunnerUtil.addToInvokeLater(new Runnable() {
110 public void run() {
111 final SMTestProxy parentSuite = getCurrentSuite();
112 //new suite
113 final SMTestProxy newSuite = new SMTestProxy(suiteName, true, locationUrl);
114 parentSuite.addChild(newSuite);
116 mySuitesStack.pushSuite(newSuite);
118 //Progress started
119 newSuite.setStarted();
121 //fire event
122 fireOnSuiteStarted(newSuite);
127 public void onTestFinished(final String testName, final int duration) {
128 SMRunnerUtil.addToInvokeLater(new Runnable() {
129 public void run() {
130 final String fullTestName = getFullTestName(testName);
131 final SMTestProxy testProxy = getProxyByFullTestName(fullTestName);
132 if (testProxy == null) {
133 LOG.warn("Test wasn't started! TestFinished event: name = {" + testName + "}. " +
134 cannotFindFullTestNameMsg(fullTestName));
135 return;
138 testProxy.setDuration(duration);
139 testProxy.setFinished();
140 myRunningTestsFullNameToProxy.remove(fullTestName);
142 //fire events
143 fireOnTestFinished(testProxy);
148 public void onSuiteFinished(final String suiteName) {
149 SMRunnerUtil.addToInvokeLater(new Runnable() {
150 public void run() {
151 final SMTestProxy mySuite = mySuitesStack.popSuite(suiteName);
152 mySuite.setFinished();
154 //fire events
155 fireOnSuiteFinished(mySuite);
160 public void onUncapturedOutput(final String text, final Key outputType) {
161 SMRunnerUtil.addToInvokeLater(new Runnable() {
162 public void run() {
163 //if we can locate test - we will send outout to it, otherwise to current test suite
164 final SMTestProxy currentProxy;
165 if (myRunningTestsFullNameToProxy.size() == 1) {
166 //current test
167 currentProxy = myRunningTestsFullNameToProxy.values().iterator().next();
168 } else {
169 //current suite
171 // ProcessHandler can fire output available event before processStarted event
172 currentProxy = mySuitesStack.isEmpty() ? myTestsRootNode : getCurrentSuite();
175 if (ProcessOutputTypes.STDERR.equals(outputType)) {
176 currentProxy.addStdErr(text);
177 } else if (ProcessOutputTypes.SYSTEM.equals(outputType)) {
178 currentProxy.addSystemOutput(text);
179 } else {
180 currentProxy.addStdOutput(text, outputType);
186 public void onTestFailure(final String testName,
187 final String localizedMessage, final String stackTrace,
188 final boolean isTestError) {
189 SMRunnerUtil.addToInvokeLater(new Runnable() {
190 public void run() {
191 final String fullTestName = getFullTestName(testName);
192 final SMTestProxy testProxy = getProxyByFullTestName(fullTestName);
193 if (testProxy == null) {
194 LOG.warn("Test wasn't started! TestFailure event: name = {" + testName + "}" +
195 ", message = {" + localizedMessage + "}" +
196 ", stackTrace = {" + stackTrace + "}. " +
197 cannotFindFullTestNameMsg(fullTestName));
198 return;
200 // if wasn't processed
201 if (myFailedTestsSet.contains(testProxy)) {
202 // dublicate message
203 LOG.warn("Duplicate failure for test [" + fullTestName + "]: msg = " + localizedMessage + ", stacktrace = " + stackTrace);
204 return;
207 testProxy.setTestFailed(localizedMessage, stackTrace, isTestError);
210 myFailedTestsSet.add(testProxy);
212 // fire event
213 fireOnTestFailed(testProxy);
218 public void onTestIgnored(final String testName, final String ignoreComment,
219 @Nullable final String stackTrace) {
220 SMRunnerUtil.addToInvokeLater(new Runnable() {
221 public void run() {
222 final String fullTestName = getFullTestName(testName);
223 final SMTestProxy testProxy = getProxyByFullTestName(fullTestName);
224 if (testProxy == null) {
225 LOG.warn("Test wasn't started! " +
226 "TestIgnored event: name = {" + testName + "}, " +
227 "message = {" + ignoreComment + "}. " +
228 cannotFindFullTestNameMsg(fullTestName));
229 return;
232 testProxy.setTestIgnored(ignoreComment, stackTrace);
234 // fire event
235 fireOnTestIgnored(testProxy);
240 public void onTestOutput(final String testName,
241 final String text, final boolean stdOut) {
242 SMRunnerUtil.addToInvokeLater(new Runnable() {
243 public void run() {
244 final String fullTestName = getFullTestName(testName);
245 final SMTestProxy testProxy = getProxyByFullTestName(fullTestName);
246 if (testProxy == null) {
247 LOG.warn("Test wasn't started! TestOutput event: name = {" + testName + "}, " +
248 "isStdOut = " + stdOut + ", " +
249 "text = {" + text + "}. " +
250 cannotFindFullTestNameMsg(fullTestName));
251 return;
254 if (stdOut) {
255 testProxy.addStdOutput(text, ProcessOutputTypes.STDOUT);
256 } else {
257 testProxy.addStdErr(text);
263 public void onTestsCountInSuite(final int count) {
264 SMRunnerUtil.addToInvokeLater(new Runnable() {
265 public void run() {
266 fireOnTestsCountInSuite(count);
271 @NotNull
272 protected final SMTestProxy getCurrentSuite() {
273 final SMTestProxy currentSuite = mySuitesStack.getCurrentSuite();
275 if (currentSuite != null) {
276 return currentSuite;
279 // current suite shouldn't be null otherwise test runner isn't correct
280 // or may be we are in debug mode
281 LOG.warn("Current suite is undefined. Root suite will be used.");
282 return myTestsRootNode;
286 protected String getFullTestName(final String testName) {
287 // Test name should be unique
288 return testName;
291 protected int getRunningTestsQuantity() {
292 return myRunningTestsFullNameToProxy.size();
295 protected Set<AbstractTestProxy> getFailedTestsSet() {
296 return Collections.unmodifiableSet(myFailedTestsSet);
299 @Nullable
300 protected SMTestProxy getProxyByFullTestName(final String fullTestName) {
301 return myRunningTestsFullNameToProxy.get(fullTestName);
304 @TestOnly
305 protected void clearInternalSuitesStack() {
306 mySuitesStack.clear();
309 private String cannotFindFullTestNameMsg(String fullTestName) {
310 return "Cant find running test for ["
311 + fullTestName
312 + "]. Current running tests: {"
313 + dumpRunningTestsNames() + "}";
316 private StringBuilder dumpRunningTestsNames() {
317 final Set<String> names = myRunningTestsFullNameToProxy.keySet();
318 final StringBuilder namesDump = new StringBuilder();
319 for (String name : names) {
320 namesDump.append('[').append(name).append(']').append(',');
322 return namesDump;
325 private void fireOnTestingStarted() {
326 for (SMTRunnerEventsListener listener : myEventsListeners) {
327 listener.onTestingStarted(myTestsRootNode);
331 private void fireOnTestingFinished() {
332 for (SMTRunnerEventsListener listener : myEventsListeners) {
333 listener.onTestingFinished(myTestsRootNode);
337 private void fireOnTestsCountInSuite(final int count) {
338 for (SMTRunnerEventsListener listener : myEventsListeners) {
339 listener.onTestsCountInSuite(count);
344 private void fireOnTestStarted(final SMTestProxy test) {
345 for (SMTRunnerEventsListener listener : myEventsListeners) {
346 listener.onTestStarted(test);
350 private void fireOnTestFinished(final SMTestProxy test) {
351 for (SMTRunnerEventsListener listener : myEventsListeners) {
352 listener.onTestFinished(test);
356 private void fireOnTestFailed(final SMTestProxy test) {
357 for (SMTRunnerEventsListener listener : myEventsListeners) {
358 listener.onTestFailed(test);
362 private void fireOnTestIgnored(final SMTestProxy test) {
363 for (SMTRunnerEventsListener listener : myEventsListeners) {
364 listener.onTestIgnored(test);
368 private void fireOnSuiteStarted(final SMTestProxy suite) {
369 for (SMTRunnerEventsListener listener : myEventsListeners) {
370 listener.onSuiteStarted(suite);
374 private void fireOnSuiteFinished(final SMTestProxy suite) {
375 for (SMTRunnerEventsListener listener : myEventsListeners) {
376 listener.onSuiteFinished(suite);
381 * Remove listeners, etc
383 public void dispose() {
384 SMRunnerUtil.addToInvokeLater(new Runnable() {
385 public void run() {
386 myEventsListeners.clear();
388 if (!myRunningTestsFullNameToProxy.isEmpty()) {
389 final Application application = ApplicationManager.getApplication();
390 if (!application.isHeadlessEnvironment() && !application.isUnitTestMode()) {
391 LOG.warn("Not all events were processed! " + dumpRunningTestsNames());
394 myRunningTestsFullNameToProxy.clear();
395 mySuitesStack.clear();