• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id$
20  */
21 
22 /*
23  *
24  * TestImpl.java
25  *
26  */
27 package org.apache.qetest;
28 
29 import java.util.Properties;
30 
31 /**
32  * Minimal class defining a test implementation, using a Reporter.
33  * <p>TestImpls generally interact with a Reporter, which reports
34  * out in various formats the results from this test.
35  * Most test classes should subclass from this test, as it adds
36  * structure that helps to define the conceptual logic of running
37  * a 'test'.  It also provides useful default implementations.</p>
38  * <p>Users wishing a much simpler testing framework can simply
39  * implement the minimal methods in the Test interface, and use a
40  * Logger to report results instead of a Reporter.</p>
41  * @author Shane_Curcuru@lotus.com
42  * @version $Id$
43  */
44 public class TestImpl implements Test
45 {
46 
47     /**
48      * Name (and description) of the current test.
49      * <p>Note that these are merely convenience variables - you do not need
50      * to use them.  If you do use them, they should be initialized at
51      * construction time.</p>
52      */
53     protected String testName = null;
54 
55     /**
56      * Accesor method for the name of this test.
57      *
58      * NEEDSDOC ($objectName$) @return
59      */
getTestName()60     public String getTestName()
61     {
62         return testName;
63     }
64 
65     /** (Name and) description of the current test. */
66     protected String testComment = null;
67 
68     /**
69      * Accesor method for a brief description of this test.
70      *
71      * NEEDSDOC ($objectName$) @return
72      */
getTestDescription()73     public String getTestDescription()
74     {
75         return testComment;
76     }
77 
78     /**
79      * Default constructor - initialize testName, Comment.
80      */
TestImpl()81     public TestImpl()
82     {
83 
84         // Only set them if they're not set
85         if (testName == null)
86             testName = "TestImpl.defaultName";
87 
88         if (testComment == null)
89             testComment = "TestImpl.defaultComment";
90     }
91 
92     /** Our Logger, who we tell all our secrets to. */
93     protected Logger logger = null;
94 
95     /**
96      * Accesor methods for our Logger.
97      *
98      * NEEDSDOC @param l
99      */
setLogger(Logger l)100     public void setLogger(Logger l)
101     {  // no-op: our implementation always uses a Reporter
102     }
103 
104     /**
105      * Accesor methods for our Logger.
106      *
107      * NEEDSDOC ($objectName$) @return
108      */
getLogger()109     public Logger getLogger()
110     {
111         return null;
112     }
113 
114     /** Our Reporter, who we tell all our secrets to. */
115     protected Reporter reporter;
116 
117     /**
118      * Accesor methods for our Reporter.
119      *
120      * NEEDSDOC @param r
121      */
setReporter(Reporter r)122     public void setReporter(Reporter r)
123     {
124         if (r != null)
125             reporter = r;
126     }
127 
128     /**
129      * Accesor methods for our Reporter.
130      *
131      * NEEDSDOC ($objectName$) @return
132      */
getReporter()133     public Reporter getReporter()
134     {
135         return reporter;
136     }
137 
138     /** Flag to indicate a serious enough error that we should just give up. */
139     protected boolean abortTest = false;
140 
141     /**
142      * Accesor methods for our abort flag.
143      *
144      * NEEDSDOC @param a
145      */
setAbortTest(boolean a)146     public void setAbortTest(boolean a)
147     {
148         abortTest = a;
149     }
150 
151     /**
152      * Accesor methods for our abort flag.
153      *
154      * NEEDSDOC ($objectName$) @return
155      */
getAbortTest()156     public boolean getAbortTest()
157     {
158         return (abortTest);
159     }
160 
161     /**
162      * Run this test: main interface to cause the test to run itself.
163      * <p>A major goal of the TestImpl class is to separate the act and process
164      * of writing a test from it's actual runtime implementation.  Testwriters
165      * should not need to know how their test is being executed.</p>
166      * <ul>They should simply focus on defining:
167      * <li>doTestFileInit: what setup has to be done before running the test</li>
168      * <li>testCase1, 2, ... n: individual, independent test cases</li>
169      * <li>doTestFileClose: what cleanup has to be done after running the test</li>
170      * </ul>
171      * <p>This method returns a simple boolean status as a convenience.  In cases
172      * where you have a harness that runs a great many tests that normally pass, the
173      * harness can simply check this value for each test: if it's true, you could
174      * even delete any result logs then, and simply print out a meta-log stating
175      * that the test passed.  Note that this does not provide any information about
176      * why a test failed (or caused an error, or whatever) - that's what the info in
177      * any Reporter's logs are for.</p>
178      * <p>If a test is aborted, then any containing harness needs not
179      * finish executing the test.  Otherwise, even if part of a test fails,
180      * you should let the whole test run through.</p>
181      * <p>Harnesses should generally simply call runTest() to ask the
182      * test to run itself.  In some cases a Harness might want to control
183      * the process more closely, in which case it should call:
184      * <code>
185      *  test.setReporter(); // optional, depending on the test
186      *  test.testFileInit();
187      *  test.runTestCases();
188      *  test.testFileClose();
189      * </code>  instead.
190      * @todo return TestResult instead of boolean flag
191      * @author Shane_Curcuru@lotus.com
192      *
193      * NEEDSDOC @param p
194      * @return status - true if test ran to completion and <b>all</b>
195      * cases passed, false otherwise
196      */
runTest(Properties p)197     public boolean runTest(Properties p)
198     {
199 
200         boolean status = testFileInit(p);
201 
202         if (getAbortTest())
203             return status;
204 
205         status &= runTestCases(p);
206 
207         if (getAbortTest())
208             return status;
209 
210         status &= testFileClose(p);
211 
212         return status;
213     }
214 
215     /**
216      * Initialize this test - called once before running testcases.
217      * Predefined behavior - subclasses should <b>not</b> override this method.
218      * <p>This method is basically a composite that masks the most common
219      * implementation: creating a reporter or logger first, then initializing
220      * any data or product settings the test needs setup first. It does this
221      * by separating this method into three methods:
222      * <code>
223      *   preTestFileInit(); // Create/initialize Reporter
224      *   doTestFileInit();  // User-defined: initialize product under test
225      *   postTestFileInit() // Report out we've completed initialization
226      * </code>
227      * </p>
228      * @author Shane_Curcuru@lotus.com
229      * @see #preTestFileInit(java.util.Properties)
230      * @see #doTestFileInit(java.util.Properties)
231      * @see #postTestFileInit(java.util.Properties)
232      *
233      * NEEDSDOC @param p
234      *
235      * NEEDSDOC ($objectName$) @return
236      */
testFileInit(Properties p)237     public boolean testFileInit(Properties p)
238     {
239 
240         // Note: we don't want to use shortcut operators here,
241         //       since we want each method to get called
242         // Pass the Property block to each method, so that
243         //       subclasses can do initialization whenever
244         //       is best for their design
245         return preTestFileInit(p) & doTestFileInit(p) & postTestFileInit(p);
246     }
247 
248     /**
249      * Initialize this test - called once before running testcases.
250      * <p>Create and initialize a Reporter here.</p>
251      * <p>This implementation simply creates a default Reporter
252      * and adds a ConsoleLogger. Most test groups will want to override
253      * this method to create custom Reporters or Loggers.</p>
254      * @author Shane_Curcuru@lotus.com
255      * @see #testFileInit(java.util.Properties)
256      *
257      * NEEDSDOC @param p
258      *
259      * NEEDSDOC ($objectName$) @return
260      */
preTestFileInit(Properties p)261     public boolean preTestFileInit(Properties p)
262     {
263 
264         // Pass our properties block directly to the reporter
265         //  so it can use the same values in initialization
266         setReporter(new Reporter(p));
267         reporter.addDefaultLogger();
268         reporter.testFileInit(testName, testComment);
269 
270         return true;
271     }
272 
273     /**
274      * Initialize this test - called once before running testcases.
275      * <p>Subclasses <b>must</b> override this to do whatever specific
276      * processing they need to initialize their product under test.</p>
277      * <p>If for any reason the test should not continue, it <b>must</b>
278      * return false from this method.</p>
279      * @author Shane_Curcuru@lotus.com
280      * @see #testFileInit(java.util.Properties)
281      *
282      * NEEDSDOC @param p
283      *
284      * NEEDSDOC ($objectName$) @return
285      */
doTestFileInit(Properties p)286     public boolean doTestFileInit(Properties p)
287     {
288 
289         // @todo implement in your subclass
290         reporter.logTraceMsg(
291             "TestImpl.doTestFileInit() default implementation - please override");
292 
293         return true;
294     }
295 
296     /**
297      * Initialize this test - called once before running testcases.
298      * <p>Simply log out that our initialization has completed,
299      * so that structured-style logs will make it clear where startup
300      * code ends and testCase code begins.</p>
301      * @author Shane_Curcuru@lotus.com
302      * @see #testFileInit(java.util.Properties)
303      *
304      * NEEDSDOC @param p
305      *
306      * NEEDSDOC ($objectName$) @return
307      */
postTestFileInit(Properties p)308     public boolean postTestFileInit(Properties p)
309     {
310 
311         reporter.logTraceMsg(
312             "TestImpl.postTestFileInit() initialization complete");
313 
314         return true;
315     }
316 
317     /**
318      * Run all of our testcases.
319      * Subclasses must override this method.  It should cause each testCase
320      * in the test to be executed independently, and then return true if and
321      * only if all testCases passed successfully.  If any testCase failed or
322      * caused any unexpected errors, exceptions, etc., it should return false.
323      * @author Shane_Curcuru@lotus.com
324      *
325      * NEEDSDOC @param p
326      * @return true if all testCases passed, false otherwise
327      */
runTestCases(Properties p)328     public boolean runTestCases(Properties p)
329     {
330 
331         // @todo implement in your subclass
332         reporter.logTraceMsg(
333             "TestImpl.runTestCases() default implementation - please override");
334 
335         return true;
336     }
337 
338     /**
339      * Cleanup this test - called once after running testcases.
340      * @author Shane_Curcuru@lotus.com
341      *
342      * NEEDSDOC @param p
343      * @return true if cleanup successful, false otherwise
344      */
testFileClose(Properties p)345     public boolean testFileClose(Properties p)
346     {
347 
348         // Note: we don't want to use shortcut operators here,
349         //       since we want each method to get called
350         return preTestFileClose(p) & doTestFileClose(p)
351                & postTestFileClose(p);
352     }
353 
354     /**
355      * Log a trace message - called once after running testcases.
356      * <p>Predefined behavior - subclasses should <B>not</B> override this method.</p>
357      * @todo currently is primarily here to mark that we're closing
358      * the test, in case doTestFileClose() blows up somehow.  May not be needed.
359      * @author Shane_Curcuru@lotus.com
360      * @see #testFileClose()
361      *
362      * NEEDSDOC @param p
363      *
364      * NEEDSDOC ($objectName$) @return
365      */
preTestFileClose(Properties p)366     protected boolean preTestFileClose(Properties p)
367     {
368 
369         // Have the reporter log a trace that the test is about to cleanup
370         reporter.logTraceMsg("TestImpl.preTestFileClose()");
371 
372         return true;
373     }
374 
375     /**
376      * Cleanup this test - called once after running testcases.
377      * <p>Subclasses <b>must</b> override this to do whatever specific
378      * processing they need to cleanup after all testcases are run.</p>
379      * @author Shane_Curcuru@lotus.com
380      *
381      * NEEDSDOC @param p
382      *
383      * NEEDSDOC ($objectName$) @return
384      */
doTestFileClose(Properties p)385     public boolean doTestFileClose(Properties p)
386     {
387 
388         // @todo implement in your subclass
389         reporter.logTraceMsg(
390             "TestImpl.doTestFileClose() default implementation - please override");
391 
392         return true;
393     }
394 
395     /**
396      * Mark the test complete - called once after running testcases.
397      * <p>Predefined behavior - subclasses should <b>not</b> override
398      * this method. Currently just tells our reporter to log the
399      * testFileClose. This will calculate final results, and complete
400      * logging for any structured output logs (like XML files).</p>
401      * @author Shane_Curcuru@lotus.com
402      * @see #testFileClose()
403      *
404      * NEEDSDOC @param p
405      *
406      * NEEDSDOC ($objectName$) @return
407      */
postTestFileClose(Properties p)408     protected boolean postTestFileClose(Properties p)
409     {
410 
411         // Have the reporter log out our completion
412         reporter.testFileClose();
413 
414         return true;
415     }
416 
417     /**
418      * Main method to run test from the command line.
419      * Test subclasses <B>must</B> override, obviously.
420      * @author Shane Curcuru
421      *
422      * NEEDSDOC @param args
423      */
main(String[] args)424     public static void main(String[] args)
425     {
426 
427         TestImpl app = new TestImpl();
428         Properties p = new Properties();
429 
430         p.put(MAIN_CMDLINE, args);
431         app.runTest(p);
432     }
433 }  // end of class Test
434 
435