KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > junit > server > JUnitHostImpl


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.junit.server;
17
18 import com.google.gwt.junit.JUnitMessageQueue;
19 import com.google.gwt.junit.JUnitShell;
20 import com.google.gwt.junit.client.impl.ExceptionWrapper;
21 import com.google.gwt.junit.client.impl.JUnitHost;
22 import com.google.gwt.junit.client.impl.StackTraceWrapper;
23 import com.google.gwt.junit.client.TestResults;
24 import com.google.gwt.junit.client.Trial;
25 import com.google.gwt.user.client.rpc.InvocationException;
26 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
27
28 import java.lang.reflect.Constructor JavaDoc;
29 import java.lang.reflect.Field JavaDoc;
30 import java.util.List JavaDoc;
31
32 import javax.servlet.http.HttpServletRequest JavaDoc;
33
34 /**
35  * An RPC servlet that serves as a proxy to JUnitTestShell. Enables
36  * communication between the unit test code running in a browser and the real
37  * test process.
38  */

39 public class JUnitHostImpl extends RemoteServiceServlet implements JUnitHost {
40
41   /**
42    * A maximum timeout to wait for the test system to respond with the next
43    * test. Practically speaking, the test system should respond nearly instantly
44    * if there are furthur tests to run.
45    */

46   private static final int TIME_TO_WAIT_FOR_TESTNAME = 300000;
47
48   // DEBUG timeout
49
// TODO(tobyr) Make this configurable
50
// private static final int TIME_TO_WAIT_FOR_TESTNAME = 500000;
51

52   /**
53    * A hook into GWTUnitTestShell, the underlying unit test process.
54    */

55   private static JUnitMessageQueue sHost = null;
56
57   /**
58    * Tries to grab the GWTUnitTestShell sHost environment to communicate with
59    * the real test process.
60    */

61   private static synchronized JUnitMessageQueue getHost() {
62     if (sHost == null) {
63       sHost = JUnitShell.getMessageQueue();
64       if (sHost == null) {
65         throw new InvocationException(
66             "Unable to find JUnitShell; is this servlet running under GWTTestCase?");
67       }
68     }
69     return sHost;
70   }
71
72   /**
73    * Simple helper method to set inaccessible fields via reflection.
74    */

75   private static void setField(Class JavaDoc cls, String JavaDoc fieldName, Object JavaDoc obj,
76       Object JavaDoc value) throws SecurityException JavaDoc, NoSuchFieldException JavaDoc,
77       IllegalArgumentException JavaDoc, IllegalAccessException JavaDoc {
78     Field JavaDoc fld = cls.getDeclaredField(fieldName);
79     fld.setAccessible(true);
80     fld.set(obj, value);
81   }
82
83   public String JavaDoc getFirstMethod(String JavaDoc testClassName) {
84     return getHost().getNextTestName(getClientId(), testClassName,
85         TIME_TO_WAIT_FOR_TESTNAME);
86   }
87
88   public String JavaDoc reportResultsAndGetNextMethod(String JavaDoc testClassName,
89       TestResults results) {
90     JUnitMessageQueue host = getHost();
91     HttpServletRequest JavaDoc request = getThreadLocalRequest();
92     String JavaDoc agent = request.getHeader("User-Agent");
93     results.setAgent(agent);
94     String JavaDoc machine = request.getRemoteHost();
95     results.setHost(machine);
96     List JavaDoc trials = results.getTrials();
97     for (int i = 0; i < trials.size(); ++i) {
98       Trial trial = (Trial) trials.get(i);
99       ExceptionWrapper ew = trial.getExceptionWrapper();
100       trial.setException(deserialize(ew));
101     }
102     host.reportResults(testClassName, results);
103     return host.getNextTestName(getClientId(), testClassName,
104         TIME_TO_WAIT_FOR_TESTNAME);
105   }
106
107   /**
108    * Deserializes an ExceptionWrapper back into a Throwable.
109    */

110   private Throwable JavaDoc deserialize(ExceptionWrapper ew) {
111     if (ew == null) {
112       return null;
113     }
114
115     Throwable JavaDoc ex = null;
116     Throwable JavaDoc cause = deserialize(ew.cause);
117     try {
118       Class JavaDoc exClass = Class.forName(ew.typeName);
119       try {
120         // try ExType(String, Throwable)
121
Constructor JavaDoc ctor = exClass.getDeclaredConstructor(new Class JavaDoc[]{
122             String JavaDoc.class, Throwable JavaDoc.class});
123         ctor.setAccessible(true);
124         ex = (Throwable JavaDoc) ctor.newInstance(new Object JavaDoc[]{ew.message, cause});
125       } catch (Throwable JavaDoc e) {
126         // try ExType(String)
127
try {
128           Constructor JavaDoc ctor = exClass
129               .getDeclaredConstructor(new Class JavaDoc[]{String JavaDoc.class});
130           ctor.setAccessible(true);
131           ex = (Throwable JavaDoc) ctor.newInstance(new Object JavaDoc[]{ew.message});
132           ex.initCause(cause);
133         } catch (Throwable JavaDoc e2) {
134           // try ExType(Throwable)
135
try {
136             Constructor JavaDoc ctor = exClass
137                 .getDeclaredConstructor(new Class JavaDoc[]{Throwable JavaDoc.class});
138             ctor.setAccessible(true);
139             ex = (Throwable JavaDoc) ctor.newInstance(new Object JavaDoc[]{cause});
140             setField(exClass, "detailMessage", ex, ew.message);
141           } catch (Throwable JavaDoc e3) {
142             // try ExType()
143
try {
144               Constructor JavaDoc ctor = exClass.getDeclaredConstructor(null);
145               ctor.setAccessible(true);
146               ex = (Throwable JavaDoc) ctor.newInstance(null);
147               ex.initCause(cause);
148               setField(exClass, "detailMessage", ex, ew.message);
149             } catch (Throwable JavaDoc e4) {
150               // we're out of options
151
this.log("Failed to deserialize getException of type '"
152                   + ew.typeName + "'; no available constructor", e4);
153
154               // fall through
155
}
156           }
157         }
158       }
159
160     } catch (Throwable JavaDoc e) {
161       this.log(
162           "Failed to deserialize getException of type '" + ew.typeName + "'",
163           e);
164     }
165
166     if (ex == null) {
167       ex = new RuntimeException JavaDoc(ew.typeName + ": " + ew.message, cause);
168     }
169
170     ex.setStackTrace(deserialize(ew.stackTrace));
171     return ex;
172   }
173
174   /**
175    * Deserializes a StackTraceWrapper back into a StackTraceElement.
176    */

177   private StackTraceElement JavaDoc deserialize(StackTraceWrapper stw) {
178     StackTraceElement JavaDoc ste = null;
179     Object JavaDoc[] args = new Object JavaDoc[]{
180         stw.className, stw.methodName, stw.fileName,
181         new Integer JavaDoc(stw.lineNumber)};
182     try {
183       try {
184         // Try the 4-arg ctor (JRE 1.5)
185
Constructor JavaDoc ctor = StackTraceElement JavaDoc.class
186             .getDeclaredConstructor(new Class JavaDoc[]{
187                 String JavaDoc.class, String JavaDoc.class, String JavaDoc.class, int.class});
188         ctor.setAccessible(true);
189         ste = (StackTraceElement JavaDoc) ctor.newInstance(args);
190       } catch (NoSuchMethodException JavaDoc e) {
191         // Okay, see if there's a zero-arg ctor we can use instead (JRE 1.4.2)
192
Constructor JavaDoc ctor = StackTraceElement JavaDoc.class.getDeclaredConstructor(null);
193         ctor.setAccessible(true);
194         ste = (StackTraceElement JavaDoc) ctor.newInstance(null);
195         setField(StackTraceElement JavaDoc.class, "declaringClass", ste, args[0]);
196         setField(StackTraceElement JavaDoc.class, "methodName", ste, args[1]);
197         setField(StackTraceElement JavaDoc.class, "fileName", ste, args[2]);
198         setField(StackTraceElement JavaDoc.class, "lineNumber", ste, args[3]);
199       }
200     } catch (Throwable JavaDoc e) {
201       this.log("Error creating stack trace", e);
202     }
203     return ste;
204   }
205
206   /**
207    * Deserializes a StackTraceWrapper[] back into a StackTraceElement[].
208    */

209   private StackTraceElement JavaDoc[] deserialize(StackTraceWrapper[] stackTrace) {
210     int len = stackTrace.length;
211     StackTraceElement JavaDoc[] result = new StackTraceElement JavaDoc[len];
212     for (int i = 0; i < len; ++i) {
213       result[i] = deserialize(stackTrace[i]);
214     }
215     return result;
216   }
217
218   /**
219    * Returns a "client id" for the current request.
220    */

221   private String JavaDoc getClientId() {
222     HttpServletRequest JavaDoc request = getThreadLocalRequest();
223     String JavaDoc agent = request.getHeader("User-Agent");
224     String JavaDoc machine = request.getRemoteHost();
225     return machine + " / " + agent;
226   }
227 }
228
Popular Tags