• 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  * Logger.java
25  *
26  */
27 package org.apache.qetest;
28 
29 import java.util.Hashtable;
30 import java.util.Properties;
31 
32 /**
33  * Interface defining a utility that can log out test results.
34  * This interface defnines a standalone utility that can be used
35  * to report the results of a test.  It would commonly be used by a
36  * testing utility library to produce actual output from the run
37  * of a test file.
38  * <p>The Logger defines a minimal interface for expressing the result
39  * of a test in a generic manner.  Different Loggers can be written
40  * to both express the results in different places (on a live console,
41  * in a persistent file, over a network) and in different formats -
42  * perhaps an XMLTestLogger would express the results in an
43  * XML file or object.</p>
44  * <p>In many cases, tests will actually call a Reporter, which
45  * acts as a composite for Logger objects, and includes numerous
46  * useful utility and convenience methods.</p>
47  * <ul>Loggers explicitly have a restricted set of logging calls for
48  * two main reasons:
49  * <li>To help keep tests structured</li>
50  * <li>To make it easier to generate 'reports' based on test output
51  * (i.e. number of tests passed/failed, graphs of results, etc.)</li>
52  * </ul>
53  * <p>While there are a number of very good general purpose logging
54  * utilities out there, I prefer to use this Logger or a similar
55  * class to report the results of tests because this class
56  * specifically constrains the format and manner that a test reports
57  * results.  This should help to keep tests more structured and
58  * easier for other users to understand.  Specific Logger
59  * implementations may of course choose to store or log out their
60  * results in any manner they like; in fact I plan on implementing
61  * a <a href="http://jakarta.apache.org/log4j/docs/index.html">
62  * Log4JLogger</a> class in the future.</p>
63  * @author Shane_Curcuru@lotus.com
64  * @version $Id$
65  */
66 public interface Logger
67 {
68 
69     //-----------------------------------------------------
70     //-------- Constants for common input params --------
71     //-----------------------------------------------------
72 
73     /**
74      * Parameter: FQCN of Logger(s) to use.
75      * <p>Default: usually none, but implementers may choose to call
76      * setupDefaultLogger(). Will accept multiple classnames separated
77      * by ";" semicolon. Format:
78      * <code>-reporters org.apache.qetest.ConsoleLogger;org.apache.qetest.SomeOtherLogger</code></p>
79      */
80     public static final String OPT_LOGGERS = "loggers";
81 
82     /** Constant ';' semicolon for delimiter in OPT_LOGGERS field.   */
83     public static final String LOGGER_SEPARATOR = ";";
84 
85     /**
86      * A default Logger classname - ConsoleLogger.
87      * //@todo have a factory creation service for this so that any
88      * test or testlet that wishes a default logger at startup
89      * can simply ask a common place for one.
90      */
91     public static final String DEFAULT_LOGGER =
92         "org.apache.qetest.ConsoleLogger";
93 
94     /**
95      * Parameter: level of output to log, int 0-99.
96      * {@link #CRITICALMSG CRITICALMSG = 0}, only very important
97      * messages are output from the test or shown in a report, to
98      * {@link #TRACEMSG TRACEMSG}, where all messages are output
99      * or shown in the result.
100      * {@link #CRITICALMSG See CRITICALMSG for a chart of levels.}
101      */
102     public static final String OPT_LOGGINGLEVEL = "loggingLevel";
103 
104     /**
105      * Parameter: if we should log performance data, true/false.
106      */
107     public static final String OPT_PERFLOGGING = "perfLogging";
108 
109     /**
110      * Parameter: if we should dump debugging info to System.err.
111      * <p>This is primarily for debugging the test framework itself,
112      * not necessarily for debugging the application under test.</p>
113      */
114     public static final String OPT_DEBUG = "debug";
115 
116     /**
117      * Parameter: Name of test results file for file-based Loggers.
118      * <p>File-based loggers should use this key as an initializer
119      * for the name of their output file.</p>
120      * <p>Commandline Format: <code>-logFile path\to\ResultsFileName.ext</code></p>
121      * <p>Properties file Format: <code>logFile=path\\to\\ResultsFileName.ext</code></p>
122      * //@todo Need more doc about platform separator differences
123      */
124     public static final String OPT_LOGFILE = "logFile";
125 
126     /**
127      * Parameter: Indent depth for console or HTML/XML loggers.
128      * <p>Loggers may use this as an integer number of spaces to
129      * indent, as applicable to their situation.</p>
130      * <p>Commandline Format: <code>-indent <i>nn</i></code></p>
131      * <p>Properties file Format: <code>indent=<i>nn</i></code></p>
132      */
133     public static final String OPT_INDENT = "indent";
134 
135     //-----------------------------------------------------
136     //-------- Constants for Logger and Reporter interactions --------
137     //-----------------------------------------------------
138 
139     /**
140      * This determines the amount of data actually logged out to results.
141      * <p>Loggers merely use these constants in their output formats.
142      * Reporters will only call contained Loggers to report messages
143      * at the current logging level and higher.
144      * For example, if you <code>setLoggingLevel(ERRORMSG)</code>
145      * (currently found in the {@link Reporter Reporter} subclass) then INFOMSGs
146      * will not be reported, presumably speeding execution time and saving
147      * output log space.  These levels are also coded into most Logger output,
148      * allowing for easy reporting of various levels of results.</p>
149      * <ul>Allowable values are:
150      * <li>CRITICALMSG - Must-be-printed messages; may print only selected
151      * fails (and skip printing most passes).</li>
152      * <li>ERRORMSG - Logs an error and (optionally) a fail.</li>
153      * <li>FAILSONLY - Skips logging out most pass messages (still
154      * reports testFileResults) but prints out all fails.</li>
155      * <li>WARNINGMSG - Used for non-fail warnings - the test will
156      * continue, hopefully sucessfully.</li>
157      * <li>STATUSMSG - Reports on basic status of the test, when you
158      * want to include more detail than in a check() call</li>
159      * <li>INFOMSG - For more basic test debugging messages.</li>
160      * <li>TRACEMSG - Tracing all operations, detailed debugging information.</li>
161      * </ul>
162      * <p>Note that Logger implementations should also generally
163      * put the actual level that each call is logged at into any
164      * persistent outputs.  This will enable you to use results \
165      * analysis tools later on against the results and screen
166      * against loggingLevel then as well.</p>
167      * <p>A common technique is to run a set of tests with a very
168      * high loggingLevel, so most or all output is stored by Loggers,
169      * and then analyze the results with a low logging level.  If
170      * those results show some problems, you can always re-analyze
171      * the results with a higher logging level without having to
172      * re-run the test.</p>
173      * @see #logMsg(int, java.lang.String)
174      */
175     // Levels are separated in actual values in case you wish to add your own levels in between
176     public static final int CRITICALMSG = 0;  // Lowest possible loggingLevel
177 
178     /**
179      * ERRORMSG - Logs an error and (optionally) a fail.
180      * {@link #CRITICALMSG See CRITICALMSG for a chart.}
181      */
182     public static final int ERRORMSG = 10;
183 
184     /**
185      * FAILSONLY - Skips logging out most pass messages.
186      * {@link #CRITICALMSG See CRITICALMSG for a chart.}
187      */
188     public static final int FAILSONLY = 20;
189 
190     /**
191      * WARNINGMSG - Used for non-fail warnings.
192      * {@link #CRITICALMSG See CRITICALMSG for a chart.}
193      */
194     public static final int WARNINGMSG = 30;
195 
196     /**
197      * STATUSMSG - Reports on basic status of the test.
198      * {@link #CRITICALMSG See CRITICALMSG for a chart.}
199      */
200     public static final int STATUSMSG = 40;
201 
202     /**
203      * INFOMSG - For more basic test debugging messages.
204      * {@link #CRITICALMSG See CRITICALMSG for a chart.}
205      */
206     public static final int INFOMSG = 50;
207 
208     /**
209      * TRACEMSG - Tracing all operations.
210      * {@link #CRITICALMSG See CRITICALMSG for a chart.}
211      */
212     public static final int TRACEMSG = 60;  // Highest possible loggingLevel
213 
214     /** Default level is {@link #STATUSMSG STATUSMSG}.   */
215     public static final int DEFAULT_LOGGINGLEVEL = STATUSMSG;
216 
217     /**
218      * Constants for tracking results by testcase or testfile.
219      * <p>Testfiles default to an incomplete or INCP_RESULT.  If a
220      * test never successfully calls a check* method, it's result
221      * will be incomplete.</p>
222      * <p>Note that a test cannot explicitly reset it's result to be INCP.</p>
223      */
224 
225     // Note: implementations should never rely on the actual values
226     //       of these constants, except possibly to ensure that
227     //       overriding values are > greater than other values
228     public static final int INCP_RESULT = 0;
229 
230     // Note: string representations are explicitly set to all be
231     //       4 characters long to make it simpler to parse results
232 
233     /**
234      * Constant "Incp" for result files.
235      * @see #INCP_RESULT
236      */
237     public static final String INCP = "Incp";
238 
239     /**
240      * Constants for tracking results by testcase or testfile.
241      * <p>A PASS_RESULT signifies that a specific test point (or a testcase,
242      * or testfile) has perfomed an operation correctly and has been verified.</p>
243      * <p>A pass overrides an incomplete.</p>
244      * @see #checkPass(java.lang.String)
245      */
246     public static final int PASS_RESULT = 2;
247 
248     /**
249      * Constant "Pass" for result files.
250      * @see #PASS_RESULT
251      */
252     public static final String PASS = "Pass";
253 
254     /**
255      * Constants for tracking results by testcase or testfile.
256      * <p>An AMBG_RESULT or ambiguous result signifies that a specific test
257      * point (or a testcase, or testfile) has perfomed an operation but
258      * that it has not been verified.</p>
259      * <p>Ambiguous results can be used when the test may not have access
260      * to baseline, or verified 'gold' result data.  It may also be used
261      * during test file creation when the tester has not yet specified the
262      * expected behavior of a test.</p>
263      * <p>Ambiguous overrides both pass and incomplete.</p>
264      * @see #checkAmbiguous(java.lang.String)
265      */
266     public static final int AMBG_RESULT = 5;
267 
268     /**
269      * Constant "Ambg" for result files.
270      * @see #AMBG_RESULT
271      */
272     public static final String AMBG = "Ambg";
273 
274     /**
275      * Constants for tracking results by testcase or testfile.
276      * <p>A FAIL_RESULT signifies that a specific test point (or a testcase,
277      * or testfile) has perfomed an operation incorrectly.</p>
278      * <p>A fail in one test point does not necessarily mean that other test
279      * points are invalid - well written tests should be able to continue
280      * and produce valid results for the rest of the test file.</p>
281      * <p>A fail overrides any of incomplete, pass or ambiguous.</p>
282      * @see #checkFail(java.lang.String)
283      */
284     public static final int FAIL_RESULT = 8;
285 
286     /**
287      * Constant "Fail" for result files.
288      * @see #FAIL_RESULT
289      */
290     public static final String FAIL = "Fail";
291 
292     /**
293      * Constants for tracking results by testcase or testfile.
294      * <p>An ERRR_RESULT signifies that some part of the testfile
295      * has caused an unexpected error, exception, or other Really Bad Thing.</p>
296      * <p>Errors signify that something unexpected happened and that the test
297      * may not produce valid results.  It would most commonly be used for
298      * problems relating to setting up test data or errors with other software
299      * being used (i.e. not problems with the actual software code that the
300      * test is attempting to verify).</p>
301      * <p>An error overrides <B>any</B> other result.</p>
302      * @see #checkErr(java.lang.String)
303      */
304     public static final int ERRR_RESULT = 9;
305 
306     /**
307      * Constant "Errr" for result files.
308      * Note all constant strings for results are 4 chars long
309      * to make fixed-length record file-based results simpler.
310      * @see #ERRR_RESULT
311      */
312     public static final String ERRR = "Errr";
313 
314     /**
315      * Testfiles and testcases should default to incomplete.
316      */
317     public final int DEFAULT_RESULT = INCP_RESULT;
318 
319     //-----------------------------------------------------
320     //-------- Control and utility routines --------
321     //-----------------------------------------------------
322 
323     /**
324      * Return a description of what this Logger/Reporter does.
325      * @author Shane_Curcuru@lotus.com
326      * @return description of how this Logger outputs results, OR
327      * how this Reporter uses Loggers, etc..
328      */
getDescription()329     public abstract String getDescription();
330 
331     /**
332      * Returns information about the Property name=value pairs that
333      * are understood by this Logger/Reporter.
334      * @author Shane_Curcuru@lotus.com
335      * @return same as {@link java.applet.Applet#getParameterInfo()}.
336      */
getParameterInfo()337     public abstract String[][] getParameterInfo();
338 
339     /**
340      * Accessor methods for a properties block.
341      * @return our Properties block.
342      */
getProperties()343     public abstract Properties getProperties();
344 
345     /**
346      * Accessor methods for a properties block.
347      * Always having a Properties block allows users to pass common
348      * options to a Logger/Reporter without having to know the specific
349      * 'properties' on the object.
350      * <p>Much like in Applets, users can call getParameterInfo() to
351      * find out what kind of properties are available.  Callers more
352      * commonly simply call initialize(p) instead of setProperties(p)</p>
353      * @author Shane_Curcuru@lotus.com
354      * @param p Properties to set (should be cloned).
355      */
setProperties(Properties p)356     public abstract void setProperties(Properties p);
357 
358     /**
359      * Call once to initialize this Logger/Reporter from Properties.
360      * <p>Simple hook to allow Logger/Reporters with special output
361      * items to initialize themselves.</p>
362      *
363      * @author Shane_Curcuru@lotus.com
364      * @param p Properties block to initialize from.
365      * @return status, true if OK, false if an error occoured.
366      */
initialize(Properties p)367     public abstract boolean initialize(Properties p);
368 
369     /**
370      * Is this Logger/Reporter ready to log results?
371      * Obviously the meaning of 'ready' may be slightly different
372      * between different kinds of Loggers.  A ConsoleLogger may
373      * simply always be ready, since it probably just sends it's
374      * output to System.out.  File-based Loggers may not be ready
375      * until they've opened their file, and if IO errors happen,
376      * may have to report not ready later on as well.
377      * @author Shane_Curcuru@lotus.com
378      * @return status - true if it's ready to report, false otherwise
379      */
isReady()380     public abstract boolean isReady();
381 
382     /**
383      * Flush this Logger/Reporter - should ensure all output is flushed.
384      * Note that the flush operation is not necessarily pertinent to
385      * all types of Logger/Reporter - console-type Loggers no-op this.
386      * @author Shane_Curcuru@lotus.com
387      */
flush()388     public abstract void flush();
389 
390     /**
391      * Close this Logger/Reporter - should include closing any OutputStreams, etc.
392      * Logger/Reporters should return {@link #isReady()} = false
393      * after being closed; presumably they will not actually log
394      * out any further data.
395      * @author Shane_Curcuru@lotus.com
396      */
close()397     public abstract void close();
398 
399     //-----------------------------------------------------
400     //-------- Testfile / Testcase start and stop routines --------
401     //-----------------------------------------------------
402 
403     /**
404      * Report that a testfile has started.
405      * Implementing Loggers must output/store/report a message
406      * that the test file has started.
407      * @author Shane_Curcuru@lotus.com
408      * @param name file name or tag specifying the test.
409      * @param comment comment about the test.
410      */
testFileInit(String name, String comment)411     public abstract void testFileInit(String name, String comment);
412 
413     /**
414      * Report that a testfile has finished, and report it's result.
415      * Implementing Loggers must output a message that the test is
416      * finished, and print the results.
417      * @author Shane_Curcuru@lotus.com
418      * @param msg message to log out
419      * @param result result of testfile
420      */
testFileClose(String msg, String result)421     public abstract void testFileClose(String msg, String result);
422 
423     /**
424      * Report that a testcase has started.
425      * @author Shane_Curcuru@lotus.com
426      * @param comment short description of this test case's objective.
427      */
testCaseInit(String comment)428     public abstract void testCaseInit(String comment);
429 
430     /**
431      * Report that a testcase has finished, and report it's result.
432      * Implementing classes must output a message that a testcase is
433      * finished, and print the results.
434      * @author Shane_Curcuru@lotus.com
435      * @param msg message of name of test case to log out
436      * @param result result of testfile
437      */
testCaseClose(String msg, String result)438     public abstract void testCaseClose(String msg, String result);
439 
440     //-----------------------------------------------------
441     //-------- Test results logging routines --------
442     //-----------------------------------------------------
443 
444     /**
445      * Report a comment to result file with specified severity.
446      * Print out the message, optionally along with the level (depends
447      * on your storage mechanisim: console output probably doesn't need
448      * the level, but a file output probably would want it.)
449      * <p>Note that some Loggers may limit the comment string,
450      * either in overall length or by stripping any linefeeds, etc.
451      * This is to allow for optimization of file or database-type
452      * reporters with fixed fields.  Users who need to log out
453      * special string data should use logArbitrary() instead.</p>
454      * <p>Remember, use {@link #checkPass(String)}, or
455      * {@link #checkFail(String)}, etc. to report the actual
456      * results of your tests.</p>
457      * @author Shane_Curcuru@lotus.com
458      * @param level severity of message; from {@link #CRITICALMSG}
459      * to {@link #TRACEMSG}
460      * @param msg comment to log out.
461      */
logMsg(int level, String msg)462     public abstract void logMsg(int level, String msg);
463 
464     /**
465      * Report an arbitrary String to result file with specified severity.
466      * Log out the String provided exactly as-is.
467      * @author Shane_Curcuru@lotus.com
468      * @param level severity of message; from {@link #CRITICALMSG}
469      * to {@link #TRACEMSG}
470      * @param msg arbitrary String to log out.
471      */
logArbitrary(int level, String msg)472     public abstract void logArbitrary(int level, String msg);
473 
474     /**
475      * Logs out statistics to result file with specified severity.
476      * This is a general-purpose way to log out numeric statistics.  We accept
477      * both a long and a double to allow users to save whatever kind of numbers
478      * they need to, with the simplest API.  The actual meanings of the numbers
479      * are dependent on the implementer.
480      * @author Shane_Curcuru@lotus.com
481      * @param level severity of message; from {@link #CRITICALMSG}
482      * to {@link #TRACEMSG}
483      * @param lVal statistic in long format, if available.
484      * @param dVal statistic in double format, if available.
485      * @param msg comment to log out.
486      */
logStatistic(int level, long lVal, double dVal, String msg)487     public abstract void logStatistic(int level, long lVal, double dVal,
488                                       String msg);
489 
490     /**
491      * Logs out Throwable.toString() and a stack trace of the
492      * Throwable with the specified severity.
493      * <p>Works in conjunction with {@link Reporter#setLoggingLevel(int) setLoggingLevel};
494      * only outputs messages that are more severe than the current
495      * logging level.  Different Logger or Reporter implementations
496      * may implement loggingLevels in different ways currently.</p>
497      * <p>This uses logArbitrary to log out your msg - message,
498      * a newline, throwable.toString(), a newline,
499      * and then throwable.printStackTrace().</p>
500      * <p>Note that this does not imply a failure or problem in
501      * a test in any way: many tests may want to verify that
502      * certain exceptions are thrown, etc.</p>
503      * @author Shane_Curcuru@lotus.com
504      * @param level severity of message.
505      * @param throwable throwable/exception to log out.
506      * @param msg description of the throwable.
507      */
logThrowable(int level, Throwable throwable, String msg)508     public abstract void logThrowable(int level, Throwable throwable, String msg);
509 
510     /**
511      * Logs out a element to results with specified severity.
512      * This method is primarily for Loggers that output to fixed
513      * structures, like files, XML data, or databases.
514      * @author Shane_Curcuru@lotus.com
515      * @param level severity of message; from {@link #CRITICALMSG}
516      * to {@link #TRACEMSG}
517      * @param element name of enclosing element
518      * @param attrs hash of name=value attributes
519      * @param msg Object to log out; up to Loggers to handle
520      * processing of this; usually logs just .toString().
521      */
logElement(int level, String element, Hashtable attrs, Object msg)522     public abstract void logElement(int level, String element,
523                                     Hashtable attrs, Object msg);
524 
525     /**
526      * Logs out contents of a Hashtable with specified severity.
527      * <p>Loggers should store or log the full contents of the hashtable.</p>
528      * @param level severity of message; from {@link #CRITICALMSG}
529      * to {@link #TRACEMSG}
530      * @param hash Hashtable to log the contents of.
531      * @param msg decription of the Hashtable.
532      */
logHashtable(int level, Hashtable hash, String msg)533     public abstract void logHashtable(int level, Hashtable hash, String msg);
534 
535     //-----------------------------------------------------
536     //-------- Test results reporting check* routines --------
537     //-----------------------------------------------------
538     // There is no public void checkIncp(String comment) method
539 
540     /**
541      * Writes out a Pass record with comment.
542      * @author Shane_Curcuru@lotus.com
543      * @param comment comment to log with the pass record.
544      * @see #PASS_RESULT
545      */
checkPass(String comment)546     public abstract void checkPass(String comment);
547 
548     /**
549      * Writes out an ambiguous record with comment.
550      * @author Shane_Curcuru@lotus.com
551      * @param comment to log with the ambg record.
552      * @see #AMBG_RESULT
553      */
checkAmbiguous(String comment)554     public abstract void checkAmbiguous(String comment);
555 
556     /**
557      * Writes out a Fail record with comment.
558      * @author Shane_Curcuru@lotus.com
559      * @param comment comment to log with the fail record.
560      * @see #FAIL_RESULT
561      */
checkFail(String comment)562     public abstract void checkFail(String comment);
563 
564     /**
565      * Writes out an Error record with comment.
566      * @author Shane_Curcuru@lotus.com
567      * @param comment comment to log with the error record.
568      * @see #ERRR_RESULT
569      */
checkErr(String comment)570     public abstract void checkErr(String comment);
571 
572 
573     /* EXPERIMENTAL: have duplicate set of check*() methods
574        that all output some form of ID as well as comment.
575        Leave the non-ID taking forms for both simplicity to the
576        end user who doesn't care about IDs as well as for
577        backwards compatibility.
578     */
579 
580     /**
581      * Writes out a Pass record with comment and ID.
582      * @author Shane_Curcuru@lotus.com
583      * @param comment comment to log with the pass record.
584      * @param ID token to log with the pass record.
585      * @see #PASS_RESULT
586      */
checkPass(String comment, String id)587     public abstract void checkPass(String comment, String id);
588 
589     /**
590      * Writes out an ambiguous record with comment and ID.
591      * @author Shane_Curcuru@lotus.com
592      * @param comment to log with the ambg record.
593      * @param ID token to log with the pass record.
594      * @see #AMBG_RESULT
595      */
checkAmbiguous(String comment, String id)596     public abstract void checkAmbiguous(String comment, String id);
597 
598     /**
599      * Writes out a Fail record with comment and ID.
600      * @author Shane_Curcuru@lotus.com
601      * @param comment comment to log with the fail record.
602      * @param ID token to log with the pass record.
603      * @see #FAIL_RESULT
604      */
checkFail(String comment, String id)605     public abstract void checkFail(String comment, String id);
606 
607     /**
608      * Writes out an Error record with comment and ID.
609      * @author Shane_Curcuru@lotus.com
610      * @param comment comment to log with the error record.
611      * @param ID token to log with the pass record.
612      * @see #ERRR_RESULT
613      */
checkErr(String comment, String id)614     public abstract void checkErr(String comment, String id);
615 }  // end of class Logger
616 
617