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