diff --git a/testrunner/.gitignore b/testrunner/.gitignore index 0d20b6487..b3421b024 100644 --- a/testrunner/.gitignore +++ b/testrunner/.gitignore @@ -1 +1,2 @@ *.pyc +.* diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py index ddc50d5b8..519134014 100755 --- a/testrunner/adb_interface.py +++ b/testrunner/adb_interface.py @@ -131,6 +131,17 @@ class AdbInterface: logger.Log("ADB Pull Failed: Source file %s does not exist." % src) return False + def Install(self, apk_path): + """Installs apk on device. + + Args: + apk_path: file path to apk file on host + + Returns: + output of install command + """ + return self.SendCommand("install -r %s" % apk_path) + def DoesFileExist(self, src): """Checks if the given path exists on device target. diff --git a/testrunner/coverage.py b/testrunner/coverage.py index 4322e26db..1c8ec2fd5 100755 --- a/testrunner/coverage.py +++ b/testrunner/coverage.py @@ -289,25 +289,6 @@ def EnableCoverageBuild(): os.environ["EMMA_INSTRUMENT"] = "true" -def TestDeviceCoverageSupport(adb): - """Check if device has support for generating code coverage metrics. - - This tries to dump emma help information on device, a response containing - help information will indicate that emma is already on system class path. - - Returns: - True if device can support code coverage. False otherwise. - """ - try: - output = adb.SendShellCommand("exec app_process / emma -h") - - if output.find('emma usage:') == 0: - return True - except errors.AbortError: - pass - return False - - def Run(): """Does coverage operations based on command line args.""" # TODO: do we want to support combining coverage for a single target diff --git a/testrunner/runtest.py b/testrunner/runtest.py index 6c1b1b6c1..9082d79e2 100755 --- a/testrunner/runtest.py +++ b/testrunner/runtest.py @@ -33,6 +33,7 @@ Do runtest --help to see full list of options. import glob import optparse import os +import re from sets import Set import sys import time @@ -73,6 +74,13 @@ class TestRunner(object): _DALVIK_VERIFIER_OFF_PROP = "dalvik.vm.dexopt-flags = v=n" + # regular expression to match install: statements in make output + _RE_MAKE_INSTALL = re.compile(r'Install:\s(.+)') + + # regular expression to find remote device path from a file path relative + # to build root + _RE_MAKE_INSTALL_PATH = re.compile(r'out\/target\/product\/\w+\/(.+)$') + def __init__(self): # disable logging of timestamp self._root_path = android_build.GetTop() @@ -243,23 +251,11 @@ class TestRunner(object): self._adb.EnableAdbRoot() else: logger.Log("adb root") - rebuild_libcore = False if target_set: if self._options.coverage: coverage.EnableCoverageBuild() - # hack to remove core library intermediates - # hack is needed because: - # 1. EMMA_INSTRUMENT changes what source files to include in libcore - # but it does not trigger a rebuild - # 2. there's no target (like "clear-intermediates") to remove the files - # decently - rebuild_libcore = not coverage.TestDeviceCoverageSupport(self._adb) - if rebuild_libcore: - cmd = "rm -rf %s" % os.path.join( - self._root_path, - "out/target/common/obj/JAVA_LIBRARIES/core_intermediates/") - logger.Log(cmd) - run_command.RunCommand(cmd, return_output=False) + target_set.append("external/emma/Android.mk") + # TODO: detect if external/emma exists target_build_string = " ".join(target_set) extra_args_string = " ".join(extra_args_set) @@ -270,17 +266,38 @@ class TestRunner(object): target_build_string, self._options.make_jobs, self._root_path, extra_args_string) logger.Log(cmd) + if not self._options.preview: + output = run_command.RunCommand(cmd, return_output=True, timeout_time=600) + self._DoInstall(output) - if self._options.preview: - # in preview mode, just display to the user what command would have been - # run - logger.Log("adb sync") - else: - # set timeout for build to 10 minutes, since libcore may need to - # be rebuilt - run_command.RunCommand(cmd, return_output=False, timeout_time=600) - logger.Log("Syncing to device...") - self._adb.Sync(runtime_restart=rebuild_libcore) + def _DoInstall(self, make_output): + """Install artifacts from build onto device. + + Looks for 'install:' text from make output to find artifacts to install. + + Args: + make_output: stdout from make command + """ + for line in make_output.split("\n"): + m = self._RE_MAKE_INSTALL.match(line) + if m: + install_path = m.group(1) + if install_path.endswith(".apk"): + abs_install_path = os.path.join(self._root_path, install_path) + logger.Log("adb install -r %s" % abs_install_path) + logger.Log(self._adb.Install(abs_install_path)) + else: + self._PushInstallFileToDevice(install_path) + + def _PushInstallFileToDevice(self, install_path): + m = self._RE_MAKE_INSTALL_PATH.match(install_path) + if m: + remote_path = m.group(1) + abs_install_path = os.path.join(self._root_path, install_path) + logger.Log("adb push %s %s", abs_install_path, remote_path) + self._adb.Push(abs_install_path, remote_path) + else: + logger.Log("Error: Failed to recognize path of file to install %s" % install_path) def _DoFullBuild(self, tests): """If necessary, run a full 'make' command for the tests that need it.""" @@ -309,8 +326,9 @@ class TestRunner(object): if not self._options.preview: old_dir = os.getcwd() os.chdir(self._root_path) - run_command.RunCommand(cmd, return_output=False) + output = run_command.RunCommand(cmd, return_output=False) os.chdir(old_dir) + self._DoInstall(output) def _AddBuildTarget(self, test_suite, target_set, extra_args_set): if not test_suite.IsFullMake(): @@ -369,7 +387,7 @@ class TestRunner(object): If one or more tests needs dalvik verifier off, and it is not already off, turns off verifier and reboots device to allow change to take effect. """ - # hack to check if these are framework/base tests. If so, turn off verifier + # hack to check if these are frameworks/base tests. If so, turn off verifier # to allow framework tests to access package-private framework api framework_test = False for test in test_list: diff --git a/testrunner/test_defs/instrumentation_test.py b/testrunner/test_defs/instrumentation_test.py index ede7ceb26..12633b269 100644 --- a/testrunner/test_defs/instrumentation_test.py +++ b/testrunner/test_defs/instrumentation_test.py @@ -33,9 +33,6 @@ class InstrumentationTestSuite(test_suite.AbstractTestSuite): DEFAULT_RUNNER = "android.test.InstrumentationTestRunner" - # dependency on libcore (used for Emma) - _LIBCORE_BUILD_PATH = "libcore" - def __init__(self): test_suite.AbstractTestSuite.__init__(self) self._package_name = None @@ -87,8 +84,6 @@ class InstrumentationTestSuite(test_suite.AbstractTestSuite): return self def GetBuildDependencies(self, options): - if options.coverage: - return [self._LIBCORE_BUILD_PATH] return [] def Run(self, options, adb): @@ -145,8 +140,6 @@ class InstrumentationTestSuite(test_suite.AbstractTestSuite): logger.Log(adb_cmd) elif options.coverage: coverage_gen = coverage.CoverageGenerator(adb) - adb.WaitForInstrumentation(self.GetPackageName(), - self.GetRunnerName()) # need to parse test output to determine path to coverage file logger.Log("Running in coverage mode, suppressing test output") try: @@ -168,8 +161,6 @@ class InstrumentationTestSuite(test_suite.AbstractTestSuite): if coverage_file is not None: logger.Log("Coverage report generated at %s" % coverage_file) else: - adb.WaitForInstrumentation(self.GetPackageName(), - self.GetRunnerName()) adb.StartInstrumentationNoResults( package_name=self.GetPackageName(), runner_name=self.GetRunnerName(),