Commit 5cea02e8 authored by jbudorick's avatar jbudorick Committed by Commit bot

[Android] Add experimental gtest xml result handling.

BUG=646677

Review-Url: https://codereview.chromium.org/2362143002
Cr-Commit-Position: refs/heads/master@{#420639}
parent dbdc108b
......@@ -2,10 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import HTMLParser
import logging
import os
import re
import tempfile
import xml.etree.ElementTree
from devil.android import apk_helper
from pylib import constants
......@@ -169,6 +171,33 @@ def ParseGTestOutput(output):
return results
def ParseGTestXML(xml_content):
"""Parse gtest XML result."""
results = []
html = HTMLParser.HTMLParser()
# TODO(jbudorick): Unclear how this handles crashes.
testsuites = xml.etree.ElementTree.fromstring(xml_content)
for testsuite in testsuites:
suite_name = testsuite.attrib['name']
for testcase in testsuite:
case_name = testcase.attrib['name']
result_type = base_test_result.ResultType.PASS
log = []
for failure in testcase:
result_type = base_test_result.ResultType.FAIL
log.append(html.unescape(failure.attrib['message']))
results.append(base_test_result.BaseTestResult(
'%s.%s' % (suite_name, case_name),
result_type,
int(float(testcase.attrib['time']) * 1000),
log=('\n'.join(log) if log else '')))
return results
class GtestTestInstance(test_instance.TestInstance):
def __init__(self, args, isolate_delegate, error_func):
......@@ -251,6 +280,9 @@ class GtestTestInstance(test_instance.TestInstance):
self._test_arguments = args.test_arguments
# TODO(jbudorick): Remove this once it's deployed.
self._enable_xml_result_parsing = args.enable_xml_result_parsing
@property
def activity(self):
return self._apk_helper and self._apk_helper.GetActivityName()
......@@ -271,6 +303,10 @@ class GtestTestInstance(test_instance.TestInstance):
def app_files(self):
return self._app_data_files
@property
def enable_xml_result_parsing(self):
return self._enable_xml_result_parsing
@property
def exe_dist_dir(self):
return self._exe_dist_dir
......
......@@ -7,6 +7,7 @@ import itertools
import logging
import os
import posixpath
import tempfile
from devil.android import device_errors
from devil.android import device_temp_file
......@@ -19,8 +20,6 @@ from pylib.local import local_test_server_spawner
from pylib.local.device import local_device_environment
from pylib.local.device import local_device_test_run
_COMMAND_LINE_FLAGS_SUPPORTED = True
_MAX_INLINE_FLAGS_LENGTH = 50 # Arbitrarily chosen.
_EXTRA_COMMAND_LINE_FILE = (
'org.chromium.native_test.NativeTest.CommandLineFile')
......@@ -116,6 +115,9 @@ class _ApkDelegate(object):
device.Install(self._apk_helper, reinstall=True,
permissions=self._permissions)
def ResultsDirectory(self, device):
return device.GetApplicationDataDirectory(self._package)
def Run(self, test, device, flags=None, **kwargs):
extras = dict(self._extras)
......@@ -175,6 +177,11 @@ class _ExeDelegate(object):
device.PushChangedFiles([(self._host_dist_dir, self._device_dist_dir)],
delete_device_stale=True)
def ResultsDirectory(self, device):
# pylint: disable=no-self-use
# pylint: disable=unused-argument
return constants.TEST_EXECUTABLE_DIR
def Run(self, test, device, flags=None, **kwargs):
tool = self._test_run.GetTool(device).GetTestWrapper()
if tool:
......@@ -341,9 +348,25 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
# Run the test.
timeout = (self._test_instance.shard_timeout
* self.GetTool(device).GetTimeoutScale())
with tempfile.NamedTemporaryFile(suffix='.xml') as host_tmp_results_file:
with device_temp_file.DeviceTempFile(
adb=device.adb,
dir=self._delegate.ResultsDirectory(device),
suffix='.xml') as device_tmp_results_file:
flags = self._test_instance.test_arguments or ''
if self._test_instance.enable_xml_result_parsing:
flags += ' --gtest_output=xml:%s' % device_tmp_results_file.name
output = self._delegate.Run(
test, device, flags=self._test_instance.test_arguments,
test, device, flags=flags,
timeout=timeout, retries=0)
if self._test_instance.enable_xml_result_parsing:
device.PullFile(
device_tmp_results_file.name,
host_tmp_results_file.name)
for s in self._servers[str(device)]:
s.Reset()
if self._test_instance.app_files:
......@@ -354,6 +377,10 @@ class LocalDeviceGtestRun(local_device_test_run.LocalDeviceTestRun):
# Parse the output.
# TODO(jbudorick): Transition test scripts away from parsing stdout.
if self._test_instance.enable_xml_result_parsing:
with open(host_tmp_results_file.name) as xml_results_file:
results = gtest_test_instance.ParseGTestXML(xml_results_file.read())
else:
results = gtest_test_instance.ParseGTestOutput(output)
# Check whether there are any crashed testcases.
......
......@@ -285,6 +285,9 @@ def AddGTestOptions(parser):
'device for the list of all tests. Speeds up local '
'development, but is not safe to use on bots ('
'http://crbug.com/549214')
group.add_argument('--enable-xml-result-parsing',
action='store_true',
help=argparse.SUPPRESS)
filter_group = group.add_mutually_exclusive_group()
filter_group.add_argument('-f', '--gtest_filter', '--gtest-filter',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment