KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.model;
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.SafeRunner;
27
28 import org.eclipse.jdt.internal.junit.runner.MessageIds;
29 import org.eclipse.jdt.internal.junit.ui.JUnitPlugin;
30
31 /**
32  * The client side of the RemoteTestRunner. Handles the
33  * marshaling of the different messages.
34  */

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

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

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

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

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

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

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

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

207     private ITestRunListener2[] fListeners;
208
209     /**
210      * The server socket
211      */

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

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

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

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

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

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

283     public synchronized void startListening(ITestRunListener2[] listeners, 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     public synchronized void stopWaiting() {
301         if (fServerSocket != null && ! fServerSocket.isClosed() && fSocket == null) {
302             shutDown(); // will throw a SocketException in Threads that wait in ServerSocket#accept()
303
}
304     }
305
306     private synchronized void shutDown() {
307         if (fDebug)
308             System.out.println("shutdown "+fPort); //$NON-NLS-1$
309

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

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