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 TestSessionLog(final Collection<TestPackage> packages, final String testPlanName)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 */ getTestPlanName()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 */ getAllResults()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 */ getTestList(int resCode)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 */ getStartTime()169 public Date getStartTime() { 170 return mSessionStartTime; 171 } 172 173 /** 174 * Get TestSession end time 175 * 176 * @return The end time. 177 */ getEndTime()178 public Date getEndTime() { 179 return mSessionEndTime; 180 } 181 182 /** 183 * Get test packages. 184 * 185 * @return The test packages. 186 */ getTestPackages()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 */ getResultPath()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 */ getResultDir()204 public String getResultDir() { 205 return mResultDir; 206 } 207 208 /** 209 * set TestSession start time 210 * 211 * @param time The start time. 212 */ setStartTime(final long time)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 */ setEndTime(final long time)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 */ sessionComplete()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 */ createResultDoc()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 325 deviceSettingNode.appendChild(devInfoNode); 326 } 327 328 Node hostInfo = doc.createElement(TAG_HOSTINFO); 329 root.appendChild(hostInfo); 330 String hostName = ""; 331 try { 332 hostName = InetAddress.getLocalHost().getHostName(); 333 } catch (UnknownHostException ignored) {} 334 setAttribute(doc, hostInfo, ATTRIBUTE_NAME, hostName); 335 Node osInfo = doc.createElement(TAG_OSINFO); 336 hostInfo.appendChild(osInfo); 337 setAttribute(doc, osInfo, ATTRIBUTE_NAME, System.getProperty("os.name")); 338 setAttribute(doc, osInfo, ATTRIBUTE_VERSION, System.getProperty("os.version")); 339 setAttribute(doc, osInfo, ATTRIBUTE_ARCH, System.getProperty("os.arch")); 340 Node javaInfo = doc.createElement(TAG_JAVA); 341 hostInfo.appendChild(javaInfo); 342 setAttribute(doc, javaInfo, ATTRIBUTE_NAME, System.getProperty("java.vendor")); 343 setAttribute(doc, javaInfo, ATTRIBUTE_VERSION, System.getProperty("java.version")); 344 Node ctsInfo = doc.createElement(TAG_CTS); 345 hostInfo.appendChild(ctsInfo); 346 setAttribute(doc, ctsInfo, ATTRIBUTE_VERSION, Version.asString()); 347 for (HostConfig.Ints i : HostConfig.Ints.values()) { 348 Node intValue = doc.createElement(TAG_INTVALUE); 349 ctsInfo.appendChild(intValue); 350 setAttribute(doc, intValue, ATTRIBUTE_NAME, i.name()); 351 setAttribute(doc, intValue, ATTRIBUTE_VALUE, i.value()); 352 } 353 354 int passNum = getTestList(CtsTestResult.CODE_PASS).size(); 355 int failNum = getTestList(CtsTestResult.CODE_FAIL).size(); 356 int notExecutedNum = getTestList(CtsTestResult.CODE_NOT_EXECUTED).size(); 357 int timeOutNum = getTestList(CtsTestResult.CODE_TIMEOUT).size(); 358 Node summaryNode = doc.createElement(TAG_SUMMARY); 359 root.appendChild(summaryNode); 360 setAttribute(doc, summaryNode, ATTRIBUTE_PASS, passNum); 361 setAttribute(doc, summaryNode, ATTRIBUTE_FAILED, failNum); 362 setAttribute(doc, summaryNode, ATTRIBUTE_NOT_EXECUTED, notExecutedNum); 363 setAttribute(doc, summaryNode, ATTRIBUTE_TIMEOUT, timeOutNum); 364 365 for (TestPackage testPackage : mTestPackages) { 366 Node testPackageNode = doc.createElement(TAG_TESTPACKAGE); 367 setAttribute(doc, testPackageNode, ATTRIBUTE_NAME, testPackage.getAppBinaryName()); 368 setAttribute(doc, testPackageNode, TestSessionBuilder.ATTRIBUTE_APP_PACKAGE_NAME, 369 testPackage.getAppPackageName()); 370 setAttribute(doc, testPackageNode, ATTRIBUTE_DIGEST, 371 testPackage.getMessageDigest()); 372 373 if (testPackage instanceof SignatureCheckPackage) { 374 setAttribute(doc, testPackageNode, 375 TestSessionBuilder.ATTRIBUTE_SIGNATURE_CHECK, "true"); 376 } 377 378 for (TestSuite testSuite : testPackage.getTestSuites()) { 379 outputTestSuite(doc, testPackage, testPackageNode, testSuite); 380 } 381 root.appendChild(testPackageNode); 382 } 383 384 return doc; 385 } catch (Exception e) { 386 Log.e("create result doc failed", e); 387 } 388 return null; 389 } 390 391 /** 392 * Output TestSuite and result to XML DOM Document. 393 * 394 * @param doc The document. 395 * @param parentNode The parent node. 396 * @param testSuite The test suite. 397 */ outputTestSuite(final Document doc, final TestPackage testPackage, final Node parentNode, TestSuite testSuite)398 private void outputTestSuite(final Document doc, 399 final TestPackage testPackage, final Node parentNode, 400 TestSuite testSuite) { 401 402 Collection<TestSuite> subSuites = testSuite.getSubSuites(); 403 Collection<TestCase> testCases = testSuite.getTestCases(); 404 405 Node testSuiteNode = doc.createElement(TAG_TESTSUITE); 406 setAttribute(doc, testSuiteNode, ATTRIBUTE_NAME, testSuite.getName()); 407 408 for (TestCase testCase : testCases) { 409 Node testCaseNode = doc.createElement(TAG_TESTCASE); 410 testSuiteNode.appendChild(testCaseNode); 411 setAttribute(doc, testCaseNode, ATTRIBUTE_NAME, testCase.getName()); 412 setAttribute(doc, testCaseNode, TestSessionBuilder.ATTRIBUTE_PRIORITY, 413 testCase.getPriority()); 414 415 Collection<Test> tests = testCase.getTests(); 416 for (Test test : tests) { 417 Node testNode = doc.createElement(TestSessionBuilder.TAG_TEST); 418 testCaseNode.appendChild(testNode); 419 420 if (test.isKnownFailure()) { 421 setAttribute(doc, testNode, ATTRIBUTE_KNOWN_FAILURE, test.getKnownFailure()); 422 } 423 424 CtsTestResult result = test.getResult(); 425 setAttribute(doc, testNode, ATTRIBUTE_NAME, test.getName()); 426 setAttribute(doc, testNode, ATTRIBUTE_RESULT, result.getResultString()); 427 setAttribute(doc, testNode, ATTRIBUTE_STARTTIME, 428 new Date(test.getStartTime()).toString()); 429 setAttribute(doc, testNode, ATTRIBUTE_ENDTIME, 430 new Date(test.getEndTime()).toString()); 431 432 String failedMessage = result.getFailedMessage(); 433 434 if (failedMessage != null) { 435 // failure message may contain control characters < 0x20 that get translated 436 // into illegal XML character entities. Replace them first. 437 failedMessage = HostUtils.replaceControlChars(failedMessage); 438 Node failedMessageNode = doc.createElement(TAG_FAILED_SCENE); 439 testNode.appendChild(failedMessageNode); 440 setAttribute(doc, failedMessageNode,TAG_FAILED_MESSAGE, failedMessage); 441 442 String stackTrace = result.getStackTrace(); 443 if (stackTrace != null) { 444 Node stackTraceNode = doc.createElement(TAG_STACK_TRACE); 445 failedMessageNode.appendChild(stackTraceNode); 446 Node stackTraceTextNode = doc.createTextNode(stackTrace); 447 stackTraceNode.appendChild(stackTraceTextNode); 448 } 449 } 450 } 451 } 452 453 for (TestSuite subSuite : subSuites) { 454 outputTestSuite(doc, testPackage, testSuiteNode, subSuite); 455 parentNode.appendChild(testSuiteNode); 456 } 457 parentNode.appendChild(testSuiteNode); 458 } 459 460 /** 461 * Fetch failed file name and line number 462 * 463 * @param failedResult failed message 464 * @return failed file name and line number 465 */ getFailedLineNumber(final String failedResult)466 public final static String[] getFailedLineNumber(final String failedResult) { 467 Matcher m = mTestFailedPattern.matcher(failedResult); 468 if (m.matches()) { 469 return new String[]{m.group(1), m.group(2)}; 470 } 471 return null; 472 } 473 474 /** 475 * set the device information of a specific device 476 * 477 * @param dInfo The device information. 478 */ setDeviceInfo(final TestDevice.DeviceParameterCollector dInfo)479 public void setDeviceInfo(final TestDevice.DeviceParameterCollector dInfo) { 480 for (DeviceParameterCollector collector : mDeviceParameterBase) { 481 if (collector.getSerialNumber().equals(dInfo.getSerialNumber())) { 482 //if there has information for the device with given serial number, 483 //replace it with the new information. 484 mDeviceParameterBase.remove(collector); 485 break; 486 } 487 } 488 mDeviceParameterBase.add(dInfo); 489 } 490 } 491