1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts; 18 19 import com.android.cts.TestDevice.DeviceParameterCollector; 20 21 import org.w3c.dom.Document; 22 import org.w3c.dom.Node; 23 import org.w3c.dom.ProcessingInstruction; 24 25 import java.io.File; 26 import java.net.InetAddress; 27 import java.net.UnknownHostException; 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.Date; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 34 import javax.xml.parsers.DocumentBuilderFactory; 35 36 /** 37 * Store the information of a test plan. 38 */ 39 public class TestSessionLog extends XMLResourceHandler { 40 private static final String EXPR_TEST_FAILED = ".+\\((\\S+):(\\d+)\\)"; 41 private static Pattern mTestFailedPattern = Pattern.compile(EXPR_TEST_FAILED); 42 private static final String ATTRIBUTE_NAME = "name"; 43 static final String ATTRIBUTE_RESULT = "result"; 44 private static final String ATTRIBUTE_VERSION = "version"; 45 private static final String ATTRIBUTE_DIGEST = "digest"; 46 private static final String ATTRIBUTE_KNOWN_FAILURE = "KnownFailure"; 47 48 public static final String CTS_RESULT_FILE_NAME = "testResult.xml"; 49 private static final String CTS_RESULT_FILE_VERSION = "1.2"; 50 51 static final String ATTRIBUTE_STARTTIME = "starttime"; 52 static final String ATTRIBUTE_ENDTIME = "endtime"; 53 static final String ATTRIBUTE_TESTPLAN = "testPlan"; 54 static final String ATTRIBUTE_RESOLUTION = "resolution"; 55 static final String ATTRIBUTE_SUBSCRIBER_ID = "subscriberId"; 56 static final String ATTRIBUTE_DEVICE_ID = "deviceID"; 57 static final String ATTRIBUTE_BUILD_ID = "buildID"; 58 static final String ATTRIBUTE_BUILD_VERSION = "buildVersion"; 59 static final String ATTRIBUTE_ANDROID_PLATFORM_VERSION = "androidPlatformVersion"; 60 static final String ATTRIBUTE_LOCALES = "locales"; 61 static final String ATTRIBUTE_XDPI = "Xdpi"; 62 static final String ATTRIBUTE_YDPI = "Ydpi"; 63 static final String ATTRIBUTE_TOUCH = "touch"; 64 static final String ATTRIBUTE_NAVIGATION = "navigation"; 65 static final String ATTRIBUTE_KEYPAD = "keypad"; 66 static final String ATTRIBUTE_NETWORK = "network"; 67 static final String ATTRIBUTE_IMEI = "imei"; 68 static final String ATTRIBUTE_IMSI = "imsi"; 69 static final String ATTRIBUTE_BUILD_NAME = "buildName"; 70 static final String ATTRIBUTE_ARCH = "arch"; 71 static final String ATTRIBUTE_VALUE = "value"; 72 73 static final String ATTRIBUTE_PASS = "pass"; 74 static final String ATTRIBUTE_FAILED = "failed"; 75 static final String ATTRIBUTE_TIMEOUT = "timeout"; 76 static final String ATTRIBUTE_NOT_EXECUTED = "notExecuted"; 77 78 static final String TAG_DEVICEINFO = "DeviceInfo"; 79 static final String TAG_HOSTINFO = "HostInfo"; 80 static final String TAG_OSINFO = "Os"; 81 static final String TAG_JAVA = "Java"; 82 static final String TAG_CTS = "Cts"; 83 static final String TAG_INTVALUE = "IntValue"; 84 static final String TAG_SUMMARY = "Summary"; 85 static final String TAG_SCREEN = "Screen"; 86 static final String TAG_BUILD_INFO = "BuildInfo"; 87 static final String TAG_PHONE_SUB_INFO = "PhoneSubInfo"; 88 static final String TAG_TEST_RESULT = "TestResult"; 89 static final String TAG_TESTPACKAGE = "TestPackage"; 90 static final String TAG_TESTSUITE = "TestSuite"; 91 static final String TAG_TESTCASE = "TestCase"; 92 static final String TAG_FAILED_SCENE = "FailedScene"; 93 static final String TAG_STACK_TRACE = "StackTrace"; 94 static final String TAG_FAILED_MESSAGE = "message"; 95 96 private Collection<TestPackage> mTestPackages; 97 private Date mSessionStartTime; 98 private Date mSessionEndTime; 99 private String mResultPath; 100 private String mResultDir; 101 private String mTestPlanName; 102 103 private ArrayList<DeviceParameterCollector> mDeviceParameterBase; 104 105 public TestSessionLog(final Collection<TestPackage> packages, final String testPlanName) { 106 mTestPackages = packages; 107 108 mDeviceParameterBase = new ArrayList<TestDevice.DeviceParameterCollector>(); 109 mTestPlanName = testPlanName; 110 111 mSessionStartTime = new Date(); 112 mSessionEndTime = new Date(); 113 } 114 115 /** 116 * Get the test plan name. 117 * 118 * @return The test plan name. 119 */ 120 public String getTestPlanName() { 121 return mTestPlanName; 122 } 123 124 /** 125 * Get all result of this session. 126 * 127 * @return All the tests with a result code of this session. 128 */ 129 public Collection<Test> getAllResults() { 130 if (mTestPackages == null || mTestPackages.size() == 0) { 131 return null; 132 } 133 134 ArrayList<Test> results = new ArrayList<Test>(); 135 for (TestPackage p : mTestPackages) { 136 results.addAll(p.getTests()); 137 } 138 139 return results; 140 } 141 142 /** 143 * Get test list according to the result type code. 144 * 145 * @param resCode The result code. 146 * @return The list of {@link Test}. 147 */ 148 public Collection<Test> getTestList(int resCode) { 149 if ((resCode < CtsTestResult.CODE_FIRST) 150 || (resCode > CtsTestResult.CODE_LAST)) { 151 return null; 152 } 153 154 ArrayList<Test> tests = new ArrayList<Test>(); 155 for (Test test : getAllResults()) { 156 if (resCode == test.getResult().getResultCode()) { 157 tests.add(test); 158 } 159 } 160 161 return tests; 162 } 163 164 /** 165 * Get TestSession start time 166 * 167 * @return The start time. 168 */ 169 public Date getStartTime() { 170 return mSessionStartTime; 171 } 172 173 /** 174 * Get TestSession end time 175 * 176 * @return The end time. 177 */ 178 public Date getEndTime() { 179 return mSessionEndTime; 180 } 181 182 /** 183 * Get test packages. 184 * 185 * @return The test packages. 186 */ 187 public Collection<TestPackage> getTestPackages() { 188 return mTestPackages; 189 } 190 191 /** 192 * Get the path to the XML result file. 193 * 194 * @return The result path. 195 */ 196 public String getResultPath() { 197 return mResultPath; 198 } 199 200 /** 201 * Get the result directory. This is the directory that all result files 202 * should go into. 203 */ 204 public String getResultDir() { 205 return mResultDir; 206 } 207 208 /** 209 * set TestSession start time 210 * 211 * @param time The start time. 212 */ 213 public void setStartTime(final long time) { 214 mSessionStartTime.setTime(time); 215 216 String startTimeStr = HostUtils.getFormattedTimeString(time, "_", ".", "."); 217 mResultDir = HostConfig.getInstance().getResultRepository().getRoot() 218 + File.separator + startTimeStr; 219 mResultPath = mResultDir + File.separator + CTS_RESULT_FILE_NAME; 220 // Make sure the result directory exists 221 new File(mResultDir).mkdirs(); 222 } 223 224 /** 225 * set TestSession end time 226 * 227 * @param time The end time. 228 */ 229 public void setEndTime(final long time) { 230 mSessionEndTime.setTime(time); 231 } 232 233 /** 234 * Calling this functions indicates that the TestSession is complete. This 235 * indicates to the TestSessionLog that it is time to store the results 236 * to the filesystem. 237 */ 238 public void sessionComplete() { 239 try { 240 writeToFile(new File(mResultPath), createResultDoc()); 241 // Now zip up the results directory so we have something nice 242 // that people can upload. 243 HostUtils.zipUpDirectory(mResultDir, 244 mResultDir + ".zip", 245 new HostUtils.ZipFilenameTransformer() { 246 public String transform(String filename) { 247 if (filename.startsWith(mResultDir)) { 248 return filename.substring(mResultDir.length() + 1); 249 } 250 return filename; 251 } 252 }); 253 } catch (Exception e) { 254 Log.e("Got exception when trying to write to result file", e); 255 } 256 HostConfig.getInstance().extractResultResources(mResultDir); 257 } 258 259 /** 260 * Create result Doc in XML format. 261 * 262 * @return Result document. 263 */ 264 protected Document createResultDoc() { 265 try { 266 267 Document doc = DocumentBuilderFactory.newInstance() 268 .newDocumentBuilder().newDocument(); 269 ProcessingInstruction pr = doc.createProcessingInstruction( 270 "xml-stylesheet", "type=\"text/xsl\" href=\"cts_result.xsl\""); 271 doc.appendChild(pr); 272 Node root = doc.createElement(TAG_TEST_RESULT); 273 doc.appendChild(root); 274 275 setAttribute(doc, root, ATTRIBUTE_VERSION, CTS_RESULT_FILE_VERSION); 276 setAttribute(doc, root, ATTRIBUTE_STARTTIME, HostUtils.dateToString(mSessionStartTime)); 277 setAttribute(doc, root, ATTRIBUTE_ENDTIME, HostUtils.dateToString(mSessionEndTime)); 278 setAttribute(doc, root, ATTRIBUTE_TESTPLAN, mTestPlanName); 279 280 // set device information 281 for (int i = 0; i < mDeviceParameterBase.size(); i ++) { 282 DeviceParameterCollector bldInfo = mDeviceParameterBase.get(i); 283 // set device setting 284 Node deviceSettingNode = doc.createElement(TAG_DEVICEINFO); 285 286 Node screenNode = doc.createElement(TAG_SCREEN); 287 setAttribute(doc, screenNode, ATTRIBUTE_RESOLUTION, bldInfo.getScreenResolution()); 288 deviceSettingNode.appendChild(screenNode); 289 Node simCardNode = doc.createElement(TAG_PHONE_SUB_INFO); 290 setAttribute(doc, simCardNode, ATTRIBUTE_SUBSCRIBER_ID, bldInfo.getPhoneNumber()); 291 deviceSettingNode.appendChild(simCardNode); 292 root.appendChild(deviceSettingNode); 293 294 Node devInfoNode = doc.createElement(TAG_BUILD_INFO); 295 setAttribute(doc, devInfoNode, ATTRIBUTE_DEVICE_ID, bldInfo.getSerialNumber()); 296 setAttribute(doc, devInfoNode, ATTRIBUTE_BUILD_ID, bldInfo.getBuildId()); 297 setAttribute(doc, devInfoNode, ATTRIBUTE_BUILD_NAME, bldInfo.getProductName()); 298 setAttribute(doc, devInfoNode, ATTRIBUTE_BUILD_VERSION, 299 bldInfo.getBuildVersion()); 300 setAttribute(doc, devInfoNode, ATTRIBUTE_ANDROID_PLATFORM_VERSION, 301 bldInfo.getAndroidPlatformVersion()); 302 setAttribute(doc, devInfoNode, ATTRIBUTE_LOCALES, bldInfo.getLocales()); 303 setAttribute(doc, devInfoNode, ATTRIBUTE_XDPI, bldInfo.getXdpi()); 304 setAttribute(doc, devInfoNode, ATTRIBUTE_YDPI, bldInfo.getYdpi()); 305 setAttribute(doc, devInfoNode, ATTRIBUTE_TOUCH, bldInfo.getTouchInfo()); 306 setAttribute(doc, devInfoNode, ATTRIBUTE_NAVIGATION, bldInfo.getNavigation()); 307 setAttribute(doc, devInfoNode, ATTRIBUTE_KEYPAD, bldInfo.getKeypad()); 308 setAttribute(doc, devInfoNode, ATTRIBUTE_NETWORK, bldInfo.getNetwork()); 309 setAttribute(doc, devInfoNode, ATTRIBUTE_IMEI, bldInfo.getIMEI()); 310 setAttribute(doc, devInfoNode, ATTRIBUTE_IMSI, bldInfo.getIMSI()); 311 312 setAttribute(doc, devInfoNode, 313 DeviceParameterCollector.BUILD_FINGERPRINT, bldInfo.getBuildFingerPrint()); 314 setAttribute(doc, devInfoNode, 315 DeviceParameterCollector.BUILD_TYPE, bldInfo.getBuildType()); 316 setAttribute(doc, devInfoNode, 317 DeviceParameterCollector.BUILD_MODEL, bldInfo.getBuildModel()); 318 setAttribute(doc, devInfoNode, 319 DeviceParameterCollector.BUILD_BRAND, bldInfo.getBuildBrand()); 320 setAttribute(doc, devInfoNode, 321 DeviceParameterCollector.BUILD_BOARD, bldInfo.getBuildBoard()); 322 setAttribute(doc, devInfoNode, 323 DeviceParameterCollector.BUILD_DEVICE, bldInfo.getBuildDevice()); 324 setAttribute(doc, devInfoNode, 325 DeviceParameterCollector.BUILD_ABI, bldInfo.getBuildAbi()); 326 setAttribute(doc, devInfoNode, 327 DeviceParameterCollector.BUILD_ABI2, bldInfo.getBuildAbi2()); 328 329 deviceSettingNode.appendChild(devInfoNode); 330 } 331 332 Node hostInfo = doc.createElement(TAG_HOSTINFO); 333 root.appendChild(hostInfo); 334 String hostName = ""; 335 try { 336 hostName = InetAddress.getLocalHost().getHostName(); 337 } catch (UnknownHostException ignored) {} 338 setAttribute(doc, hostInfo, ATTRIBUTE_NAME, hostName); 339 Node osInfo = doc.createElement(TAG_OSINFO); 340 hostInfo.appendChild(osInfo); 341 setAttribute(doc, osInfo, ATTRIBUTE_NAME, System.getProperty("os.name")); 342 setAttribute(doc, osInfo, ATTRIBUTE_VERSION, System.getProperty("os.version")); 343 setAttribute(doc, osInfo, ATTRIBUTE_ARCH, System.getProperty("os.arch")); 344 Node javaInfo = doc.createElement(TAG_JAVA); 345 hostInfo.appendChild(javaInfo); 346 setAttribute(doc, javaInfo, ATTRIBUTE_NAME, System.getProperty("java.vendor")); 347 setAttribute(doc, javaInfo, ATTRIBUTE_VERSION, System.getProperty("java.version")); 348 Node ctsInfo = doc.createElement(TAG_CTS); 349 hostInfo.appendChild(ctsInfo); 350 setAttribute(doc, ctsInfo, ATTRIBUTE_VERSION, Version.asString()); 351 for (HostConfig.Ints i : HostConfig.Ints.values()) { 352 Node intValue = doc.createElement(TAG_INTVALUE); 353 ctsInfo.appendChild(intValue); 354 setAttribute(doc, intValue, ATTRIBUTE_NAME, i.name()); 355 setAttribute(doc, intValue, ATTRIBUTE_VALUE, i.value()); 356 } 357 358 int passNum = getTestList(CtsTestResult.CODE_PASS).size(); 359 int failNum = getTestList(CtsTestResult.CODE_FAIL).size(); 360 int notExecutedNum = getTestList(CtsTestResult.CODE_NOT_EXECUTED).size(); 361 int timeOutNum = getTestList(CtsTestResult.CODE_TIMEOUT).size(); 362 Node summaryNode = doc.createElement(TAG_SUMMARY); 363 root.appendChild(summaryNode); 364 setAttribute(doc, summaryNode, ATTRIBUTE_PASS, passNum); 365 setAttribute(doc, summaryNode, ATTRIBUTE_FAILED, failNum); 366 setAttribute(doc, summaryNode, ATTRIBUTE_NOT_EXECUTED, notExecutedNum); 367 setAttribute(doc, summaryNode, ATTRIBUTE_TIMEOUT, timeOutNum); 368 369 for (TestPackage testPackage : mTestPackages) { 370 Node testPackageNode = doc.createElement(TAG_TESTPACKAGE); 371 setAttribute(doc, testPackageNode, ATTRIBUTE_NAME, testPackage.getAppBinaryName()); 372 setAttribute(doc, testPackageNode, TestSessionBuilder.ATTRIBUTE_APP_PACKAGE_NAME, 373 testPackage.getAppPackageName()); 374 setAttribute(doc, testPackageNode, ATTRIBUTE_DIGEST, 375 testPackage.getMessageDigest()); 376 377 if (testPackage instanceof SignatureCheckPackage) { 378 setAttribute(doc, testPackageNode, 379 TestSessionBuilder.ATTRIBUTE_SIGNATURE_CHECK, "true"); 380 } 381 382 for (TestSuite testSuite : testPackage.getTestSuites()) { 383 outputTestSuite(doc, testPackage, testPackageNode, testSuite); 384 } 385 root.appendChild(testPackageNode); 386 } 387 388 return doc; 389 } catch (Exception e) { 390 Log.e("create result doc failed", e); 391 } 392 return null; 393 } 394 395 /** 396 * Output TestSuite and result to XML DOM Document. 397 * 398 * @param doc The document. 399 * @param parentNode The parent node. 400 * @param testSuite The test suite. 401 */ 402 private void outputTestSuite(final Document doc, 403 final TestPackage testPackage, final Node parentNode, 404 TestSuite testSuite) { 405 406 Collection<TestSuite> subSuites = testSuite.getSubSuites(); 407 Collection<TestCase> testCases = testSuite.getTestCases(); 408 409 Node testSuiteNode = doc.createElement(TAG_TESTSUITE); 410 setAttribute(doc, testSuiteNode, ATTRIBUTE_NAME, testSuite.getName()); 411 412 for (TestCase testCase : testCases) { 413 Node testCaseNode = doc.createElement(TAG_TESTCASE); 414 testSuiteNode.appendChild(testCaseNode); 415 setAttribute(doc, testCaseNode, ATTRIBUTE_NAME, testCase.getName()); 416 setAttribute(doc, testCaseNode, TestSessionBuilder.ATTRIBUTE_PRIORITY, 417 testCase.getPriority()); 418 419 Collection<Test> tests = testCase.getTests(); 420 for (Test test : tests) { 421 Node testNode = doc.createElement(TestSessionBuilder.TAG_TEST); 422 testCaseNode.appendChild(testNode); 423 424 if (test.isKnownFailure()) { 425 setAttribute(doc, testNode, ATTRIBUTE_KNOWN_FAILURE, test.getKnownFailure()); 426 } 427 428 CtsTestResult result = test.getResult(); 429 setAttribute(doc, testNode, ATTRIBUTE_NAME, test.getName()); 430 setAttribute(doc, testNode, ATTRIBUTE_RESULT, result.getResultString()); 431 setAttribute(doc, testNode, ATTRIBUTE_STARTTIME, 432 new Date(test.getStartTime()).toString()); 433 setAttribute(doc, testNode, ATTRIBUTE_ENDTIME, 434 new Date(test.getEndTime()).toString()); 435 436 String failedMessage = result.getFailedMessage(); 437 438 if (failedMessage != null) { 439 // failure message may contain control characters < 0x20 that get translated 440 // into illegal XML character entities. Replace them first. 441 failedMessage = HostUtils.replaceControlChars(failedMessage); 442 Node failedMessageNode = doc.createElement(TAG_FAILED_SCENE); 443 testNode.appendChild(failedMessageNode); 444 setAttribute(doc, failedMessageNode,TAG_FAILED_MESSAGE, failedMessage); 445 446 String stackTrace = result.getStackTrace(); 447 if (stackTrace != null) { 448 Node stackTraceNode = doc.createElement(TAG_STACK_TRACE); 449 failedMessageNode.appendChild(stackTraceNode); 450 Node stackTraceTextNode = doc.createTextNode(stackTrace); 451 stackTraceNode.appendChild(stackTraceTextNode); 452 } 453 } 454 } 455 } 456 457 for (TestSuite subSuite : subSuites) { 458 outputTestSuite(doc, testPackage, testSuiteNode, subSuite); 459 parentNode.appendChild(testSuiteNode); 460 } 461 parentNode.appendChild(testSuiteNode); 462 } 463 464 /** 465 * Fetch failed file name and line number 466 * 467 * @param failedResult failed message 468 * @return failed file name and line number 469 */ 470 public final static String[] getFailedLineNumber(final String failedResult) { 471 Matcher m = mTestFailedPattern.matcher(failedResult); 472 if (m.matches()) { 473 return new String[]{m.group(1), m.group(2)}; 474 } 475 return null; 476 } 477 478 /** 479 * set the device information of a specific device 480 * 481 * @param dInfo The device information. 482 */ 483 public void setDeviceInfo(final TestDevice.DeviceParameterCollector dInfo) { 484 for (DeviceParameterCollector collector : mDeviceParameterBase) { 485 if (collector.getSerialNumber().equals(dInfo.getSerialNumber())) { 486 //if there has information for the device with given serial number, 487 //replace it with the new information. 488 mDeviceParameterBase.remove(collector); 489 break; 490 } 491 } 492 mDeviceParameterBase.add(dInfo); 493 } 494 } 495