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; 23 24 import java.io.File; 25 26 /** 27 * Testlet superclass for testing URI or file based resources. 28 * 29 * This class is broken up into common worker methods to make 30 * subclassing easier for alternate testing algoritims. 31 * Individual subclasses may be implemented to test various 32 * programs that somehow can be tested by taking an input file 33 * and processing it, creating an output file, and then comparing 34 * the output to a known good gold file. 35 * 36 * @author Shane_Curcuru@us.ibm.com 37 * @version $Id$ 38 */ 39 public class FileTestlet extends TestletImpl 40 { 41 // Initialize our classname for TestletImpl's main() method 42 static { thisClassName = "org.apache.qetest.FileTestlet"; } 43 44 // Initialize our defaultDatalet 45 { defaultDatalet = (Datalet)new FileDatalet(); } 46 47 /** 48 * Accesor method for a brief description of this test. 49 * 50 * @return String describing what this FileTestlet does. 51 */ getDescription()52 public String getDescription() 53 { 54 return "FileTestlet"; 55 } 56 57 58 /** 59 * Run this FileTestlet: execute it's test and return. 60 * 61 * Calls various worker methods to perform the basic steps of: 62 * initDatalet, testDatalet, checkDatalet; 63 * catch... {handleException} 64 * 65 * @param Datalet to use as data point for the test. 66 */ execute(Datalet d)67 public void execute(Datalet d) 68 { 69 // Ensure we have the correct kind of datalet 70 FileDatalet datalet = null; 71 try 72 { 73 datalet = (FileDatalet)d; 74 } 75 catch (ClassCastException e) 76 { 77 logger.checkErr("Datalet provided is not a FileDatalet; cannot continue with " + d); 78 return; 79 } 80 81 // Perform any general setup needed... 82 if (!initDatalet(datalet)) 83 return; 84 85 try 86 { 87 // Perform the operation on the product under test.. 88 testDatalet(datalet); 89 90 // ...and compare with gold data 91 checkDatalet(datalet); 92 } 93 // Handle any exceptions from the testing 94 catch (Throwable t) 95 { 96 handleException(datalet, t); 97 return; 98 } 99 } 100 101 102 /** 103 * Worker method to perform any initialization needed. 104 * 105 * Subclasses might pre-verify the existence of the input and 106 * gold files or delete any pre-existing outputs in the 107 * datalet before testing. 108 * 109 * @param datalet to test with 110 * @return true if OK, false if test should be aborted; if 111 * false, this method must log a fail or error 112 */ initDatalet(FileDatalet datalet)113 protected boolean initDatalet(FileDatalet datalet) 114 { 115 //@todo validate our Datalet - ensure it has valid 116 // and/or existing files available. 117 118 // Cleanup outName only if asked to - delete the file on disk 119 // Optimization: this takes extra time and often is not 120 // needed, so only do this if the option is set 121 if ("true".equalsIgnoreCase(datalet.getOptions().getProperty("deleteOutFile"))) 122 { 123 String output = datalet.getOutput(); 124 try 125 { 126 boolean btmp = (new File(output)).delete(); 127 logger.logMsg(logger.TRACEMSG, "initDatalet delete: " + output 128 + " status: " + btmp); 129 } 130 catch (SecurityException se) 131 { 132 logger.logMsg(logger.WARNINGMSG, "initDatalet delete: " + output 133 + " threw: " + se.toString()); 134 } 135 } 136 return true; 137 } 138 139 140 /** 141 * Worker method to actually perform the test operation. 142 * 143 * Subclasses must (obviously) override this. They should 144 * perform whatever actions are needed to process the input 145 * into an output, logging any status along the way. 146 * Note that validation of the output file is handled later 147 * in checkDatalet. 148 * 149 * @param datalet to test with 150 * @throws allows any underlying exception to be thrown 151 */ testDatalet(FileDatalet datalet)152 protected void testDatalet(FileDatalet datalet) 153 throws Exception 154 { 155 logger.logMsg(Logger.TRACEMSG, getCheckDescription(datalet)); 156 157 // Perform the test operation here - you must subclass this! 158 } 159 160 161 /** 162 * Worker method to validate output resource with gold. 163 * 164 * Logs out applicable info while validating output file. 165 * Attempts to use datalet.getOptions.get("fileCheckerImpl") 166 * or datalet.getOptions.getProperty("fileChecker") to get 167 * a CheckService for the output; if that fails, it uses a 168 * default QetestFactory.newCheckService(). 169 * 170 * @param datalet to test with 171 * @throws allows any underlying exception to be thrown 172 */ checkDatalet(FileDatalet datalet)173 protected void checkDatalet(FileDatalet datalet) 174 throws Exception 175 { 176 // See if the datalet already has a fileChecker to use... 177 CheckService fileChecker = (CheckService)datalet.getOptions().get("fileCheckerImpl"); 178 // ...if not, look for a default classname to use... 179 if (null == fileChecker) 180 { 181 String clazzName = datalet.getOptions().getProperty("fileChecker"); 182 if (null != clazzName) 183 { 184 // ...find and create a class of the default classname given 185 Class fClazz = QetestUtils.testClassForName(clazzName, QetestUtils.defaultPackages, null); 186 fileChecker = (CheckService)fClazz.newInstance(); 187 } 188 else 189 { 190 //...If all else failed, simply get a default one from the factory 191 fileChecker = QetestFactory.newCheckService(logger, QetestFactory.TYPE_FILES); 192 } 193 // Apply any testing options to the fileChecker 194 fileChecker.applyAttributes(datalet.getOptions()); 195 // Note assumption that if we got the fileCheckerImpl 196 // directly from the datalet that we do not need to 197 // set the Attributes here again 198 } 199 200 int result = fileChecker.check(logger, 201 new File(datalet.getOutput()), 202 new File(datalet.getGold()), 203 getCheckDescription(datalet)); 204 205 //@todo if needed, we can put additional processing here 206 // to output special logging in case of results that are fail 207 } 208 209 210 /** 211 * Worker method to validate or log exceptions thrown by testDatalet. 212 * 213 * Provided so subclassing is simpler; our implementation merely 214 * calls checkErr and logs the exception. 215 * 216 * @param datalet to test with 217 * @param e Throwable that was thrown 218 */ handleException(FileDatalet datalet, Throwable t)219 protected void handleException(FileDatalet datalet, Throwable t) 220 { 221 // Put the logThrowable first, so it appears before 222 // the Fail record, and gets color-coded 223 logger.logThrowable(Logger.ERRORMSG, t, getCheckDescription(datalet) + " threw"); 224 logger.checkErr(getCheckDescription(datalet) 225 + " threw: " + t.toString()); 226 } 227 228 229 /** 230 * Worker method to construct a description. 231 * 232 * Simply concatenates useful info to override getDescription(). 233 * 234 * @param datalet to test with 235 * @return simple concatenation of our desc and datalet's desc 236 */ getCheckDescription(FileDatalet datalet)237 protected String getCheckDescription(FileDatalet datalet) 238 { 239 return getDescription() 240 + ": " 241 + datalet.getDescription(); 242 } 243 } // end of class FileTestlet 244 245