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 package org.apache.qetest.trax; 23 24 import java.io.File; 25 import java.io.FileOutputStream; 26 import java.util.Enumeration; 27 import java.util.Hashtable; 28 import java.util.Properties; 29 import java.util.Vector; 30 31 import javax.xml.transform.Templates; 32 import javax.xml.transform.Transformer; 33 import javax.xml.transform.TransformerFactory; 34 import javax.xml.transform.stream.StreamResult; 35 import javax.xml.transform.stream.StreamSource; 36 37 import org.apache.qetest.FileBasedTest; 38 import org.apache.qetest.Logger; 39 import org.apache.qetest.OutputNameManager; 40 import org.apache.qetest.QetestUtils; 41 import org.apache.qetest.xsl.XSLTestfileInfo; 42 import org.apache.qetest.xslwrapper.TransformWrapper; 43 import org.apache.qetest.xslwrapper.TransformWrapperFactory; 44 import org.apache.qetest.xslwrapper.TransformWrapperHelper; 45 46 /** 47 * Minitest - developer check-in test for Xalan-J 2.x. 48 * 49 * <p>Developers should always run either the minitest or smoketest 50 * target before checking any code into the xml-xalan CVS 51 * repository. Running the minitest before checking in ensures 52 * that the Xalan CVS tree will always be in a compileable and 53 * at least basically functional state, thus ensuring a workable 54 * product for your fellow Xalan developers. Ensuring your code 55 * passes the smoketest target will also help the nightly GUMP 56 * runs to pass the smoketest as well and avoid 'nag' emails.</p> 57 * 58 * <p>If you really need to make a checkin that will temporarily 59 * break or fail the minitest, then <b>please</b> be sure to send 60 * email to xalan-dev@xml.apache.org letting everyone know.</p> 61 * 62 * <p>For more information, please see the 63 * <a href="http://xml.apache.org/xalan-j/test/overview.html"> 64 * testing docs</a> and the nightly 65 * <a href="http://jakarta.apache.org/builds/gump/"> 66 * GUMP build page</a>.</p> 67 * 68 * @author shane_curcuru@us.ibm.com 69 * @version $Id$ 70 */ 71 public class Minitest extends FileBasedTest 72 { 73 74 /** 75 * Provides nextName(), currentName() functionality for tests 76 * that may produce any number of output files. 77 */ 78 protected OutputNameManager outNames; 79 80 /** 81 * Basic output name root used throughout tests. 82 */ 83 protected String baseOutName; 84 85 /** The Minitest.xsl/.xml file; note goldName is version-specific. */ 86 protected XSLTestfileInfo testFileInfo = new XSLTestfileInfo(); 87 88 /** The MinitestParam.xsl/.xml file. */ 89 protected XSLTestfileInfo paramFileInfo = new XSLTestfileInfo(); 90 91 /** The MinitestPerf.xsl/.xml file. */ 92 protected XSLTestfileInfo perfFileInfo = new XSLTestfileInfo(); 93 94 95 /** Constants matching parameter names/values in paramFileInfo. */ 96 public static final String PARAM1S = "param1s"; 97 public static final String PARAM2S = "param2s"; 98 public static final String PARAM1N = "param1n"; 99 public static final String PARAM2N = "param2n"; 100 101 /** Just initialize test name, comment, numTestCases. */ Minitest()102 public Minitest() 103 { 104 numTestCases = 5; // REPLACE_num 105 testName = "Minitest"; 106 testComment = "Minitest - developer check-in test for Xalan-J 2.x."; 107 } 108 109 110 /** 111 * Initialize this test - Set names of xml/xsl test files, etc. 112 * 113 * Also cleans up any Pass-Minitest.xml file that is checked 114 * for in test.properties' minitest.passfile and generated by 115 * Reporter.writeResultsStatus(). 116 * 117 * @param p Properties to initialize from (if needed) 118 * @return false if we should abort the test; true otherwise 119 * @see Reporter.writeResultsStatus(boolean) 120 */ doTestFileInit(Properties p)121 public boolean doTestFileInit(Properties p) 122 { 123 // Used for all tests; just dump files in outputDir 124 File outSubDir = new File(outputDir); 125 if (!outSubDir.mkdirs()) 126 { 127 if (!outSubDir.exists()) 128 reporter.logErrorMsg("Problem creating output dir: " + outSubDir); 129 } 130 // Initialize an output name manager to that dir with .out extension 131 baseOutName = outputDir + File.separator + testName; 132 outNames = new OutputNameManager(baseOutName, ".out"); 133 134 String testBasePath = inputDir 135 + File.separator; 136 String goldBasePath = goldDir 137 + File.separator; 138 139 testFileInfo.inputName = testBasePath + "Minitest.xsl"; 140 testFileInfo.xmlName = testBasePath + "Minitest.xml"; 141 // Use separate output files for different versions, since 142 // some indenting rules are implemented differently 1.x/2.x 143 testFileInfo.goldName = goldBasePath + "Minitest-xalanj2.out"; 144 testFileInfo.description = "General minitest, covers many xsl: elems"; 145 146 paramFileInfo.inputName = testBasePath + "MinitestParam.xsl"; 147 paramFileInfo.xmlName = testBasePath + "MinitestParam.xml"; 148 paramFileInfo.goldName = goldBasePath + "MinitestParam.out"; 149 paramFileInfo.description = "Simple string and int params"; 150 151 perfFileInfo.inputName = testBasePath + "MinitestPerf.xsl"; 152 perfFileInfo.xmlName = testBasePath + "MinitestPerf.xml"; 153 perfFileInfo.goldName = goldBasePath + "MinitestPerf.out"; 154 perfFileInfo.description = "Simple performance test"; 155 156 try 157 { 158 // Clean up any Pass files for the minitest that exist 159 //@see Reporter.writeResultsStatus(boolean) 160 String logFileBase = (new File(testProps.getProperty(Logger.OPT_LOGFILE, "ResultsSummary.xml"))).getAbsolutePath(); 161 logFileBase = (new File(logFileBase)).getParent(); 162 163 File f = new File(logFileBase, Logger.PASS + "-" + testName + ".xml"); 164 reporter.logTraceMsg("Deleting previous file: " + f); 165 f.delete(); 166 } 167 catch (Exception e) 168 { 169 reporter.logThrowable(reporter.ERRORMSG, e, "Deleting Pass-Minitest file threw"); 170 reporter.logErrorMsg("Deleting Pass-Minitest file threw: " + e.toString()); 171 } 172 173 return true; 174 } 175 176 177 /** 178 * Basic systemId transforms and params plus API coverage. 179 * 180 * @return false if we should abort the test; true otherwise 181 */ testCase1()182 public boolean testCase1() 183 { 184 reporter.testCaseInit("Basic systemId transforms and params plus API coverage"); 185 186 TransformerFactory factory = null; 187 Templates templates = null; 188 Transformer transformer = null; 189 try 190 { 191 factory = TransformerFactory.newInstance(); 192 templates = factory.newTemplates(new StreamSource(QetestUtils.filenameToURL(testFileInfo.inputName))); 193 reporter.check((templates != null), true, "factory.newTemplates(StreamSource) is non-null"); 194 } 195 catch (Throwable t) 196 { 197 reporter.logThrowable(reporter.ERRORMSG, t, 198 "Problem creating Templates; cannot continue testcase"); 199 reporter.checkErr("Problem creating Templates; cannot continue testcase"); 200 return true; 201 } 202 try 203 { 204 // Validate a systemId transform 205 reporter.logTraceMsg("Basic stream transform(1)(" + QetestUtils.filenameToURL(testFileInfo.xmlName) + ", " 206 + QetestUtils.filenameToURL(testFileInfo.inputName) + ", " 207 + outNames.nextName()); 208 transformer = templates.newTransformer(); 209 FileOutputStream fos = new FileOutputStream(outNames.currentName()); 210 transformer.transform(new StreamSource(QetestUtils.filenameToURL(testFileInfo.xmlName)), 211 new StreamResult(fos)); 212 fos.close(); 213 int fileCheckStatus = fileChecker.check(reporter, 214 new File(outNames.currentName()), 215 new File(testFileInfo.goldName), 216 "Basic stream transform(1) into: " + outNames.currentName()); 217 if (fileCheckStatus != reporter.PASS_RESULT) 218 { 219 reporter.logWarningMsg("Basic stream transform(1) into: " + outNames.currentName() 220 + fileChecker.getExtendedInfo()); 221 } 222 223 // Validate transformer reuse 224 reporter.logTraceMsg("Basic stream transform(2)(" + QetestUtils.filenameToURL(testFileInfo.xmlName) + ", " 225 + QetestUtils.filenameToURL(testFileInfo.inputName) + ", " 226 + outNames.nextName()); 227 fos = new FileOutputStream(outNames.currentName()); 228 transformer.transform(new StreamSource(QetestUtils.filenameToURL(testFileInfo.xmlName)), 229 new StreamResult(fos)); 230 fos.close(); 231 fileCheckStatus = fileChecker.check(reporter, 232 new File(outNames.currentName()), 233 new File(testFileInfo.goldName), 234 "Basic stream transform(2) into: " + outNames.currentName()); 235 if (fileCheckStatus != reporter.PASS_RESULT) 236 { 237 reporter.logWarningMsg("Basic stream transform(2) into: " + outNames.currentName() 238 + fileChecker.getExtendedInfo()); 239 } 240 } 241 catch (Throwable t) 242 { 243 reporter.checkFail("Problem with simple stream transform"); 244 reporter.logThrowable(reporter.ERRORMSG, t, "Problem with simple stream transform"); 245 } 246 247 try 248 { 249 // Validate selected API's - primarily Parameters 250 Templates paramTemplates = factory.newTemplates(new StreamSource(QetestUtils.filenameToURL(paramFileInfo.inputName))); 251 Transformer paramTransformer = paramTemplates.newTransformer(); 252 String paramStr = "paramVal"; 253 paramTransformer.setParameter(PARAM1S, paramStr); 254 reporter.logTraceMsg("Just set " + PARAM1S + " to " + paramStr); 255 Object tmp = paramTransformer.getParameter(PARAM1S); // SPR SCUU4QWTVZ - returns an XObject - fixed 256 if (tmp == null) 257 { 258 reporter.checkFail(PARAM1S + " is still set to null!"); 259 } 260 else 261 { // Validate SPR SCUU4QWTVZ - should return the same type you set 262 if (tmp instanceof String) 263 { 264 reporter.checkObject(tmp, paramStr, PARAM1S + " is now set to ?" + tmp + "?"); 265 } 266 else 267 { 268 reporter.checkFail(PARAM1S + " is now ?" + tmp + "?, isa " + tmp.getClass().getName()); 269 } 270 } 271 272 // Verify simple re-set/get of a single parameter - new Integer 273 Integer paramInteger = new Integer(1234); 274 paramTransformer.setParameter(PARAM1S, paramInteger); // SPR SCUU4R3JGY - can't re-set 275 reporter.logTraceMsg("Just reset " + PARAM1S + " to new Integer(99)"); 276 tmp = null; 277 tmp = paramTransformer.getParameter(PARAM1S); 278 if (tmp == null) 279 { 280 reporter.checkFail(PARAM1S + " is still set to null!"); 281 } 282 else 283 { // Validate SPR SCUU4QWTVZ - should return the same type you set 284 if (tmp instanceof Integer) 285 { 286 reporter.checkObject(tmp, paramInteger, PARAM1S + " is now set to ?" + tmp + "?"); 287 } 288 else 289 { 290 reporter.checkFail(PARAM1S + " is now ?" + tmp + "?, isa " + tmp.getClass().getName()); 291 } 292 } 293 // Validate a transform with two params set 294 paramTransformer.setParameter(PARAM1N, "new-param1n-value"); 295 reporter.logTraceMsg("Just reset " + PARAM1N + " to new-param1n-value"); 296 297 reporter.logTraceMsg("Stream-param transform(" + QetestUtils.filenameToURL(paramFileInfo.xmlName) + ", " 298 + QetestUtils.filenameToURL(paramFileInfo.inputName) + ", " 299 + outNames.nextName()); 300 FileOutputStream fos = new FileOutputStream(outNames.currentName()); 301 paramTransformer.transform(new StreamSource(QetestUtils.filenameToURL(paramFileInfo.xmlName)), 302 new StreamResult(fos)); 303 fos.close(); 304 int fileCheckStatus = fileChecker.check(reporter, 305 new File(outNames.currentName()), 306 new File(paramFileInfo.goldName), 307 "Stream transform with params into: " + outNames.currentName()); 308 if (fileCheckStatus != reporter.PASS_RESULT) 309 { 310 reporter.logWarningMsg("Stream transform with params into: " + outNames.currentName() 311 + fileChecker.getExtendedInfo()); 312 } 313 // Validate params are still set after transform 314 tmp = paramTransformer.getParameter(PARAM1S); 315 reporter.checkObject(tmp, paramInteger, PARAM1S + " is now set to ?" + tmp + "?"); 316 tmp = paramTransformer.getParameter(PARAM1N); 317 reporter.checkObject(tmp, "new-param1n-value", PARAM1N + " is now set to ?" + tmp + "?"); 318 } 319 catch (Throwable t) 320 { 321 reporter.checkFail("Problem with parameters"); 322 reporter.logThrowable(reporter.ERRORMSG, t, "Problem with parameters"); 323 } 324 reporter.testCaseClose(); 325 return true; 326 } 327 328 329 /** 330 * Basic trax.dom transformWrapper. 331 * 332 * @return false if we should abort the test; true otherwise 333 */ testCase2()334 public boolean testCase2() 335 { 336 final String FLAVOR = "trax.dom"; 337 final String DESC = "Basic " + FLAVOR + " transformWrapper"; 338 reporter.testCaseInit(DESC); 339 try 340 { 341 testFileInfo.outputName = outNames.nextName(); 342 transformUsingFlavor(testFileInfo, FLAVOR); 343 fileChecker.check(reporter, 344 new File(testFileInfo.outputName), 345 new File(testFileInfo.goldName), 346 DESC +" into: " + testFileInfo.outputName); 347 348 } 349 catch (Throwable t) 350 { 351 reporter.logThrowable(reporter.ERRORMSG, t, DESC + " threw: "); 352 reporter.checkErr(DESC + " threw: " + t.toString()); 353 } 354 return true; 355 } 356 357 358 /** 359 * Basic trax.sax transformWrapper. 360 * 361 * @return false if we should abort the test; true otherwise 362 */ testCase3()363 public boolean testCase3() 364 { 365 final String FLAVOR = "trax.sax"; 366 final String DESC = "Basic " + FLAVOR + " transformWrapper"; 367 reporter.testCaseInit(DESC); 368 try 369 { 370 testFileInfo.outputName = outNames.nextName(); 371 transformUsingFlavor(testFileInfo, FLAVOR); 372 fileChecker.check(reporter, 373 new File(testFileInfo.outputName), 374 new File(testFileInfo.goldName), 375 DESC +" into: " + testFileInfo.outputName); 376 } 377 catch (Throwable t) 378 { 379 reporter.logThrowable(reporter.ERRORMSG, t, DESC + " threw: "); 380 reporter.checkErr(DESC + " threw: " + t.toString()); 381 } 382 reporter.testCaseClose(); 383 return true; 384 } 385 386 387 /** 388 * Basic trax.stream transformWrapper. 389 * 390 * @return false if we should abort the test; true otherwise 391 */ testCase4()392 public boolean testCase4() 393 { 394 final String FLAVOR = "trax.stream"; 395 final String DESC = "Basic " + FLAVOR + " transformWrapper"; 396 reporter.testCaseInit(DESC); 397 try 398 { 399 testFileInfo.outputName = outNames.nextName(); 400 transformUsingFlavor(testFileInfo, FLAVOR); 401 fileChecker.check(reporter, 402 new File(testFileInfo.outputName), 403 new File(testFileInfo.goldName), 404 DESC +" into: " + testFileInfo.outputName); 405 } 406 catch (Throwable t) 407 { 408 reporter.logThrowable(reporter.ERRORMSG, t, DESC + " threw: "); 409 reporter.checkErr(DESC + " threw: " + t.toString()); 410 } 411 reporter.testCaseClose(); 412 return true; 413 } 414 415 416 /** 417 * Basic performance measurements of sample files. 418 * @return false if we should abort the test; true otherwise 419 */ testCase5()420 public boolean testCase5() 421 { 422 String flavor = null; 423 final String DESC = "Simple performance measurement "; 424 reporter.testCaseInit(DESC); 425 // Reset the counting for outputNames for this testcase 426 outNames = new OutputNameManager(baseOutName + "Perf", ".out"); 427 try 428 { 429 long[] times = null; 430 Vector streamTimes = new Vector(); 431 Vector domTimes = new Vector(); 432 TransformWrapper transformWrapper = null; 433 434 flavor = "trax.stream"; 435 transformWrapper = TransformWrapperFactory.newWrapper(flavor); 436 transformWrapper.newProcessor(testProps); 437 reporter.logHashtable(Logger.TRACEMSG, transformWrapper.getProcessorInfo(), "wrapper.getProcessorInfo() for next transforms"); 438 439 // Repeat a few times with streams 440 for (int i = 1; i <= 5; i++) 441 { 442 perfFileInfo.outputName = outNames.nextName(); 443 reporter.logInfoMsg("perf-stream transform into " + perfFileInfo.outputName); 444 times = transformWrapper.transform(perfFileInfo.xmlName, perfFileInfo.inputName, perfFileInfo.outputName); 445 logPerfElem(times, perfFileInfo, flavor); 446 streamTimes.addElement(new Long(times[TransformWrapper.IDX_OVERALL])); 447 } 448 // Only bother checking the *last* iteration of perfs 449 fileChecker.check(reporter, 450 new File(perfFileInfo.outputName), 451 new File(perfFileInfo.goldName), 452 DESC + flavor + " into: " + perfFileInfo.outputName); 453 454 flavor = "trax.dom"; 455 transformWrapper = TransformWrapperFactory.newWrapper(flavor); 456 transformWrapper.newProcessor(testProps); 457 reporter.logHashtable(Logger.TRACEMSG, transformWrapper.getProcessorInfo(), "wrapper.getProcessorInfo() for next transforms"); 458 459 // Repeat a few times with DOMs 460 for (int i = 1; i <= 5; i++) 461 { 462 perfFileInfo.outputName = outNames.nextName(); 463 reporter.logInfoMsg("perf-dom transform into " + perfFileInfo.outputName); 464 times = transformWrapper.transform(perfFileInfo.xmlName, perfFileInfo.inputName, perfFileInfo.outputName); 465 logPerfElem(times, perfFileInfo, flavor); 466 domTimes.addElement(new Long(times[TransformWrapper.IDX_OVERALL])); 467 } 468 // Only bother checking the *last* iteration of perfs 469 fileChecker.check(reporter, 470 new File(perfFileInfo.outputName), 471 new File(perfFileInfo.goldName), 472 DESC + flavor + " into: " + perfFileInfo.outputName); 473 474 // Log a big message at the very end to make it easier to see 475 StringBuffer buf = new StringBuffer("Minitest.testCase5 PERFORMANCE NUMBERS\n"); 476 buf.append(" STREAM OVERALL TIMES: "); 477 for (Enumeration elements = streamTimes.elements(); 478 elements.hasMoreElements(); /* no increment portion */ ) 479 { 480 buf.append(elements.nextElement()); 481 buf.append(", "); 482 } 483 buf.append("\n"); 484 buf.append(" DOM OVERALL TIMES: "); 485 for (Enumeration elements = domTimes.elements(); 486 elements.hasMoreElements(); /* no increment portion */ ) 487 { 488 buf.append(elements.nextElement()); 489 buf.append(", "); 490 } 491 buf.append("\n"); 492 reporter.logArbitrary(Logger.CRITICALMSG, buf.toString()); 493 } 494 catch (Throwable t) 495 { 496 reporter.logThrowable(reporter.ERRORMSG, t, DESC + flavor + " threw: "); 497 reporter.checkErr(DESC + flavor + " threw: " + t.toString()); 498 } 499 reporter.testCaseClose(); 500 return true; 501 } 502 503 504 /** 505 * Worker method to use a TransformWrapper to transform a file. 506 * 507 * @param fileInfo inputName, xmlName of file to test 508 * @param flavor of TransformWrapper to use 509 * @return log number of overall millisec for transform. 510 */ transformUsingFlavor(XSLTestfileInfo fileInfo, String flavor)511 public void transformUsingFlavor(XSLTestfileInfo fileInfo, String flavor) 512 throws Exception 513 { 514 TransformWrapper transformWrapper = TransformWrapperFactory.newWrapper(flavor); 515 transformWrapper.newProcessor(testProps); 516 reporter.logHashtable(Logger.TRACEMSG, transformWrapper.getProcessorInfo(), "wrapper.getProcessorInfo() for next transform"); 517 if (null == fileInfo.inputName) 518 { 519 // presume it's an embedded test 520 reporter.logInfoMsg("transformEmbedded(" + fileInfo.xmlName + ", " + fileInfo.outputName + ")"); 521 long[] times = transformWrapper.transformEmbedded(fileInfo.xmlName, fileInfo.outputName); 522 logPerfElem(times, fileInfo, flavor); 523 } 524 else 525 { 526 // presume it's a normal stylesheet test 527 reporter.logInfoMsg("transform(" + fileInfo.xmlName + ", " + fileInfo.inputName + ", " + fileInfo.outputName + ")"); 528 long[] times = transformWrapper.transform(fileInfo.xmlName, fileInfo.inputName, fileInfo.outputName); 529 logPerfElem(times, fileInfo, flavor); 530 } 531 532 } 533 534 535 /** 536 * Worker method to output a <perf> element. 537 * @return false if we should abort the test; true otherwise 538 */ logPerfElem(long[] times, XSLTestfileInfo fileInfo, String flavor)539 public void logPerfElem(long[] times, XSLTestfileInfo fileInfo, String flavor) 540 { 541 Hashtable attrs = new Hashtable(); 542 // Add general information about this perf elem 543 attrs.put("UniqRunid", testProps.getProperty("runId", "runId;none")); 544 attrs.put("processor", flavor); 545 // idref is the individual filename 546 attrs.put("idref", (new File(fileInfo.inputName)).getName()); 547 // inputName is the actual name we gave to the processor 548 attrs.put("inputName", fileInfo.inputName); 549 550 // Add all available specific timing data as well 551 for (int i = 0; i < times.length; i++) 552 { 553 // Only log items that have actual timing data 554 if (TransformWrapper.TIME_UNUSED != times[i]) 555 { 556 attrs.put(TransformWrapperHelper.getTimeArrayDesc(i), 557 new Long(times[i])); 558 } 559 } 560 561 // Log the element out; note formatting matches 562 reporter.logElement(Logger.STATUSMSG, "perf", attrs, fileInfo.description); 563 } 564 565 566 /** 567 * Convenience method to print out usage information - update if needed. 568 * @return String denoting usage of this test class 569 */ usage()570 public String usage() 571 { 572 return ("Common [optional] options supported by Minitest:\n" 573 + "(Note: assumes inputDir=.\\tests\\api)\n" 574 + super.usage()); // Grab our parent classes usage as well 575 } 576 577 578 /** 579 * Main method to run test from the command line - can be left alone. 580 * @param args command line argument array 581 */ main(String[] args)582 public static void main(String[] args) 583 { 584 Minitest app = new Minitest(); 585 app.doMain(args); 586 } 587 } 588