KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > junit > ui > RemoteTestRunnerClient


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Julien Ruaux: jruaux@octo.com
11  * Vincent Massol: vmassol@octo.com
12  *******************************************************************************/

13 package org.eclipse.jdt.internal.junit.ui;
14
15 import java.io.BufferedReader JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.InputStreamReader JavaDoc;
18 import java.io.OutputStreamWriter JavaDoc;
19 import java.io.PrintWriter JavaDoc;
20 import java.io.UnsupportedEncodingException JavaDoc;
21 import java.net.ServerSocket JavaDoc;
22 import java.net.Socket JavaDoc;
23 import java.net.SocketException JavaDoc;
24
25 import org.eclipse.core.runtime.ISafeRunnable;
26 import org.eclipse.core.runtime.Platform;
27
28 import org.eclipse.jdt.junit.ITestRunListener;
29
30 import org.eclipse.jdt.internal.junit.runner.MessageIds;
31
32 /**
33  * The client side of the RemoteTestRunner. Handles the
34  * marshaling of the different messages.
35  */

36 public class RemoteTestRunnerClient {
37     public abstract class ListenerSafeRunnable implements ISafeRunnable {
38         public void handleException(Throwable JavaDoc exception) {
39             JUnitPlugin.log(exception);
40         }
41     }
42     /**
43      * A simple state machine to process requests from the RemoteTestRunner
44      */

45     abstract class ProcessingState {
46         abstract ProcessingState readMessage(String JavaDoc message);
47     }
48     
49     class DefaultProcessingState extends ProcessingState {
50         ProcessingState readMessage(String JavaDoc message) {
51             if (message.startsWith(MessageIds.TRACE_START)) {
52                 fFailedTrace.setLength(0);
53                 return fTraceState;
54             }
55             if (message.startsWith(MessageIds.EXPECTED_START)) {
56                 fExpectedResult.setLength(0);
57                 return fExpectedState;
58             }
59             if (message.startsWith(MessageIds.ACTUAL_START)) {
60                 fActualResult.setLength(0);
61                 return fActualState;
62             }
63             if (message.startsWith(MessageIds.RTRACE_START)) {
64                 fFailedRerunTrace.setLength(0); //$NON-NLS-1$
65
return fRerunState;
66             }
67             String JavaDoc arg= message.substring(MessageIds.MSG_HEADER_LENGTH);
68             if (message.startsWith(MessageIds.TEST_RUN_START)) {
69                 // version < 2 format: count
70
// version >= 2 format: count+" "+version
71
int count= 0;
72                 int v= arg.indexOf(' ');
73                 if (v == -1) {
74                     fVersion= "v1"; //$NON-NLS-1$
75
count= Integer.parseInt(arg);
76                 } else {
77                     fVersion= arg.substring(v+1);
78                     String JavaDoc sc= arg.substring(0, v);
79                     count= Integer.parseInt(sc);
80                 }
81                 notifyTestRunStarted(count);
82                 return this;
83             }
84             if (message.startsWith(MessageIds.TEST_START)) {
85                 notifyTestStarted(arg);
86                 return this;
87             }
88             if (message.startsWith(MessageIds.TEST_END)) {
89                 notifyTestEnded(arg);
90                 return this;
91             }
92             if (message.startsWith(MessageIds.TEST_ERROR)) {
93                 extractFailure(arg, ITestRunListener.STATUS_ERROR);
94                 return this;
95             }
96             if (message.startsWith(MessageIds.TEST_FAILED)) {
97                 extractFailure(arg, ITestRunListener.STATUS_FAILURE);
98                 return this;
99             }
100             if (message.startsWith(MessageIds.TEST_RUN_END)) {
101                 long elapsedTime = Long.parseLong(arg);
102                 testRunEnded(elapsedTime);
103                 return this;
104             }
105             if (message.startsWith(MessageIds.TEST_STOPPED)) {
106                 long elapsedTime = Long.parseLong(arg);
107                 notifyTestRunStopped(elapsedTime);
108                 shutDown();
109                 return this;
110             }
111             if (message.startsWith(MessageIds.TEST_TREE)) {
112                 notifyTestTreeEntry(arg);
113                 return this;
114             }
115             if (message.startsWith(MessageIds.TEST_RERAN)) {
116                 if (hasTestId())
117                     scanReranMessage(arg);
118                 else
119                     scanOldReranMessage(arg);
120                 return this;
121             }
122             return this;
123         }
124     }
125     
126     /**
127      * Base class for states in which messages are appended to an internal
128      * string buffer until an end message is read.
129      */

130     class AppendingProcessingState extends ProcessingState {
131         private final StringBuffer JavaDoc fBuffer;
132         private String JavaDoc fEndString;
133
134         AppendingProcessingState(StringBuffer JavaDoc buffer, String JavaDoc endString) {
135             this.fBuffer= buffer;
136             this.fEndString = endString;
137         }
138         
139         ProcessingState readMessage(String JavaDoc message) {
140             if (message.startsWith(fEndString)) {
141                 entireStringRead();
142                 return fDefaultState;
143             }
144             fBuffer.append(message);
145             fBuffer.append('\n');
146             return this;
147         }
148
149         /**
150          * subclasses can override to do special things when end message is read
151          */

152         void entireStringRead() {
153         }
154     }
155     
156     class TraceProcessingState extends AppendingProcessingState {
157         TraceProcessingState() {
158             super(fFailedTrace, MessageIds.TRACE_END);
159         }
160         
161         void entireStringRead() {
162             notifyTestFailed();
163             fExpectedResult.setLength(0);
164             fActualResult.setLength(0);
165         }
166         
167         ProcessingState readMessage(String JavaDoc message) {
168             if (message.startsWith(MessageIds.TRACE_END)) {
169                 notifyTestFailed();
170                 fFailedTrace.setLength(0);
171                 fActualResult.setLength(0);
172                 fExpectedResult.setLength(0);
173                 return fDefaultState;
174             }
175             fFailedTrace.append(message + '\n');
176             return this;
177         }
178     }
179     
180     /**
181      * The failed trace that is currently reported from the RemoteTestRunner
182      */

183     private final StringBuffer JavaDoc fFailedTrace = new StringBuffer JavaDoc();
184     /**
185      * The expected test result
186      */

187     private final StringBuffer JavaDoc fExpectedResult = new StringBuffer JavaDoc();
188     /**
189      * The actual test result
190      */

191     private final StringBuffer JavaDoc fActualResult = new StringBuffer JavaDoc();
192     /**
193      * The failed trace of a reran test
194      */

195     private final StringBuffer JavaDoc fFailedRerunTrace = new StringBuffer JavaDoc();
196
197     
198     ProcessingState fDefaultState= new DefaultProcessingState();
199     ProcessingState fTraceState= new TraceProcessingState();
200     ProcessingState fExpectedState= new AppendingProcessingState(fExpectedResult, MessageIds.EXPECTED_END);
201     ProcessingState fActualState= new AppendingProcessingState(fActualResult, MessageIds.ACTUAL_END);
202     ProcessingState fRerunState= new AppendingProcessingState(fFailedRerunTrace, MessageIds.RTRACE_END);
203     ProcessingState fCurrentState= fDefaultState;
204     
205     /**
206      * An array of listeners that are informed about test events.
207      */

208     private ITestRunListener[] fListeners;
209
210     /**
211      * The server socket
212      */

213     private ServerSocket JavaDoc fServerSocket;
214     private Socket JavaDoc fSocket;
215     private int fPort= -1;
216     private PrintWriter JavaDoc fWriter;
217     private BufferedReader JavaDoc fBufferedReader;
218     /**
219      * The protocol version
220      */

221     private String JavaDoc fVersion;
222     /**
223      * The failed test that is currently reported from the RemoteTestRunner
224      */

225     private String JavaDoc fFailedTest;
226     /**
227      * The Id of the failed test
228      */

229     private String JavaDoc fFailedTestId;
230     /**
231      * The kind of failure of the test that is currently reported as failed
232      */

233     private int fFailureKind;
234     
235     private boolean fDebug= false;
236     
237     /**
238      * Reads the message stream from the RemoteTestRunner
239      */

240     private class ServerConnection extends Thread JavaDoc {
241         int fServerPort;
242         
243         public ServerConnection(int port) {
244             super("ServerConnection"); //$NON-NLS-1$
245
fServerPort= port;
246         }
247         
248         public void run() {
249             try {
250                 if (fDebug)
251                     System.out.println("Creating server socket "+fServerPort); //$NON-NLS-1$
252
fServerSocket= new ServerSocket JavaDoc(fServerPort);
253                 fSocket= fServerSocket.accept();
254                 try {
255                     fBufferedReader= new BufferedReader JavaDoc(new InputStreamReader JavaDoc(fSocket.getInputStream(), "UTF-8")); //$NON-NLS-1$
256
} catch (UnsupportedEncodingException JavaDoc e) {
257                     fBufferedReader= new BufferedReader JavaDoc(new InputStreamReader JavaDoc(fSocket.getInputStream()));
258                 }
259                 try {
260                     fWriter= new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(fSocket.getOutputStream(), "UTF-8"), true); //$NON-NLS-1$
261
} catch (UnsupportedEncodingException JavaDoc e1) {
262                     fWriter= new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(fSocket.getOutputStream()), true);
263                 }
264                 String JavaDoc message;
265                 while(fBufferedReader != null && (message= readMessage(fBufferedReader)) != null)
266                     receiveMessage(message);
267             } catch (SocketException JavaDoc e) {
268                 notifyTestRunTerminated();
269             } catch (IOException JavaDoc e) {
270                 System.out.println(e);
271                 // fall through
272
}
273             shutDown();
274         }
275     }
276
277     /**
278      * Start listening to a test run. Start a server connection that
279      * the RemoteTestRunner can connect to.
280      */

281     public synchronized void startListening(
282         ITestRunListener[] listeners,
283         int port) {
284         fListeners = listeners;
285         fPort = port;
286         ServerConnection connection = new ServerConnection(port);
287         connection.start();
288     }
289     
290     /**
291      * Requests to stop the remote test run.
292      */

293     public synchronized void stopTest() {
294         if (isRunning()) {
295             fWriter.println(MessageIds.TEST_STOP);
296             fWriter.flush();
297         }
298     }
299
300     private synchronized void shutDown() {
301         if (fDebug)
302             System.out.println("shutdown "+fPort); //$NON-NLS-1$
303

304         if (fWriter != null) {
305             fWriter.close();
306             fWriter= null;
307         }
308         try {
309             if (fBufferedReader != null) {
310                 fBufferedReader.close();
311                 fBufferedReader= null;
312             }
313         } catch(IOException JavaDoc e) {
314         }
315         try {
316             if (fSocket != null) {
317                 fSocket.close();
318                 fSocket= null;
319             }
320         } catch(IOException JavaDoc e) {
321         }
322         try{
323             if (fServerSocket != null) {
324                 fServerSocket.close();
325                 fServerSocket= null;
326             }
327         } catch(IOException JavaDoc e) {
328         }
329     }
330     
331     public boolean isRunning() {
332         return fSocket != null;
333     }
334     
335     private String JavaDoc readMessage(BufferedReader JavaDoc in) throws IOException JavaDoc {
336         return in.readLine();
337     }
338         
339     private void receiveMessage(String JavaDoc message) {
340         fCurrentState= fCurrentState.readMessage(message);
341     }
342
343     private void scanOldReranMessage(String JavaDoc arg) {
344         // OLD V1 format
345
// format: className" "testName" "status
346
// status: FAILURE, ERROR, OK
347
int c= arg.indexOf(" "); //$NON-NLS-1$
348
int t= arg.indexOf(" ", c+1); //$NON-NLS-1$
349
String JavaDoc className= arg.substring(0, c);
350         String JavaDoc testName= arg.substring(c+1, t);
351         String JavaDoc status= arg.substring(t+1);
352         String JavaDoc testId = className+testName;
353         notifyTestReran(testId, className, testName, status);
354     }
355
356     private void scanReranMessage(String JavaDoc arg) {
357         // format: testId" "className" "testName" "status
358
// status: FAILURE, ERROR, OK
359
int i= arg.indexOf(' ');
360         int c= arg.indexOf(' ', i+1); //$NON-NLS-1$
361
int t= arg.indexOf(' ', c+1); //$NON-NLS-1$
362
String JavaDoc testId= arg.substring(0, i);
363         String JavaDoc className= arg.substring(i+1, c);
364         String JavaDoc testName= arg.substring(c+1, t);
365         String JavaDoc status= arg.substring(t+1);
366         notifyTestReran(testId, className, testName, status);
367     }
368     
369     private void notifyTestReran(String JavaDoc testId, String JavaDoc className, String JavaDoc testName, String JavaDoc status) {
370         int statusCode= ITestRunListener.STATUS_OK;
371         if (status.equals("FAILURE")) //$NON-NLS-1$
372
statusCode= ITestRunListener.STATUS_FAILURE;
373         else if (status.equals("ERROR")) //$NON-NLS-1$
374
statusCode= ITestRunListener.STATUS_ERROR;
375                 
376         String JavaDoc trace= ""; //$NON-NLS-1$
377
if (statusCode != ITestRunListener.STATUS_OK)
378             trace = fFailedRerunTrace.toString();
379         // assumption a rerun trace was sent before
380
notifyTestReran(testId, className, testName, statusCode, trace);
381     }
382
383     private void extractFailure(String JavaDoc arg, int status) {
384         String JavaDoc s[]= extractTestId(arg);
385         fFailedTestId= s[0];
386         fFailedTest= s[1];
387         fFailureKind= status;
388     }
389
390     /**
391      * Returns an array with two elements. The first one is the testId, the second one the testName.
392      */

393     String JavaDoc[] extractTestId(String JavaDoc arg) {
394         String JavaDoc[] result= new String JavaDoc[2];
395         if (!hasTestId()) {
396             result[0]= arg; // use the test name as the test Id
397
result[1]= arg;
398             return result;
399         }
400         int i= arg.indexOf(',');
401         result[0]= arg.substring(0, i);
402         result[1]= arg.substring(i+1, arg.length());
403         return result;
404     }
405     
406     private boolean hasTestId() {
407         if (fVersion == null) // TODO fix me
408
return true;
409         return fVersion.equals("v2"); //$NON-NLS-1$
410
}
411
412     private void notifyTestReran(final String JavaDoc testId, final String JavaDoc className, final String JavaDoc testName, final int statusCode, final String JavaDoc trace) {
413         for (int i= 0; i < fListeners.length; i++) {
414             final ITestRunListener listener= fListeners[i];
415             Platform.run(new ListenerSafeRunnable() {
416                 public void run() {
417                     if (listener instanceof ITestRunListener3 )
418                         ((ITestRunListener3) listener).testReran(testId,
419                                 className, testName, statusCode, trace,
420                                 fExpectedResult.toString(), fActualResult.toString());
421                     else
422                         listener.testReran(testId, className, testName, statusCode, trace);
423                 }
424             });
425         }
426     }
427
428     private void notifyTestTreeEntry(final String JavaDoc treeEntry) {
429         for (int i= 0; i < fListeners.length; i++) {
430             if (fListeners[i] instanceof ITestRunListener2) {
431                 ITestRunListener2 listener= (ITestRunListener2)fListeners[i];
432                 if (!hasTestId())
433                     listener.testTreeEntry(fakeTestId(treeEntry));
434                 else
435                     listener.testTreeEntry(treeEntry);
436             }
437         }
438     }
439
440     private String JavaDoc fakeTestId(String JavaDoc treeEntry) {
441         // extract the test name and add it as the testId
442
int index0= treeEntry.indexOf(',');
443         String JavaDoc testName= treeEntry.substring(0, index0).trim();
444         return testName+","+treeEntry; //$NON-NLS-1$
445
}
446
447     private void notifyTestRunStopped(final long elapsedTime) {
448         if (JUnitPlugin.isStopped())
449             return;
450         for (int i= 0; i < fListeners.length; i++) {
451             final ITestRunListener listener= fListeners[i];
452             Platform.run(new ListenerSafeRunnable() {
453                 public void run() {
454                     listener.testRunStopped(elapsedTime);
455                 }
456             });
457         }
458     }
459
460     private void testRunEnded(final long elapsedTime) {
461         if (JUnitPlugin.isStopped())
462             return;
463         for (int i= 0; i < fListeners.length; i++) {
464             final ITestRunListener listener= fListeners[i];
465             Platform.run(new ListenerSafeRunnable() {
466                 public void run() {
467                     listener.testRunEnded(elapsedTime);
468                 }
469             });
470         }
471     }
472
473     private void notifyTestEnded(final String JavaDoc test) {
474         if (JUnitPlugin.isStopped())
475             return;
476         for (int i= 0; i < fListeners.length; i++) {
477             final ITestRunListener listener= fListeners[i];
478             Platform.run(new ListenerSafeRunnable() {
479                 public void run() {
480                     String JavaDoc s[]= extractTestId(test);
481                     listener.testEnded(s[0], s[1]);
482                 }
483             });
484         }
485     }
486
487     private void notifyTestStarted(final String JavaDoc test) {
488         if (JUnitPlugin.isStopped())
489             return;
490         for (int i= 0; i < fListeners.length; i++) {
491             final ITestRunListener listener= fListeners[i];
492             Platform.run(new ListenerSafeRunnable() {
493                 public void run() {
494                     String JavaDoc s[]= extractTestId(test);
495                     listener.testStarted(s[0], s[1]);
496                 }
497             });
498         }
499     }
500
501     private void notifyTestRunStarted(final int count) {
502         if (JUnitPlugin.isStopped())
503             return;
504         for (int i= 0; i < fListeners.length; i++) {
505             final ITestRunListener listener= fListeners[i];
506             Platform.run(new ListenerSafeRunnable() {
507                 public void run() {
508                     listener.testRunStarted(count);
509                 }
510             });
511         }
512     }
513
514     private void notifyTestFailed() {
515         if (JUnitPlugin.isStopped())
516             return;
517         for (int i= 0; i < fListeners.length; i++) {
518             final ITestRunListener listener= fListeners[i];
519             Platform.run(new ListenerSafeRunnable() {
520                 public void run() {
521                     if (listener instanceof ITestRunListener3 )
522                         ((ITestRunListener3)listener).testFailed(fFailureKind, fFailedTestId,
523                                 fFailedTest, fFailedTrace.toString(), fExpectedResult.toString(), fActualResult.toString());
524                     else
525                         listener.testFailed(fFailureKind, fFailedTestId, fFailedTest, fFailedTrace.toString());
526                 }
527             });
528         }
529     }
530     
531     private void notifyTestRunTerminated() {
532         // fix for 77771 RemoteTestRunnerClient doing work after junit shutdown [JUnit]
533
if (JUnitPlugin.isStopped())
534             return;
535         for (int i= 0; i < fListeners.length; i++) {
536             final ITestRunListener listener= fListeners[i];
537             Platform.run(new ListenerSafeRunnable() {
538                 public void run() {
539                     listener.testRunTerminated();
540                 }
541             });
542         }
543     }
544
545     public void rerunTest(String JavaDoc testId, String JavaDoc className, String JavaDoc testName) {
546         if (isRunning()) {
547             fWriter.println(MessageIds.TEST_RERUN+testId+" "+className+" "+testName); //$NON-NLS-1$ //$NON-NLS-2$
548
fWriter.flush();
549         }
550     }
551 }
552
Popular Tags