1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.jameleon;
20
21 import net.sf.jameleon.event.TestCaseEventHandler;
22 import net.sf.jameleon.event.TestCaseListener;
23 import net.sf.jameleon.event.TestRunEventHandler;
24 import net.sf.jameleon.exception.JameleonException;
25 import net.sf.jameleon.reporting.ReporterUtils;
26 import net.sf.jameleon.reporting.ResultsReporter;
27 import net.sf.jameleon.util.Configurator;
28 import net.sf.jameleon.util.JameleonDefaultValues;
29 import net.sf.jameleon.util.JameleonUtility;
30 import org.apache.commons.jelly.JellyContext;
31 import org.apache.commons.jelly.JellyException;
32 import org.apache.commons.jelly.XMLOutput;
33 import org.apache.log4j.LogManager;
34 import org.apache.log4j.Logger;
35
36 import java.io.File;
37 import java.io.FileNotFoundException;
38 import java.io.FileWriter;
39 import java.io.IOException;
40 import java.util.*;
41
42 /***
43 * Executes a Jameleon Test Case.
44 */
45 public class ExecuteTestCase {
46
47 /***
48 * A list of files to execute
49 */
50 protected final List files = new LinkedList();
51 /***
52 * A list of files to execute
53 */
54 protected final List testCaseListeners = new LinkedList();
55 /***
56 * A set of key-value variables to be set in the context
57 */
58 protected Map contextVars;
59 /***
60 * Print out stack trace of each failed Jameleon Test Case
61 * to stdout.
62 */
63 protected boolean debug = false;
64 /***
65 * Print the name of the script being executed to stdout
66 */
67 protected boolean printFooter = true;
68 /***
69 * The # of milliseconds to wait between each script execution
70 */
71 protected long waitTimeBetweenScripts = 0;
72 /***
73 * A line of dashes
74 */
75 protected static final String DASH = "\n-------------------------------------------------------------\n";
76 /***
77 * A line of underscores
78 */
79 protected static final String US = "\n_______________________________________________________________\n";
80 protected final Logger log = Logger.getLogger(ExecuteTestCase.class.getName());
81 private ResultsReporter reporter;
82
83 protected final static TestCaseTagLibrary tagLibrary = new TestCaseTagLibrary();
84 /***
85 * The jameleon.conf configuration name for a list of desired TestCaseListeners to be registered.
86 */
87 public static final String TEST_CASE_LISTENERS = "TestCaseListeners";
88
89 public ExecuteTestCase(){
90 contextVars = new HashMap();
91 }
92
93 public ExecuteTestCase(boolean debug){
94 this();
95 this.debug = debug;
96 }
97
98 /***
99 * Read in desired TestCaseListeners defined in jameleon.conf and register them
100 * in the TestCaseEventHandler.
101 */
102 public void registerEventListeners(){
103 registerEventListeners(true);
104 }
105
106 public ResultsReporter getResultsReporter(){
107 return reporter;
108 }
109
110 /***
111 * Read in desired TestCaseListeners defined in jameleon.conf and register them
112 * in the TestCaseEventHandler.
113 * @param useCurrentThread if set to true, then use the current thread's classloader
114 */
115 public void registerEventListeners(boolean useCurrentThread){
116
117 beginTestRun();
118 String[] tcListeners = Configurator.getInstance().getValueAsArray(TEST_CASE_LISTENERS);
119 TestCaseListener tcListener;
120 Class c;
121 for (int i = 0; tcListeners != null && i < tcListeners.length; i++) {
122 try{
123
124
125 if (useCurrentThread) {
126 c = Thread.currentThread().getContextClassLoader().loadClass(tcListeners[i]);
127 }else{
128 c = Class.forName(tcListeners[i]);
129 }
130 tcListener = (TestCaseListener)c.newInstance();
131
132 registerEventListener(tcListener);
133 }catch(Exception e){
134 e.printStackTrace();
135 System.err.println("Could not register TestCaseListeners: "+e.getMessage());
136 }
137 }
138 }
139
140 /***
141 * Register a new TestCaseListener
142 * in the TestCaseEventHandler.
143 * @param tcListener The TestCaseListener to register
144 */
145 public void registerEventListener(TestCaseListener tcListener){
146 if (tcListener != null) {
147 TestCaseEventHandler tcHandler = TestCaseEventHandler.getInstance();
148 testCaseListeners.add(tcListener);
149 tcHandler.addTestCaseListener(tcListener);
150 }
151 }
152
153 /***
154 * Remove all TestCaseListeners registered via the registerEventListeners method.
155 */
156 public void deregisterEventListeners(){
157 endTestRun();
158 TestCaseListener listener;
159 for (Iterator it = testCaseListeners.iterator(); it.hasNext(); ) {
160 listener = (TestCaseListener)it.next();
161 TestCaseEventHandler.getInstance().removeTestCaseListener(listener);
162 }
163 }
164
165 public void setPrintFooter(boolean printFooter){
166 this.printFooter = printFooter;
167 }
168
169 public void setWaitTimeBetweenScripts(long waitTimeBetweenScripts){
170 this.waitTimeBetweenScripts = waitTimeBetweenScripts;
171 }
172
173 public long getWaitTimeBetweenScripts(){
174 return waitTimeBetweenScripts;
175 }
176
177 /***
178 * Begins the test run. This creates a new html reporter which in turn ends up
179 * generating another results file.
180 */
181 public void beginTestRun(){
182 Calendar startTime = Calendar.getInstance();
183 try{
184 File resultsDir = ReporterUtils.getResultsDir();
185 File resultsFile = new File(ResultsReporter.getResultsDir(resultsDir, startTime),
186 "TestResults.html");
187 File testRunSummaryFile = new File(resultsDir, JameleonDefaultValues.TEST_RUN_SUMMARY_FILE_NAME);
188 JameleonUtility.createDirStructure(resultsFile.getParentFile());
189 reporter = ResultsReporter.getInstance();
190 reporter.getHtmlTestRunReporter().setWriter(new FileWriter(resultsFile));
191 reporter.getHtmlTestRunSummaryReporter().setPrintHeader(testRunSummaryFile.length() == 0);
192
193 reporter.getHtmlTestRunSummaryReporter().setWriter(new FileWriter(testRunSummaryFile, true));
194 }catch(IOException ioe){
195 throw new JameleonException("Could not configure Jameleon to write out results file", ioe);
196 }
197 TestCaseEventHandler.getInstance().addTestCaseListener(reporter);
198 TestRunEventHandler.getInstance().addTestRunListener(reporter);
199 TestRunEventHandler.getInstance().beginTestRun(startTime);
200 }
201
202 /***
203 * Ends the test run.
204 */
205 public void endTestRun(){
206 TestRunEventHandler.getInstance().endTestRun(Calendar.getInstance());
207 TestCaseEventHandler.getInstance().removeTestCaseListener(reporter);
208 TestRunEventHandler.getInstance().removeTestRunListener(reporter);
209 try {
210 reporter.getHtmlTestRunReporter().getWriter().close();
211 } catch (IOException e) {
212 System.err.println("Error closing test results summary writer");
213 e.printStackTrace();
214 }
215 }
216
217
218
219
220
221 public static void main (String args[]) {
222 StringBuffer errMsg = new StringBuffer();
223 ExecuteTestCase exec = new ExecuteTestCase();
224 exec.registerEventListeners();
225 boolean printFooterStatic = true;
226 int startingPoint = 0;
227 if (args.length > 0 && args[0].equalsIgnoreCase("false")) {
228 printFooterStatic = false;
229 startingPoint = 1;
230 }
231 if (args.length > startingPoint) {
232 File f = null;
233 for (int i = startingPoint; i < args.length; i++) {
234 f = new File(args[i]);
235 if (f.exists()) {
236 exec.addFile(f);
237 }
238 }
239 }
240 errMsg.append(exec.executeFiles());
241 try{
242 if ( errMsg.length() > 0 ) {
243 System.out.println("The following test cases failed:"+errMsg.toString());
244 System.out.println("");
245 System.out.println("");
246 throw new JameleonException("See 'TestResults.xml' and 'TestResults.html' for a more detailed reason (stack trace) as why the test case(s) failed.");
247 }
248 }finally{
249 exec.deregisterEventListeners();
250 if (printFooterStatic) {
251 closeAllLogs();
252 }
253 }
254 }
255
256 /***
257 * This is a workaround to the fact the shutdown is not called in log4j.
258 */
259 public static void closeAllLogs(){
260 LogManager.getLoggerRepository().shutdown();
261 }
262
263 /***
264 * Runs through all files in the given file or directory
265 * and executes each file as a Jameleon test script.
266 * @param f The file to execute
267 * @return the error message if one exists
268 */
269 public String execute(File f) {
270 StringBuffer errMsg = new StringBuffer();
271 if (f.isDirectory()) {
272 File[] filesA = f.listFiles();
273 for (int i = 0; i < filesA.length; i++) {
274 if (filesA[i].isDirectory()) {
275 errMsg.append(execute(filesA[i]));
276 }else if(filesA[i].isFile() && filesA[i].getName().endsWith(".xml")){
277 errMsg.append(executeJellyScript(filesA[i]));
278 }else{
279 System.out.println("Skipping "+filesA[i].getAbsolutePath());
280 }
281 }
282 }else if(f.isFile() && f.getName().endsWith(".xml")){
283 errMsg.append(executeJellyScript(f));
284 }else{
285 System.out.println("Skipping "+f.getAbsolutePath());
286 }
287 return errMsg.toString();
288 }
289
290 public String executeFiles(){
291 StringBuffer errMsg = new StringBuffer();
292 Iterator it = getFiles().iterator();
293 while (it.hasNext()) {
294 File f = (File)it.next();
295 errMsg.append(execute(f));
296 if (it.hasNext()) {
297 delay();
298 }
299 }
300 return errMsg.toString();
301 }
302
303 /***
304 * Executes the given file as a Jameleon test script and returns the error message if the test failed.
305 * Only a single file should be passed to this method.
306 * @param file - the file to execute.
307 * @return a String representing the error(s), if any, that occured
308 */
309 public String executeJellyScript(File file){
310 String errMsg = "";
311 JellyContext context = null;
312 try{
313 context = runScript(file);
314 }catch(FileNotFoundException fnfe){
315 errMsg = "Could not execute \""+file.getPath() + "\"! File NOT FOUND!";
316 return errMsg;
317 }catch(Exception je){
318 if ( debug ) {
319 je.printStackTrace();
320 }
321 errMsg = US + file + DASH + "CAUSE:\n" + je.getMessage();
322 }finally{
323 if (context != null) {
324 context.getVariables().clear();
325 context.clear();
326 context = null;
327 }
328 }
329 return errMsg;
330 }
331
332 public JellyContext runScript(File file) throws JellyException, FileNotFoundException{
333 if (!file.exists()) {
334 throw new FileNotFoundException(file.getPath() +" not found!");
335 }
336 XMLOutput out = XMLOutput.createDummyXMLOutput();
337 JellyContext context = new JellyContext();
338
339
340 String fileName = file.getPath();
341 JellyContext scriptContext = null;
342 try{
343 context.registerTagLibrary("jelly:jameleon", tagLibrary);
344 setContextVariables(context);
345 scriptContext = context.runScript(file, out);
346 }finally{
347 try{
348 out.close();
349 }catch(IOException ioe){
350 ioe.printStackTrace();
351 }
352 out = null;
353 }
354 return scriptContext;
355 }
356
357 protected void setContextVariables(JellyContext context){
358 if (contextVars.size() > 0) {
359 context.setVariables(contextVars);
360 }
361 }
362
363 /***
364 * Adds a file or directory to the list of files to be executed by this instance.
365 * @param f The file to add
366 */
367 public void addFile(File f){
368 files.add(f);
369 }
370
371 /***
372 * @return a List of files and/or directories to be executed by this instance.
373 */
374 public List getFiles(){
375 return files;
376 }
377
378 public Map getContextVars(){
379 return contextVars;
380 }
381
382
383 protected void delay(){
384 if (waitTimeBetweenScripts > 0) {
385 synchronized (this){
386 try {
387 this.wait(waitTimeBetweenScripts);
388 } catch (InterruptedException e) {
389 e.printStackTrace();
390 }
391 }
392 }
393 }
394
395 }
396