Add support for parsing code coverage file path to runtest and related cleanup.
This change is to adapt runtest to the InstrumentationTestRunner change which dumps coverage data to the app's local data folder, instead of a fixed file on the sdcard. Also fixed adb_interace.StartInstrumentationForPackage, added better handling when generating coverage for tests with unknown coverage targets, and reduced the duplicate definitions of the "coverage_targets.xml" definition file.
This commit is contained in:
@@ -157,8 +157,9 @@ class AdbInterface:
|
|||||||
separated into its package and runner components.
|
separated into its package and runner components.
|
||||||
"""
|
"""
|
||||||
instrumentation_path = "%s/%s" % (package_name, runner_name)
|
instrumentation_path = "%s/%s" % (package_name, runner_name)
|
||||||
return self.StartInstrumentation(self, instrumentation_path, timeout_time,
|
return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
|
||||||
no_window_animation, instrumentation_args)
|
no_window_animation=no_window_animation,
|
||||||
|
instrumentation_args=instrumentation_args)
|
||||||
|
|
||||||
def StartInstrumentation(
|
def StartInstrumentation(
|
||||||
self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
|
self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
|
||||||
@@ -203,7 +204,7 @@ class AdbInterface:
|
|||||||
instrumentation_path, no_window_animation=no_window_animation,
|
instrumentation_path, no_window_animation=no_window_animation,
|
||||||
profile=profile, raw_mode=True,
|
profile=profile, raw_mode=True,
|
||||||
instrumentation_args=instrumentation_args)
|
instrumentation_args=instrumentation_args)
|
||||||
|
logger.Log(command_string)
|
||||||
(test_results, inst_finished_bundle) = (
|
(test_results, inst_finished_bundle) = (
|
||||||
am_instrument_parser.ParseAmInstrumentOutput(
|
am_instrument_parser.ParseAmInstrumentOutput(
|
||||||
self.SendShellCommand(command_string, timeout_time=timeout_time,
|
self.SendShellCommand(command_string, timeout_time=timeout_time,
|
||||||
@@ -217,7 +218,7 @@ class AdbInterface:
|
|||||||
short_msg_result = "no error message"
|
short_msg_result = "no error message"
|
||||||
if "shortMsg" in inst_finished_bundle:
|
if "shortMsg" in inst_finished_bundle:
|
||||||
short_msg_result = inst_finished_bundle["shortMsg"]
|
short_msg_result = inst_finished_bundle["shortMsg"]
|
||||||
logger.Log(short_msg_result)
|
logger.Log("Error! Test run failed: %s" % short_msg_result)
|
||||||
raise errors.InstrumentationError(short_msg_result)
|
raise errors.InstrumentationError(short_msg_result)
|
||||||
|
|
||||||
if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
|
if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
|
||||||
|
|||||||
@@ -44,16 +44,15 @@ class CoverageGenerator(object):
|
|||||||
# path to EMMA host jar, relative to Android build root
|
# path to EMMA host jar, relative to Android build root
|
||||||
_EMMA_JAR = os.path.join(_EMMA_BUILD_PATH, "lib", "emma.jar")
|
_EMMA_JAR = os.path.join(_EMMA_BUILD_PATH, "lib", "emma.jar")
|
||||||
_TEST_COVERAGE_EXT = "ec"
|
_TEST_COVERAGE_EXT = "ec"
|
||||||
# default device-side path to code coverage results file
|
|
||||||
_DEVICE_COVERAGE_PATH = "/sdcard/coverage.ec"
|
|
||||||
# root path of generated coverage report files, relative to Android build root
|
# root path of generated coverage report files, relative to Android build root
|
||||||
_COVERAGE_REPORT_PATH = os.path.join("out", "emma")
|
_COVERAGE_REPORT_PATH = os.path.join("out", "emma")
|
||||||
|
_TARGET_DEF_FILE = "coverage_targets.xml"
|
||||||
_CORE_TARGET_PATH = os.path.join("development", "testrunner",
|
_CORE_TARGET_PATH = os.path.join("development", "testrunner",
|
||||||
"coverage_targets.xml")
|
_TARGET_DEF_FILE)
|
||||||
# vendor glob file path patterns to tests, relative to android
|
# vendor glob file path patterns to tests, relative to android
|
||||||
# build root
|
# build root
|
||||||
_VENDOR_TARGET_PATH = os.path.join("vendor", "*", "tests", "testinfo",
|
_VENDOR_TARGET_PATH = os.path.join("vendor", "*", "tests", "testinfo",
|
||||||
"coverage_targets.xml")
|
_TARGET_DEF_FILE)
|
||||||
|
|
||||||
# path to root of target build intermediates
|
# path to root of target build intermediates
|
||||||
_TARGET_INTERMEDIATES_BASE_PATH = os.path.join("out", "target", "common",
|
_TARGET_INTERMEDIATES_BASE_PATH = os.path.join("out", "target", "common",
|
||||||
@@ -93,7 +92,7 @@ class CoverageGenerator(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def ExtractReport(self, test_suite,
|
def ExtractReport(self, test_suite,
|
||||||
device_coverage_path=_DEVICE_COVERAGE_PATH,
|
device_coverage_path,
|
||||||
output_path=None):
|
output_path=None):
|
||||||
"""Extract runtime coverage data and generate code coverage report.
|
"""Extract runtime coverage data and generate code coverage report.
|
||||||
|
|
||||||
@@ -122,8 +121,14 @@ class CoverageGenerator(object):
|
|||||||
report_path = os.path.join(output_path,
|
report_path = os.path.join(output_path,
|
||||||
test_suite.GetName())
|
test_suite.GetName())
|
||||||
target = self._targets_manifest.GetTarget(test_suite.GetTargetName())
|
target = self._targets_manifest.GetTarget(test_suite.GetTargetName())
|
||||||
return self._GenerateReport(report_path, coverage_local_path, [target],
|
if target is None:
|
||||||
do_src=True)
|
msg = ["Error: test %s references undefined target %s."
|
||||||
|
% (test_suite.GetName(), test_suite.GetTargetName())]
|
||||||
|
msg.append(" Ensure target is defined in %s" % self._TARGET_DEF_FILE)
|
||||||
|
logger.Log("".join(msg))
|
||||||
|
else:
|
||||||
|
return self._GenerateReport(report_path, coverage_local_path, [target],
|
||||||
|
do_src=True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _GenerateReport(self, report_path, coverage_file_path, targets,
|
def _GenerateReport(self, report_path, coverage_file_path, targets,
|
||||||
|
|||||||
@@ -278,16 +278,53 @@ class TestRunner(object):
|
|||||||
raw_mode=self._options.raw_mode,
|
raw_mode=self._options.raw_mode,
|
||||||
instrumentation_args=instrumentation_args)
|
instrumentation_args=instrumentation_args)
|
||||||
logger.Log(adb_cmd)
|
logger.Log(adb_cmd)
|
||||||
|
elif self._options.coverage:
|
||||||
|
# need to parse test output to determine path to coverage file
|
||||||
|
logger.Log("Running in coverage mode, suppressing test output")
|
||||||
|
try:
|
||||||
|
(test_results, status_map) = self._adb.StartInstrumentationForPackage(
|
||||||
|
package_name=test_suite.GetPackageName(),
|
||||||
|
runner_name=test_suite.GetRunnerName(),
|
||||||
|
timeout_time=60*60,
|
||||||
|
instrumentation_args=instrumentation_args)
|
||||||
|
except errors.InstrumentationError, errors.DeviceUnresponsiveError:
|
||||||
|
return
|
||||||
|
self._PrintTestResults(test_results)
|
||||||
|
device_coverage_path = status_map.get("coverageFilePath", None)
|
||||||
|
if device_coverage_path is None:
|
||||||
|
logger.Log("Error: could not find coverage data on device")
|
||||||
|
return
|
||||||
|
coverage_file = self._coverage_gen.ExtractReport(test_suite, device_coverage_path)
|
||||||
|
if coverage_file is not None:
|
||||||
|
logger.Log("Coverage report generated at %s" % coverage_file)
|
||||||
else:
|
else:
|
||||||
self._adb.StartInstrumentationNoResults(
|
self._adb.StartInstrumentationNoResults(
|
||||||
package_name=test_suite.GetPackageName(),
|
package_name=test_suite.GetPackageName(),
|
||||||
runner_name=test_suite.GetRunnerName(),
|
runner_name=test_suite.GetRunnerName(),
|
||||||
raw_mode=self._options.raw_mode,
|
raw_mode=self._options.raw_mode,
|
||||||
instrumentation_args=instrumentation_args)
|
instrumentation_args=instrumentation_args)
|
||||||
if self._options.coverage and test_suite.GetTargetName() is not None:
|
|
||||||
coverage_file = self._coverage_gen.ExtractReport(test_suite)
|
def _PrintTestResults(self, test_results):
|
||||||
if coverage_file is not None:
|
"""Prints a summary of test result data to stdout.
|
||||||
logger.Log("Coverage report generated at %s" % coverage_file)
|
|
||||||
|
Args:
|
||||||
|
test_results: a list of am_instrument_parser.TestResult
|
||||||
|
"""
|
||||||
|
total_count = 0
|
||||||
|
error_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
for test_result in test_results:
|
||||||
|
if test_result.GetStatusCode() == -1: # error
|
||||||
|
logger.Log("Error in %s: %s" % (test_result.GetTestName(),
|
||||||
|
test_result.GetFailureReason()))
|
||||||
|
error_count+=1
|
||||||
|
elif test_result.GetStatusCode() == -2: # failure
|
||||||
|
logger.Log("Failure in %s: %s" % (test_result.GetTestName(),
|
||||||
|
test_result.GetFailureReason()))
|
||||||
|
fail_count+=1
|
||||||
|
total_count+=1
|
||||||
|
logger.Log("Tests run: %d, Failures: %d, Errors: %d" %
|
||||||
|
(total_count, fail_count, error_count))
|
||||||
|
|
||||||
def _CollectTestSources(self, test_list, dirname, files):
|
def _CollectTestSources(self, test_list, dirname, files):
|
||||||
"""For each directory, find tests source file and add them to the list.
|
"""For each directory, find tests source file and add them to the list.
|
||||||
|
|||||||
Reference in New Issue
Block a user