diff --git a/testrunner/.gitignore b/testrunner/.gitignore deleted file mode 100644 index b3421b024..000000000 --- a/testrunner/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.pyc -.* diff --git a/testrunner/Android.mk b/testrunner/Android.mk deleted file mode 100644 index 8c80143cd..000000000 --- a/testrunner/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -# -# Install a list of test definitions on device -# - -# where to install the sample files on the device -# -local_target_dir := $(TARGET_OUT_DATA)/testinfo -LOCAL_PATH := $(call my-dir) - -######################## -include $(CLEAR_VARS) -LOCAL_MODULE := test_defs.xml -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(local_target_dir) -LOCAL_SRC_FILES := $(LOCAL_MODULE) -include $(BUILD_PREBUILT) - -include $(CLEAR_VARS) -LOCAL_MODULE := coverage_targets.xml -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $(local_target_dir) -LOCAL_SRC_FILES := $(LOCAL_MODULE) -include $(BUILD_PREBUILT) diff --git a/testrunner/__init__.py b/testrunner/__init__.py deleted file mode 100644 index 69ee92b04..000000000 --- a/testrunner/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['adb_interface', 'android_build', 'errors', 'logger', 'run_command'] diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py deleted file mode 100755 index 93b4088d2..000000000 --- a/testrunner/adb_interface.py +++ /dev/null @@ -1,557 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Provides an interface to communicate with the device via the adb command. - -Assumes adb binary is currently on system path. -""" -# Python imports -import os -import string -import time - -# local imports -import am_instrument_parser -import errors -import logger -import run_command - - -class AdbInterface: - """Helper class for communicating with Android device via adb.""" - - # argument to pass to adb, to direct command to specific device - _target_arg = "" - - DEVICE_TRACE_DIR = "/data/test_results/" - - def SetEmulatorTarget(self): - """Direct all future commands to the only running emulator.""" - self._target_arg = "-e" - - def SetDeviceTarget(self): - """Direct all future commands to the only connected USB device.""" - self._target_arg = "-d" - - def SetTargetSerial(self, serial): - """Direct all future commands to Android target with the given serial.""" - self._target_arg = "-s %s" % serial - - def SendCommand(self, command_string, timeout_time=60, retry_count=3): - """Send a command via adb. - - Args: - command_string: adb command to run - timeout_time: number of seconds to wait for command to respond before - retrying - retry_count: number of times to retry command before raising - WaitForResponseTimedOutError - Returns: - string output of command - - Raises: - WaitForResponseTimedOutError if device does not respond to command within time - """ - adb_cmd = "adb %s %s" % (self._target_arg, command_string) - logger.SilentLog("about to run %s" % adb_cmd) - return run_command.RunCommand(adb_cmd, timeout_time=timeout_time, - retry_count=retry_count) - - def SendShellCommand(self, cmd, timeout_time=20, retry_count=3): - """Send a adb shell command. - - Args: - cmd: adb shell command to run - timeout_time: number of seconds to wait for command to respond before - retrying - retry_count: number of times to retry command before raising - WaitForResponseTimedOutError - - Returns: - string output of command - - Raises: - WaitForResponseTimedOutError: if device does not respond to command - """ - return self.SendCommand("shell %s" % cmd, timeout_time=timeout_time, - retry_count=retry_count) - - def BugReport(self, path): - """Dumps adb bugreport to the file specified by the path. - - Args: - path: Path of the file where adb bugreport is dumped to. - """ - bug_output = self.SendShellCommand("bugreport", timeout_time=60) - bugreport_file = open(path, "w") - bugreport_file.write(bug_output) - bugreport_file.close() - - def Push(self, src, dest): - """Pushes the file src onto the device at dest. - - Args: - src: file path of host file to push - dest: destination absolute file path on device - """ - self.SendCommand("push %s %s" % (src, dest), timeout_time=60) - - def Pull(self, src, dest): - """Pulls the file src on the device onto dest on the host. - - Args: - src: absolute file path of file on device to pull - dest: destination file path on host - - Returns: - True if success and False otherwise. - """ - # Create the base dir if it doesn't exist already - if not os.path.exists(os.path.dirname(dest)): - os.makedirs(os.path.dirname(dest)) - - if self.DoesFileExist(src): - self.SendCommand("pull %s %s" % (src, dest), timeout_time=60) - return True - else: - logger.Log("ADB Pull Failed: Source file %s does not exist." % src) - return False - - def Install(self, apk_path, extra_flags): - """Installs apk on device. - - Args: - apk_path: file path to apk file on host - extra_flags: Additional flags to use with adb install - - Returns: - output of install command - """ - return self.SendCommand("install -r %s %s" % (extra_flags, apk_path)) - - def DoesFileExist(self, src): - """Checks if the given path exists on device target. - - Args: - src: file path to be checked. - - Returns: - True if file exists - """ - - output = self.SendShellCommand("ls %s" % src) - error = "No such file or directory" - - if error in output: - return False - return True - - def EnableAdbRoot(self): - """Enable adb root on device.""" - output = self.SendCommand("root") - if "adbd is already running as root" in output: - return True - elif "restarting adbd as root" in output: - # device will disappear from adb, wait for it to come back - time.sleep(2) - self.SendCommand("wait-for-device") - return True - else: - logger.Log("Unrecognized output from adb root: %s" % output) - return False - - def StartInstrumentationForPackage( - self, package_name, runner_name, timeout_time=60*10, - no_window_animation=False, instrumentation_args={}, user=None, - no_hidden_api_checks=False): - """Run instrumentation test for given package and runner. - - Equivalent to StartInstrumentation, except instrumentation path is - separated into its package and runner components. - """ - instrumentation_path = "%s/%s" % (package_name, runner_name) - return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time, - no_window_animation=no_window_animation, - instrumentation_args=instrumentation_args, - user=user, - no_hidden_api_checks=no_hidden_api_checks) - - def StartInstrumentation( - self, instrumentation_path, timeout_time=60*10, no_window_animation=False, - profile=False, instrumentation_args={}, user=None, - no_hidden_api_checks=False): - - """Runs an instrumentation class on the target. - - Returns a dictionary containing the key value pairs from the - instrumentations result bundle and a list of TestResults. Also handles the - interpreting of error output from the device and raises the necessary - exceptions. - - Args: - instrumentation_path: string. It should be the fully classified package - name, and instrumentation test runner, separated by "/" - e.g. com.android.globaltimelaunch/.GlobalTimeLaunch - timeout_time: Timeout value for the am command. - no_window_animation: boolean, Whether you want window animations enabled - or disabled - profile: If True, profiling will be turned on for the instrumentation. - instrumentation_args: Dictionary of key value bundle arguments to pass to - instrumentation. - user: The user id to start the instrumentation with. - - Returns: - (test_results, inst_finished_bundle) - - test_results: a list of TestResults - inst_finished_bundle (dict): Key/value pairs contained in the bundle that - is passed into ActivityManager.finishInstrumentation(). Included in this - bundle is the return code of the Instrumentation process, any error - codes reported by the activity manager, and any results explicitly added - by the instrumentation code. - - Raises: - WaitForResponseTimedOutError: if timeout occurred while waiting for - response to adb instrument command - DeviceUnresponsiveError: if device system process is not responding - InstrumentationError: if instrumentation failed to run - """ - - command_string = self._BuildInstrumentationCommandPath( - instrumentation_path, no_window_animation=no_window_animation, - profile=profile, raw_mode=True, - instrumentation_args=instrumentation_args, - user=user, no_hidden_api_checks=no_hidden_api_checks) - logger.Log(command_string) - (test_results, inst_finished_bundle) = ( - am_instrument_parser.ParseAmInstrumentOutput( - self.SendShellCommand(command_string, timeout_time=timeout_time, - retry_count=2))) - - if "code" not in inst_finished_bundle: - raise errors.InstrumentationError("no test results... device setup " - "correctly?") - - if inst_finished_bundle["code"] == "0": - short_msg_result = "no error message" - if "shortMsg" in inst_finished_bundle: - short_msg_result = inst_finished_bundle["shortMsg"] - logger.Log("Error! Test run failed: %s" % short_msg_result) - raise errors.InstrumentationError(short_msg_result) - - if "INSTRUMENTATION_ABORTED" in inst_finished_bundle: - logger.Log("INSTRUMENTATION ABORTED!") - raise errors.DeviceUnresponsiveError - - return (test_results, inst_finished_bundle) - - def StartInstrumentationNoResults( - self, package_name, runner_name, no_window_animation=False, - raw_mode=False, instrumentation_args={}, user=None, - no_hidden_api_checks=False): - """Runs instrumentation and dumps output to stdout. - - Equivalent to StartInstrumentation, but will dump instrumentation - 'normal' output to stdout, instead of parsing return results. Command will - never timeout. - """ - adb_command_string = self.PreviewInstrumentationCommand( - package_name, runner_name, no_window_animation=no_window_animation, - raw_mode=raw_mode, instrumentation_args=instrumentation_args, - user=user, no_hidden_api_checks=no_hidden_api_checks) - logger.Log(adb_command_string) - run_command.RunCommand(adb_command_string, return_output=False) - - def PreviewInstrumentationCommand( - self, package_name, runner_name, no_window_animation=False, - raw_mode=False, instrumentation_args={}, user=None, - no_hidden_api_checks=False): - """Returns a string of adb command that will be executed.""" - inst_command_string = self._BuildInstrumentationCommand( - package_name, runner_name, no_window_animation=no_window_animation, - raw_mode=raw_mode, instrumentation_args=instrumentation_args, - user=user, no_hidden_api_checks=no_hidden_api_checks) - return self.PreviewShellCommand(inst_command_string) - - def PreviewShellCommand(self, cmd): - return "adb %s shell %s" % (self._target_arg, cmd) - - def _BuildInstrumentationCommand( - self, package, runner_name, no_window_animation=False, profile=False, - raw_mode=True, instrumentation_args={}, user=None, - no_hidden_api_checks=False): - instrumentation_path = "%s/%s" % (package, runner_name) - - return self._BuildInstrumentationCommandPath( - instrumentation_path, no_window_animation=no_window_animation, - profile=profile, raw_mode=raw_mode, - instrumentation_args=instrumentation_args, user=user, - no_hidden_api_checks=no_hidden_api_checks) - - def _BuildInstrumentationCommandPath( - self, instrumentation_path, no_window_animation=False, profile=False, - raw_mode=True, instrumentation_args={}, user=None, - no_hidden_api_checks=False): - command_string = "am instrument" - if no_hidden_api_checks: - command_string += " --no-hidden-api-checks" - if user: - command_string += " --user %s" % user - if no_window_animation: - command_string += " --no_window_animation" - if profile: - self._CreateTraceDir() - command_string += ( - " -p %s/%s.dmtrace" % - (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1])) - - for key, value in instrumentation_args.items(): - command_string += " -e %s '%s'" % (key, value) - if raw_mode: - command_string += " -r" - command_string += " -w '%s'" % instrumentation_path - return command_string - - def _CreateTraceDir(self): - ls_response = self.SendShellCommand("ls /data/trace") - if ls_response.strip("#").strip(string.whitespace) != "": - self.SendShellCommand("create /data/trace", "mkdir /data/trace") - self.SendShellCommand("make /data/trace world writeable", - "chmod 777 /data/trace") - - def WaitForDevicePm(self, wait_time=120): - """Waits for targeted device's package manager to be up. - - Args: - wait_time: time in seconds to wait - - Raises: - WaitForResponseTimedOutError if wait_time elapses and pm still does not - respond. - """ - logger.Log("Waiting for device package manager...") - self.SendCommand("wait-for-device") - # Now the device is there, but may not be running. - # Query the package manager with a basic command - try: - self._WaitForShellCommandContents("pm path android", "package:", - wait_time) - except errors.WaitForResponseTimedOutError: - raise errors.WaitForResponseTimedOutError( - "Package manager did not respond after %s seconds" % wait_time) - - def IsInstrumentationInstalled(self, package_name, runner_name): - """Checks if instrumentation is present on device.""" - instrumentation_path = "%s/%s" % (package_name, runner_name) - command = "pm list instrumentation | grep %s" % instrumentation_path - try: - output = self.SendShellCommand(command) - return output.startswith("instrumentation:") - except errors.AbortError: - # command can return error code on failure - return False - - def WaitForProcess(self, name, wait_time=120): - """Wait until a process is running on the device. - - Args: - name: the process name as it appears in `ps` - wait_time: time in seconds to wait - - Raises: - WaitForResponseTimedOutError if wait_time elapses and the process is - still not running - """ - logger.Log("Waiting for process %s" % name) - self.SendCommand("wait-for-device") - self._WaitForShellCommandContents("ps", name, wait_time) - - def WaitForProcessEnd(self, name, wait_time=120): - """Wait until a process is no longer running on the device. - - Args: - name: the process name as it appears in `ps` - wait_time: time in seconds to wait - - Raises: - WaitForResponseTimedOutError if wait_time elapses and the process is - still running - """ - logger.Log("Waiting for process %s to end" % name) - self._WaitForShellCommandContents("ps", name, wait_time, invert=True) - - def _WaitForShellCommandContents(self, command, expected, wait_time, - raise_abort=True, invert=False): - """Wait until the response to a command contains a given output. - - Assumes that a only successful execution of "adb shell " contains - the substring expected. Assumes that a device is present. - - Args: - command: adb shell command to execute - expected: the string that should appear to consider the - command successful. - wait_time: time in seconds to wait - raise_abort: if False, retry when executing the command raises an - AbortError, rather than failing. - invert: if True, wait until the command output no longer contains the - expected contents. - - Raises: - WaitForResponseTimedOutError: If wait_time elapses and the command has not - returned an output containing expected yet. - """ - # Query the device with the command - success = False - attempts = 0 - wait_period = 5 - while not success and (attempts*wait_period) < wait_time: - # assume the command will always contain expected in the success case - try: - output = self.SendShellCommand(command, retry_count=1) - if ((not invert and expected in output) - or (invert and expected not in output)): - success = True - except errors.AbortError, e: - if raise_abort: - raise - # ignore otherwise - - if not success: - time.sleep(wait_period) - attempts += 1 - - if not success: - raise errors.WaitForResponseTimedOutError() - - def WaitForBootComplete(self, wait_time=120): - """Waits for targeted device's bootcomplete flag to be set. - - Args: - wait_time: time in seconds to wait - - Raises: - WaitForResponseTimedOutError if wait_time elapses and pm still does not - respond. - """ - logger.Log("Waiting for boot complete...") - self.SendCommand("wait-for-device") - # Now the device is there, but may not be running. - # Query the package manager with a basic command - boot_complete = False - attempts = 0 - wait_period = 5 - while not boot_complete and (attempts*wait_period) < wait_time: - output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1) - output = output.strip() - if output == "1": - boot_complete = True - else: - time.sleep(wait_period) - attempts += 1 - if not boot_complete: - raise errors.WaitForResponseTimedOutError( - "dev.bootcomplete flag was not set after %s seconds" % wait_time) - - def Sync(self, retry_count=3, runtime_restart=False): - """Perform a adb sync. - - Blocks until device package manager is responding. - - Args: - retry_count: number of times to retry sync before failing - runtime_restart: stop runtime during sync and restart afterwards, useful - for syncing system libraries (core, framework etc) - - Raises: - WaitForResponseTimedOutError if package manager does not respond - AbortError if unrecoverable error occurred - """ - output = "" - error = None - if runtime_restart: - self.SendShellCommand("setprop ro.test_harness 1", retry_count=retry_count) - # manual rest bootcomplete flag - self.SendShellCommand("setprop dev.bootcomplete 0", - retry_count=retry_count) - self.SendShellCommand("stop", retry_count=retry_count) - - try: - output = self.SendCommand("sync", retry_count=retry_count) - except errors.AbortError, e: - error = e - output = e.msg - if "Read-only file system" in output: - logger.SilentLog(output) - logger.Log("Remounting read-only filesystem") - self.SendCommand("remount") - output = self.SendCommand("sync", retry_count=retry_count) - elif "No space left on device" in output: - logger.SilentLog(output) - logger.Log("Restarting device runtime") - self.SendShellCommand("stop", retry_count=retry_count) - output = self.SendCommand("sync", retry_count=retry_count) - self.SendShellCommand("start", retry_count=retry_count) - elif error is not None: - # exception occurred that cannot be recovered from - raise error - logger.SilentLog(output) - if runtime_restart: - # start runtime and wait till boot complete flag is set - self.SendShellCommand("start", retry_count=retry_count) - self.WaitForBootComplete() - # press the MENU key, this will disable key guard if runtime is started - # with ro.monkey set to 1 - self.SendShellCommand("input keyevent 82", retry_count=retry_count) - else: - self.WaitForDevicePm() - return output - - def GetSerialNumber(self): - """Returns the serial number of the targeted device.""" - return self.SendCommand("get-serialno").strip() - - def RuntimeReset(self, disable_keyguard=False, retry_count=3, preview_only=False): - """ - Resets the Android runtime (does *not* reboot the kernel). - - Blocks until the reset is complete and the package manager - is available. - - Args: - disable_keyguard: if True, presses the MENU key to disable - key guard, after reset is finished - retry_count: number of times to retry reset before failing - - Raises: - WaitForResponseTimedOutError if package manager does not respond - AbortError if unrecoverable error occurred - """ - - logger.Log("adb shell stop") - logger.Log("adb shell start") - - if not preview_only: - self.SendShellCommand("stop", retry_count=retry_count) - self.SendShellCommand("start", retry_count=retry_count) - - self.WaitForDevicePm() - - if disable_keyguard: - logger.Log("input keyevent 82 ## disable keyguard") - if not preview_only: - self.SendShellCommand("input keyevent 82", retry_count=retry_count) diff --git a/testrunner/am_instrument_parser.py b/testrunner/am_instrument_parser.py deleted file mode 100755 index 4554c4d56..000000000 --- a/testrunner/am_instrument_parser.py +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Module that assists in parsing the output of "am instrument" commands run on -the device.""" - -import re -import string - - -def ParseAmInstrumentOutput(result): - """Given the raw output of an "am instrument" command that targets and - InstrumentationTestRunner, return structured data. - - Args: - result (string): Raw output of "am instrument" - - Return - (test_results, inst_finished_bundle) - - test_results (list of am_output_parser.TestResult) - inst_finished_bundle (dict): Key/value pairs contained in the bundle that is - passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return - code of the Instrumentation process, any error codes reported by the - activity manager, and any results explicity added by the instrumentation - code. - """ - - re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P-?\d)$') - test_results = [] - inst_finished_bundle = {} - - result_block_string = "" - for line in result.splitlines(): - result_block_string += line + '\n' - - if "INSTRUMENTATION_STATUS_CODE:" in line: - test_result = TestResult(result_block_string) - if test_result.GetStatusCode() == 1: # The test started - pass - elif test_result.GetStatusCode() in [0, -1, -2]: - test_results.append(test_result) - else: - pass - result_block_string = "" - if "INSTRUMENTATION_CODE:" in line: - inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string) - result_block_string = "" - - return (test_results, inst_finished_bundle) - - -def _ParseInstrumentationFinishedBundle(result): - """Given the raw output of "am instrument" returns a dictionary of the - key/value pairs from the bundle passed into - ActivityManager.finishInstrumentation(). - - Args: - result (string): Raw output of "am instrument" - - Return: - inst_finished_bundle (dict): Key/value pairs contained in the bundle that is - passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return - code of the Instrumentation process, any error codes reported by the - activity manager, and any results explicity added by the instrumentation - code. - """ - - re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$') - re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$') - result_dict = {} - key = '' - val = '' - last_tag = '' - - for line in result.split('\n'): - line = line.strip(string.whitespace) - if re_result.match(line): - last_tag = 'INSTRUMENTATION_RESULT' - key = re_result.search(line).group(1).strip(string.whitespace) - if key.startswith('performance.'): - key = key[len('performance.'):] - val = re_result.search(line).group(2).strip(string.whitespace) - try: - result_dict[key] = float(val) - except ValueError: - result_dict[key] = val - except TypeError: - result_dict[key] = val - elif re_code.match(line): - last_tag = 'INSTRUMENTATION_CODE' - key = 'code' - val = re_code.search(line).group(1).strip(string.whitespace) - result_dict[key] = val - elif 'INSTRUMENTATION_ABORTED:' in line: - last_tag = 'INSTRUMENTATION_ABORTED' - key = 'INSTRUMENTATION_ABORTED' - val = '' - result_dict[key] = val - elif last_tag == 'INSTRUMENTATION_RESULT': - result_dict[key] += '\n' + line - - if not result_dict.has_key('code'): - result_dict['code'] = '0' - result_dict['shortMsg'] = "No result returned from instrumentation" - - return result_dict - - -class TestResult(object): - """A class that contains information about a single test result.""" - - def __init__(self, result_block_string): - """ - Args: - result_block_string (string): Is a single "block" of output. A single - "block" would be either a "test started" status report, or a "test - finished" status report. - """ - - self._test_name = None - self._status_code = None - self._failure_reason = None - self._fields_map = {} - - re_status_code = re.search(r'INSTRUMENTATION_STATUS_CODE: ' - '(?P1|0|-1|-2)', result_block_string) - re_fields = re.compile(r'INSTRUMENTATION_STATUS: ' - '(?P[\w.]+)=(?P.*?)(?=\nINSTRUMENTATION_STATUS)', re.DOTALL) - - for field in re_fields.finditer(result_block_string): - key, value = (field.group('key').strip(), field.group('value').strip()) - if key.startswith('performance.'): - key = key[len('performance.'):] - self._fields_map[key] = value - self._fields_map.setdefault('class') - self._fields_map.setdefault('test') - - self._test_name = '%s:%s' % (self._fields_map['class'], - self._fields_map['test']) - self._status_code = int(re_status_code.group('status_code')) - if 'stack' in self._fields_map: - self._failure_reason = self._fields_map['stack'] - - def GetTestName(self): - return self._test_name - - def GetStatusCode(self): - return self._status_code - - def GetFailureReason(self): - return self._failure_reason - - def GetResultFields(self): - return self._fields_map diff --git a/testrunner/android_build.py b/testrunner/android_build.py deleted file mode 100644 index 2bbb8f608..000000000 --- a/testrunner/android_build.py +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Contains utility functions for interacting with the Android build system.""" - -# Python imports -import os -import re -import subprocess - -# local imports -import errors -import logger - - -def GetTop(): - """Returns the full pathname of the "top" of the Android development tree. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - the absolute file path of the Android build root. - - Raises: - AbortError: if Android build root could not be found. - """ - # TODO: does this need to be reimplemented to be like gettop() in envsetup.sh - root_path = os.getenv("ANDROID_BUILD_TOP") - if root_path is None: - logger.Log("Error: ANDROID_BUILD_TOP not defined. Please run " - "envsetup.sh and lunch/choosecombo") - raise errors.AbortError - return root_path - - -def GetHostOutDir(): - """Returns the full pathname of out/host/arch of the Android development tree. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - the absolute file path of the Android host output directory. - Raises: - AbortError: if Android host output directory could not be found. - """ - host_out_path = os.getenv("ANDROID_HOST_OUT") - if host_out_path is None: - logger.Log("Error: ANDROID_HOST_OUT not defined. Please run " - "envsetup.sh and lunch/choosecombo") - raise errors.AbortError - return host_out_path - - -def GetOutDir(): - """Returns the full pathname of the "out" of the Android development tree. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - the absolute file path of the Android build output directory. - """ - root_path = os.getenv("OUT_DIR") - if root_path is None: - root_path = os.path.join(GetTop(), "out") - return root_path - - -def GetHostBin(): - """Compute the full pathname to the host binary directory. - - Typically $ANDROID_HOST_OUT/bin. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - The absolute file path of the Android host binary directory. - - Raises: - AbortError: if Android host binary directory could not be found. - """ - path = os.path.join(GetHostOutDir(), "bin") - if not os.path.exists(path): - logger.Log("Error: Host bin path could not be found %s" % path) - raise errors.AbortError - return path - - -def GetProductOut(): - """Returns the full pathname to the target/product directory. - - Typically the value of the env variable $ANDROID_PRODUCT_OUT. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - The absolute file path of the Android product directory. - - Raises: - AbortError: if Android product directory could not be found. - """ - path = os.getenv("ANDROID_PRODUCT_OUT") - if path is None: - logger.Log("Error: ANDROID_PRODUCT_OUT not defined. Please run " - "envsetup.sh and lunch/choosecombo") - raise errors.AbortError - return path - - -def GetTargetNativeTestPath(): - """Returns the full pathname to target/product data/nativetest/ directory. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - The absolute file path of the Android target native test directory. - - Raises: - AbortError: if Android target native test directory could not be found. - """ - path = os.path.join(GetProductOut(), "data", "nativetest") - if not os.path.exists(path): - logger.Log("Error: Target native test path could not be found") - raise errors.AbortError - return path - - -def GetTargetSystemBin(): - """Returns the full pathname to the target/product system/bin directory. - - Typically the value of the env variable $ANDROID_PRODUCT_OUT/system/bin - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - The absolute file path of the Android target system bin directory. - - Raises: - AbortError: if Android target system bin directory could not be found. - """ - path = os.path.join(GetProductOut(), "system", "bin") - if not os.path.exists(path): - logger.Log("Error: Target system bin path could not be found") - raise errors.AbortError - return path - -def GetHostLibraryPath(): - """Returns the full pathname to the host java library output directory. - - Typically $ANDROID_HOST_OUT/framework. - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - The absolute file path of the Android host java library directory. - - Raises: - AbortError: if Android host java library directory could not be found. - """ - path = os.path.join(GetHostOutDir(), "framework") - if not os.path.exists(path): - logger.Log("Error: Host library path could not be found %s" % path) - raise errors.AbortError - return path - -def GetTestAppPath(): - """Returns the full pathname to the test app build output directory. - - Typically $ANDROID_PRODUCT_OUT/data/app - - Assumes build environment has been properly configured by envsetup & - lunch/choosecombo. - - Returns: - The absolute file path of the Android test app build directory. - """ - return os.path.join(GetProductOut(), "data", "app") diff --git a/testrunner/android_manifest.py b/testrunner/android_manifest.py deleted file mode 100644 index 6e8bd6c71..000000000 --- a/testrunner/android_manifest.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""In memory representation of AndroidManifest.xml file. - -Specification of AndroidManifest.xml can be found at -http://developer.android.com/guide/topics/manifest/manifest-intro.html -""" - -# python imports -import os -import xml.dom.minidom -import xml.parsers - - -class AndroidManifest(object): - """In memory representation of AndroidManifest.xml file.""" - - FILENAME = 'AndroidManifest.xml' - - def __init__(self, app_path=None): - if app_path: - self._ParseManifest(app_path) - - def GetAppPath(self): - """Retrieve file system path to this manifest file's directory.""" - return self._app_path - - def GetPackageName(self): - """Retrieve package name defined at . - - Returns: - Package name if defined, otherwise None - """ - manifest = self._GetManifestElement() - if not manifest or not manifest.hasAttribute('package'): - return None - return manifest.getAttribute('package') - - def _ParseManifest(self, app_path): - """Parse AndroidManifest.xml at the specified path. - - Args: - app_path: path to folder containing AndroidManifest.xml - Raises: - IOError: AndroidManifest.xml cannot be found at given path, or cannot be - opened for reading - """ - self._app_path = app_path - self._manifest_path = os.path.join(app_path, self.FILENAME) - self._dom = xml.dom.minidom.parse(self._manifest_path) - - def AddUsesSdk(self, min_sdk_version): - """Adds a uses-sdk element to manifest. - - Args: - min_sdk_version: value to provide for minSdkVersion attribute. - """ - manifest = self._GetManifestElement() - uses_sdk_elements = manifest.getElementsByTagName('uses-sdk') - if uses_sdk_elements: - uses_sdk_element = uses_sdk_elements[0] - else: - uses_sdk_element = self._dom.createElement('uses-sdk') - manifest.appendChild(uses_sdk_element) - - uses_sdk_element.setAttribute('android:minSdkVersion', min_sdk_version) - self._SaveXml() - - def GetInstrumentationNames(self): - """Get the instrumentation names from manifest. - - Returns: - list of names, might be empty - """ - instr_elements = self._dom.getElementsByTagName('instrumentation') - instrs = [] - for element in instr_elements: - instrs.append(element.getAttribute('android:name')) - return instrs - - def _GetManifestElement(self): - """Retrieve the root manifest element. - - Returns: - the DOM element for manifest or None. - """ - manifests = self._dom.getElementsByTagName('manifest') - if not manifests: - return None - return manifests[0] - - def _SaveXml(self): - """Saves the manifest to disk.""" - self._dom.writexml(open(self._manifest_path, mode='w'), encoding='utf-8') - - -def CreateAndroidManifest(path): - """Factory method for creating a AndroidManifest. - - Args: - path: the directory for the manifest file - - Return: - the AndroidManifest or None if there was no file present - """ - manifest_path = os.path.join(path, AndroidManifest.FILENAME) - if os.path.isfile(manifest_path): - manifest = AndroidManifest() - manifest._ParseManifest(path) - return manifest - else: - return None diff --git a/testrunner/android_mk.py b/testrunner/android_mk.py deleted file mode 100644 index 7a7769f68..000000000 --- a/testrunner/android_mk.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""In memory representation of Android.mk file. - -Specifications for Android.mk can be found at -development/ndk/docs/ANDROID-MK.txt -""" - -import os -import re -from sets import Set - -import logger - -class AndroidMK(object): - """In memory representation of Android.mk file.""" - - _RE_INCLUDE = re.compile(r'include\s+\$\((.+)\)') - _RE_VARIABLE_REF = re.compile(r'\$\((.+)\)') - _VAR_DELIMITER = ":=" - FILENAME = "Android.mk" - CERTIFICATE = "LOCAL_CERTIFICATE" - PACKAGE_NAME = "LOCAL_PACKAGE_NAME" - - def __init__(self): - self._includes = Set() # variables included in makefile - self._variables = {} # variables defined in makefile - self._has_gtestlib = False - - def _ProcessMKLine(self, line): - """Add a variable definition or include. - - Ignores unrecognized lines. - - Args: - line: line of text from makefile - """ - m = self._RE_INCLUDE.match(line) - if m: - self._includes.add(m.group(1)) - else: - parts = line.split(self._VAR_DELIMITER) - if len(parts) > 1: - self._variables[parts[0].strip()] = parts[1].strip() - # hack, look for explicit mention of libgtest_main - if line.find('libgtest_main') != -1: - self._has_gtestlib = True - - def GetVariable(self, identifier): - """Retrieve makefile variable. - - Args: - identifier: name of variable to retrieve - Returns: - value of specified identifier, None if identifier not found in makefile - """ - # use dict.get(x) rather than dict[x] to avoid KeyError exception, - # so None is returned if identifier not found - return self._variables.get(identifier, None) - - def GetExpandedVariable(self, identifier): - """Retrieve makefile variable. - - If variable value refers to another variable, recursively expand it to - find its literal value - - Args: - identifier: name of variable to retrieve - Returns: - value of specified identifier, None if identifier not found in makefile - """ - # use dict.get(x) rather than dict[x] to avoid KeyError exception, - # so None is returned if identifier not found - return self.__RecursiveGetVariable(identifier, Set()) - - def __RecursiveGetVariable(self, identifier, visited_variables): - variable_value = self.GetVariable(identifier) - if not variable_value: - return None - if variable_value in visited_variables: - raise RuntimeError('recursive loop found for makefile variable %s' - % variable_value) - m = self._RE_VARIABLE_REF.match(variable_value) - if m: - logger.SilentLog('Found variable ref %s for identifier %s' - % (variable_value, identifier)) - variable_ref = m.group(1) - visited_variables.add(variable_ref) - return self.__RecursiveGetVariable(variable_ref, visited_variables) - else: - return variable_value - - def HasInclude(self, identifier): - """Check variable is included in makefile. - - Args: - identifer: name of variable to check - Returns: - True if identifer is included in makefile, otherwise False - """ - return identifier in self._includes - - def IncludesMakefilesUnder(self): - """Check if makefile has a 'include makefiles under here' rule""" - return self.HasInclude('call all-makefiles-under,$(LOCAL_PATH)') - - def HasJavaLibrary(self, library_name): - """Check if library is specified as a local java library in makefile. - - Args: - library_name: name of library to check - Returns: - True if library_name is included in makefile, otherwise False - """ - java_lib_string = self.GetExpandedVariable('LOCAL_JAVA_LIBRARIES') - if java_lib_string: - java_libs = java_lib_string.split(' ') - return library_name in java_libs - return False - - def HasGTest(self): - """Check if makefile includes rule to build a native gtest. - - Returns: - True if rule to build native test is in makefile, otherwise False - """ - return self._has_gtestlib or self.HasInclude('BUILD_NATIVE_TEST') - - def _ParseMK(self, mk_path): - """Parse Android.mk at the specified path. - - Args: - mk_path: path to Android.mk - Raises: - IOError: Android.mk cannot be found at given path, or cannot be opened - for reading - """ - mk = open(mk_path) - for line in mk: - self._ProcessMKLine(line) - mk.close() - - -def CreateAndroidMK(path, filename=AndroidMK.FILENAME): - """Factory method for creating a AndroidMK. - - Args: - path: the directory of the make file - filename: the filename of the makefile - - Return: - the AndroidMK or None if there was no file present - """ - mk_path = os.path.join(path, filename) - if os.path.isfile(mk_path): - mk = AndroidMK() - mk._ParseMK(mk_path) - return mk - else: - return None diff --git a/testrunner/coverage/__init__.py b/testrunner/coverage/__init__.py deleted file mode 100644 index 4be2078b0..000000000 --- a/testrunner/coverage/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['coverage', 'coverage_targets', 'coverage_target'] diff --git a/testrunner/coverage/coverage.py b/testrunner/coverage/coverage.py deleted file mode 100755 index 824f5c5f0..000000000 --- a/testrunner/coverage/coverage.py +++ /dev/null @@ -1,338 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utilities for generating code coverage reports for Android tests.""" - -# Python imports -import glob -import optparse -import os - -# local imports -import android_build -import android_mk -import coverage_target -import coverage_targets -import errors -import logger -import run_command - - -class CoverageGenerator(object): - """Helper utility for obtaining code coverage results on Android. - - Intended to simplify the process of building,running, and generating code - coverage results for a pre-defined set of tests and targets - """ - - # path to EMMA host jar, relative to Android build root - _EMMA_JAR = os.path.join("external", "emma", "lib", "emma.jar") - _TEST_COVERAGE_EXT = "ec" - # root path of generated coverage report files, relative to Android build root - _COVERAGE_REPORT_PATH = "emma" - _TARGET_DEF_FILE = "coverage_targets.xml" - _CORE_TARGET_PATH = os.path.join("development", "testrunner", - _TARGET_DEF_FILE) - # vendor glob file path patterns to tests, relative to android - # build root - _VENDOR_TARGET_PATH = os.path.join("vendor", "*", "tests", "testinfo", - _TARGET_DEF_FILE) - - # path to root of target build intermediates - _TARGET_INTERMEDIATES_BASE_PATH = os.path.join("target", "common", - "obj") - - def __init__(self, adb_interface): - self._root_path = android_build.GetTop() - self._out_path = android_build.GetOut() - self._output_root_path = os.path.join(self._out_path, - self._COVERAGE_REPORT_PATH) - self._emma_jar_path = os.path.join(self._root_path, self._EMMA_JAR) - self._adb = adb_interface - self._targets_manifest = self._ReadTargets() - - def ExtractReport(self, - test_suite_name, - target, - device_coverage_path, - output_path=None, - test_qualifier=None): - """Extract runtime coverage data and generate code coverage report. - - Assumes test has just been executed. - Args: - test_suite_name: name of TestSuite to generate coverage data for - target: the CoverageTarget to use as basis for coverage calculation - device_coverage_path: location of coverage file on device - output_path: path to place output files in. If None will use - /<_COVERAGE_REPORT_PATH>// - test_qualifier: designates mode test was run with. e.g size=small. - If not None, this will be used to customize output_path as shown above. - - Returns: - absolute file path string of generated html report file. - """ - if output_path is None: - report_name = test_suite_name - if test_qualifier: - report_name = report_name + "-" + test_qualifier - output_path = os.path.join(self._out_path, - self._COVERAGE_REPORT_PATH, - target.GetName(), - report_name) - - coverage_local_name = "%s.%s" % (report_name, - self._TEST_COVERAGE_EXT) - coverage_local_path = os.path.join(output_path, - coverage_local_name) - if self._adb.Pull(device_coverage_path, coverage_local_path): - - report_path = os.path.join(output_path, - report_name) - return self._GenerateReport(report_path, coverage_local_path, [target], - do_src=True) - return None - - def _GenerateReport(self, report_path, coverage_file_path, targets, - do_src=True): - """Generate the code coverage report. - - Args: - report_path: absolute file path of output file, without extension - coverage_file_path: absolute file path of code coverage result file - targets: list of CoverageTargets to use as base for code coverage - measurement. - do_src: True if generate coverage report with source linked in. - Note this will increase size of generated report. - - Returns: - absolute file path to generated report file. - """ - input_metadatas = self._GatherMetadatas(targets) - - if do_src: - src_arg = self._GatherSrcs(targets) - else: - src_arg = "" - - report_file = "%s.html" % report_path - cmd1 = ("java -cp %s emma report -r html -in %s %s %s " % - (self._emma_jar_path, coverage_file_path, input_metadatas, src_arg)) - cmd2 = "-Dreport.html.out.file=%s" % report_file - self._RunCmd(cmd1 + cmd2) - return report_file - - def _GatherMetadatas(self, targets): - """Builds the emma input metadata argument from provided targets. - - Args: - targets: list of CoverageTargets - - Returns: - input metadata argument string - """ - input_metadatas = "" - for target in targets: - input_metadata = os.path.join(self._GetBuildIntermediatePath(target), - "coverage.em") - input_metadatas += " -in %s" % input_metadata - return input_metadatas - - def _GetBuildIntermediatePath(self, target): - return os.path.join( - self._out_path, self._TARGET_INTERMEDIATES_BASE_PATH, target.GetType(), - "%s_intermediates" % target.GetName()) - - def _GatherSrcs(self, targets): - """Builds the emma input source path arguments from provided targets. - - Args: - targets: list of CoverageTargets - Returns: - source path arguments string - """ - src_list = [] - for target in targets: - target_srcs = target.GetPaths() - for path in target_srcs: - src_list.append("-sp %s" % os.path.join(self._root_path, path)) - return " ".join(src_list) - - def _MergeFiles(self, input_paths, dest_path): - """Merges a set of emma coverage files into a consolidated file. - - Args: - input_paths: list of string absolute coverage file paths to merge - dest_path: absolute file path of destination file - """ - input_list = [] - for input_path in input_paths: - input_list.append("-in %s" % input_path) - input_args = " ".join(input_list) - self._RunCmd("java -cp %s emma merge %s -out %s" % (self._emma_jar_path, - input_args, dest_path)) - - def _RunCmd(self, cmd): - """Runs and logs the given os command.""" - run_command.RunCommand(cmd, return_output=False) - - def _CombineTargetCoverage(self): - """Combines all target mode code coverage results. - - Will find all code coverage data files in direct sub-directories of - self._output_root_path, and combine them into a single coverage report. - Generated report is placed at self._output_root_path/android.html - """ - coverage_files = self._FindCoverageFiles(self._output_root_path) - combined_coverage = os.path.join(self._output_root_path, - "android.%s" % self._TEST_COVERAGE_EXT) - self._MergeFiles(coverage_files, combined_coverage) - report_path = os.path.join(self._output_root_path, "android") - # don't link to source, to limit file size - self._GenerateReport(report_path, combined_coverage, - self._targets_manifest.GetTargets(), do_src=False) - - def _CombineTestCoverage(self): - """Consolidates code coverage results for all target result directories.""" - target_dirs = os.listdir(self._output_root_path) - for target_name in target_dirs: - output_path = os.path.join(self._output_root_path, target_name) - target = self._targets_manifest.GetTarget(target_name) - if os.path.isdir(output_path) and target is not None: - coverage_files = self._FindCoverageFiles(output_path) - combined_coverage = os.path.join(output_path, "%s.%s" % - (target_name, self._TEST_COVERAGE_EXT)) - self._MergeFiles(coverage_files, combined_coverage) - report_path = os.path.join(output_path, target_name) - self._GenerateReport(report_path, combined_coverage, [target]) - else: - logger.Log("%s is not a valid target directory, skipping" % output_path) - - def _FindCoverageFiles(self, root_path): - """Finds all files in /*/*.<_TEST_COVERAGE_EXT>. - - Args: - root_path: absolute file path string to search from - Returns: - list of absolute file path strings of coverage files - """ - file_pattern = os.path.join(root_path, "*", "*.%s" % - self._TEST_COVERAGE_EXT) - coverage_files = glob.glob(file_pattern) - return coverage_files - - def _ReadTargets(self): - """Parses the set of coverage target data. - - Returns: - a CoverageTargets object that contains set of parsed targets. - Raises: - AbortError if a fatal error occurred when parsing the target files. - """ - core_target_path = os.path.join(self._root_path, self._CORE_TARGET_PATH) - try: - targets = coverage_targets.CoverageTargets() - targets.Parse(core_target_path) - vendor_targets_pattern = os.path.join(self._root_path, - self._VENDOR_TARGET_PATH) - target_file_paths = glob.glob(vendor_targets_pattern) - for target_file_path in target_file_paths: - targets.Parse(target_file_path) - return targets - except errors.ParseError: - raise errors.AbortError - - def TidyOutput(self): - """Runs tidy on all generated html files. - - This is needed to the html files can be displayed cleanly on a web server. - Assumes tidy is on current PATH. - """ - logger.Log("Tidying output files") - self._TidyDir(self._output_root_path) - - def _TidyDir(self, dir_path): - """Recursively tidy all html files in given dir_path.""" - html_file_pattern = os.path.join(dir_path, "*.html") - html_files_iter = glob.glob(html_file_pattern) - for html_file_path in html_files_iter: - os.system("tidy -m -errors -quiet %s" % html_file_path) - sub_dirs = os.listdir(dir_path) - for sub_dir_name in sub_dirs: - sub_dir_path = os.path.join(dir_path, sub_dir_name) - if os.path.isdir(sub_dir_path): - self._TidyDir(sub_dir_path) - - def CombineCoverage(self): - """Create combined coverage reports for all targets and tests.""" - self._CombineTestCoverage() - self._CombineTargetCoverage() - - def GetCoverageTarget(self, name): - """Find the CoverageTarget for given name""" - target = self._targets_manifest.GetTarget(name) - if target is None: - msg = ["Error: test references undefined target %s." % name] - msg.append(" Ensure target is defined in %s" % self._TARGET_DEF_FILE) - raise errors.AbortError(msg) - return target - - def GetCoverageTargetForPath(self, path): - """Find the CoverageTarget for given file system path""" - android_mk_path = os.path.join(path, "Android.mk") - if os.path.exists(android_mk_path): - android_mk_parser = android_mk.CreateAndroidMK(path) - target = coverage_target.CoverageTarget() - target.SetBuildPath(os.path.join(path, "src")) - target.SetName(android_mk_parser.GetVariable(android_mk_parser.PACKAGE_NAME)) - target.SetType("APPS") - return target - else: - msg = "No Android.mk found at %s" % path - raise errors.AbortError(msg) - - -def EnableCoverageBuild(): - """Enable building an Android target with code coverage instrumentation.""" - os.environ["EMMA_INSTRUMENT"] = "true" - -def Run(): - """Does coverage operations based on command line args.""" - # TODO: do we want to support combining coverage for a single target - - try: - parser = optparse.OptionParser(usage="usage: %prog --combine-coverage") - parser.add_option( - "-c", "--combine-coverage", dest="combine_coverage", default=False, - action="store_true", help="Combine coverage results stored given " - "android root path") - parser.add_option( - "-t", "--tidy", dest="tidy", default=False, action="store_true", - help="Run tidy on all generated html files") - - options, args = parser.parse_args() - - coverage = CoverageGenerator(None) - if options.combine_coverage: - coverage.CombineCoverage() - if options.tidy: - coverage.TidyOutput() - except errors.AbortError: - logger.SilentLog("Exiting due to AbortError") - -if __name__ == "__main__": - Run() diff --git a/testrunner/coverage/coverage_target.py b/testrunner/coverage/coverage_target.py deleted file mode 100644 index 9d08a5c32..000000000 --- a/testrunner/coverage/coverage_target.py +++ /dev/null @@ -1,48 +0,0 @@ -# -# Copyright 2012, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -class CoverageTarget: - """ Represents a code coverage target definition""" - - def __init__(self): - self._name = None - self._type = None - self._build_path = None - self._paths = [] - - def GetName(self): - return self._name - - def SetName(self, name): - self._name = name - - def GetPaths(self): - return self._paths - - def AddPath(self, path): - self._paths.append(path) - - def GetType(self): - return self._type - - def SetType(self, buildtype): - self._type = buildtype - - def GetBuildPath(self): - return self._build_path - - def SetBuildPath(self, build_path): - self._build_path = build_path - diff --git a/testrunner/coverage/coverage_targets.py b/testrunner/coverage/coverage_targets.py deleted file mode 100644 index 11988053d..000000000 --- a/testrunner/coverage/coverage_targets.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import xml.dom.minidom -import xml.parsers -import os - - -import coverage_target -import logger -import errors - -class CoverageTargets: - """Accessor for the code coverage target xml file - Expects the following format: - - ] (0..*) - These are relative to build_path. If missing, - assumes 'src' - >/target> - - TODO: add more format checking - """ - - _TARGET_TAG_NAME = 'coverage_target' - _NAME_ATTR = 'name' - _TYPE_ATTR = 'type' - _BUILD_ATTR = 'build_path' - _SRC_TAG = 'src' - _PATH_ATTR = 'path' - - def __init__(self, ): - self._target_map= {} - - def __iter__(self): - return iter(self._target_map.values()) - - def Parse(self, file_path): - """Parse the coverage target data from from given file path, and add it to - the current object - Args: - file_path: absolute file path to parse - Raises: - errors.ParseError if file_path cannot be parsed - """ - try: - doc = xml.dom.minidom.parse(file_path) - except IOError: - # Error: The results file does not exist - logger.Log('Results file %s does not exist' % file_path) - raise errors.ParseError - except xml.parsers.expat.ExpatError: - logger.Log('Error Parsing xml file: %s ' % file_path) - raise errors.ParseError - - target_elements = doc.getElementsByTagName(self._TARGET_TAG_NAME) - - for target_element in target_elements: - target = coverage_target.CoverageTarget() - self._ParseCoverageTarget(target, target_element) - self._AddTarget(target) - - def _AddTarget(self, target): - self._target_map[target.GetName()] = target - - def GetBuildTargets(self): - """ returns list of target names """ - build_targets = [] - for target in self: - build_targets.append(target.GetName()) - return build_targets - - def GetTargets(self): - """ returns list of CoverageTarget""" - return self._target_map.values() - - def GetTarget(self, name): - """ returns CoverageTarget for given name. None if not found """ - try: - return self._target_map[name] - except KeyError: - return None - - def _ParseCoverageTarget(self, target, target_element): - """Parse coverage data from XML. - - Args: - target: the Coverage object to populate - target_element: the XML element to get data from - """ - target.SetName(target_element.getAttribute(self._NAME_ATTR)) - target.SetType(target_element.getAttribute(self._TYPE_ATTR)) - target.SetBuildPath(target_element.getAttribute(self._BUILD_ATTR)) - self._paths = [] - self._ParsePaths(target, target_element) - - def _ParsePaths(self, target, target_element): - src_elements = target_element.getElementsByTagName(self._SRC_TAG) - if len(src_elements) <= 0: - # no src tags specified. Assume build_path + src - target.AddPath(os.path.join(target.GetBuildPath(), "src")) - for src_element in src_elements: - rel_path = src_element.getAttribute(self._PATH_ATTR) - target.AddPath(os.path.join(target.GetBuildPath(), rel_path)) - - -def Parse(xml_file_path): - """parses out a file_path class from given path to xml""" - targets = CoverageTargets() - targets.Parse(xml_file_path) - return targets diff --git a/testrunner/coverage_targets.xml b/testrunner/coverage_targets.xml deleted file mode 100644 index df8e7af63..000000000 --- a/testrunner/coverage_targets.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/testrunner/create_test.py b/testrunner/create_test.py deleted file mode 100755 index 90da25463..000000000 --- a/testrunner/create_test.py +++ /dev/null @@ -1,246 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utility to create Android project files for tests.""" - -# python imports -import datetime -import optparse -import os -import string -import sys - -# local imports -import android_mk -import android_manifest - - -class TestsConsts(object): - """Constants for test Android.mk and AndroidManifest.xml creation.""" - - MK_BUILD_INCLUDE = "call all-makefiles-under,$(LOCAL_PATH)" - MK_BUILD_STRING = "\ninclude $(%s)\n" % MK_BUILD_INCLUDE - TEST_MANIFEST_TEMPLATE = """ - - - - - - - - - - - -""" - TEST_MK_TEMPLATE = """LOCAL_PATH := $$(call my-dir) -include $$(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.test.runner - -LOCAL_SRC_FILES := $$(call all-java-files-under, src) - -LOCAL_PACKAGE_NAME := ${MODULE_NAME}Tests${CERTIFICATE} - -LOCAL_INSTRUMENTATION_FOR := ${MODULE_NAME} - -LOCAL_SDK_VERSION := current - -include $$(BUILD_PACKAGE) -""" - TESTS_FOLDER = "tests" - - -def _GenerateTestManifest(manifest, module_name, mapping=None): - """Create and populate tests/AndroidManifest.xml with variable values from - Android.mk and AndroidManifest.xml. - - Does nothing if tests/AndroidManifest.xml already exists. - - Args: - manifest: AndroidManifest object for application manifest - module_name: module name used for labelling - mapping: optional user defined mapping of variable values, replaces values - extracted from AndroidManifest.xml - Raises: - IOError: tests/AndroidManifest.xml cannot be opened for writing - """ - # skip if file already exists - tests_path = "%s/%s" % (manifest.GetAppPath(), TestsConsts.TESTS_FOLDER) - tests_manifest_path = "%s/%s" % (tests_path, manifest.FILENAME) - if os.path.exists(tests_manifest_path): - _PrintMessage("%s already exists, not overwritten" % tests_manifest_path) - return - - if not mapping: - package_name = manifest.GetPackageName() - mapping = {"PACKAGE_NAME":package_name, "MODULE_NAME":module_name, - "YEAR":datetime.date.today().year} - output = string.Template(TestsConsts.TEST_MANIFEST_TEMPLATE).substitute(mapping) - - # create tests folder if not existent - if not os.path.exists(tests_path): - os.mkdir(tests_path) - - # write tests/AndroidManifest.xml - tests_manifest = open(tests_manifest_path, mode="w") - tests_manifest.write(output) - tests_manifest.close() - _PrintMessage("Created %s" % tests_manifest_path) - - -def _GenerateTestMK(mk, app_path, mapping=None): - """Create and populate tests/Android.mk with variable values from Android.mk. - - Does nothing if tests/Android.mk already exists. - - Args: - mk: AndroidMK object for application makefile - app_path: path to the application being tested - mapping: optional user defined mapping of variable values, replaces - values stored in mk - Raises: - IOError: tests/Android.mk cannot be opened for writing - """ - # skip if file already exists - tests_path = "%s/%s" % (app_path, TestsConsts.TESTS_FOLDER) - tests_mk_path = "%s/%s" % (tests_path, mk.FILENAME) - if os.path.exists(tests_mk_path): - _PrintMessage("%s already exists, not overwritten" % tests_mk_path) - return - - # append test build if not existent in makefile - if not mk.HasInclude(TestsConsts.MK_BUILD_INCLUDE): - mk_path = "%s/%s" % (app_path, mk.FILENAME) - mk_file = open(mk_path, mode="a") - mk_file.write(TestsConsts.MK_BUILD_STRING) - mk_file.close() - - # construct tests/Android.mk - # include certificate definition if existent in makefile - certificate = mk.GetVariable(mk.CERTIFICATE) - if certificate: - cert_definition = ("\n%s := %s" % (mk.CERTIFICATE, certificate)) - else: - cert_definition = "" - if not mapping: - module_name = mk.GetVariable(mk.PACKAGE_NAME) - mapping = {"MODULE_NAME":module_name, "CERTIFICATE":cert_definition} - output = string.Template(TestsConsts.TEST_MK_TEMPLATE).substitute(mapping) - - # create tests folder if not existent - if not os.path.exists(tests_path): - os.mkdir(tests_path) - - # write tests/Android.mk to disk - tests_mk = open(tests_mk_path, mode="w") - tests_mk.write(output) - tests_mk.close() - _PrintMessage("Created %s" % tests_mk_path) - - -def _ParseArgs(argv): - """Parse the command line arguments. - - Args: - argv: the list of command line arguments - Returns: - a tuple of options and individual command line arguments. - """ - parser = optparse.OptionParser(usage="%s " % sys.argv[0]) - options, args = parser.parse_args(argv) - if len(args) < 1: - _PrintError("Error: Incorrect syntax") - parser.print_usage() - sys.exit() - return (options, args) - - -def _PrintMessage(msg): - print >> sys.stdout, msg - - -def _PrintError(msg): - print >> sys.stderr, msg - - -def _ValidateInputFiles(mk, manifest): - """Verify that required variables are defined in input files. - - Args: - mk: AndroidMK object for application makefile - manifest: AndroidManifest object for application manifest - Raises: - RuntimeError: mk does not define LOCAL_PACKAGE_NAME or - manifest does not define package variable - """ - module_name = mk.GetVariable(mk.PACKAGE_NAME) - if not module_name: - raise RuntimeError("Variable %s missing from %s" % - (mk.PACKAGE_NAME, mk.FILENAME)) - - package_name = manifest.GetPackageName() - if not package_name: - raise RuntimeError("Variable package missing from %s" % manifest.FILENAME) - - -def main(argv): - options, args = _ParseArgs(argv) - app_path = args[0]; - - if not os.path.exists(app_path): - _PrintError("Error: Application path %s not found" % app_path) - sys.exit() - - try: - mk = android_mk.CreateAndroidMK(path=app_path) - manifest = android_manifest.AndroidManifest(app_path=app_path) - _ValidateInputFiles(mk, manifest) - - module_name = mk.GetVariable(mk.PACKAGE_NAME) - _GenerateTestMK(mk, app_path) - _GenerateTestManifest(manifest, module_name) - except Exception, e: - _PrintError("Error: %s" % e) - _PrintError("Error encountered, script aborted") - sys.exit() - - src_path = app_path + "/tests/src" - if not os.path.exists(src_path): - os.mkdir(src_path) - - -if __name__ == "__main__": - main(sys.argv[1:]) diff --git a/testrunner/errors.py b/testrunner/errors.py deleted file mode 100755 index e163dd45b..000000000 --- a/testrunner/errors.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Defines common exception classes for this package.""" - - -class MsgException(Exception): - """Generic exception with an optional string msg.""" - def __init__(self, msg=""): - self.msg = msg - - -class WaitForResponseTimedOutError(Exception): - """We sent a command and had to wait too long for response.""" - - -class DeviceUnresponsiveError(Exception): - """Device is unresponsive to command.""" - - -class InstrumentationError(Exception): - """Failed to run instrumentation.""" - - -class AbortError(MsgException): - """Generic exception that indicates a fatal error has occurred and program - execution should be aborted.""" - - -class ParseError(MsgException): - """Raised when xml data to parse has unrecognized format.""" - diff --git a/testrunner/logger.py b/testrunner/logger.py deleted file mode 100755 index 61463a198..000000000 --- a/testrunner/logger.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2007, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Simple logging utility. Dumps log messages to stdout, and optionally, to a -log file. - -Init(path) must be called to enable logging to a file -""" - -import datetime - -_LOG_FILE = None -_verbose = False -_log_time = True - -def Init(log_file_path): - """Set the path to the log file""" - global _LOG_FILE - _LOG_FILE = log_file_path - print "Using log file: %s" % _LOG_FILE - -def GetLogFilePath(): - """Returns the path and name of the Log file""" - global _LOG_FILE - return _LOG_FILE - -def Log(new_str): - """Appends new_str to the end of _LOG_FILE and prints it to stdout. - - Args: - # new_str is a string. - new_str: 'some message to log' - """ - msg = _PrependTimeStamp(new_str) - print msg - _WriteLog(msg) - -def _WriteLog(msg): - global _LOG_FILE - if _LOG_FILE is not None: - file_handle = file(_LOG_FILE, 'a') - file_handle.write('\n' + str(msg)) - file_handle.close() - -def _PrependTimeStamp(log_string): - """Returns the log_string prepended with current timestamp """ - global _log_time - if _log_time: - return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"), - log_string) - else: - # timestamp logging disabled - return log_string - -def SilentLog(new_str): - """Silently log new_str. Unless verbose mode is enabled, will log new_str - only to the log file - Args: - # new_str is a string. - new_str: 'some message to log' - """ - global _verbose - msg = _PrependTimeStamp(new_str) - if _verbose: - print msg - _WriteLog(msg) - -def SetVerbose(new_verbose=True): - """ Enable or disable verbose logging""" - global _verbose - _verbose = new_verbose - -def SetTimestampLogging(new_timestamp=True): - """ Enable or disable outputting a timestamp with each log entry""" - global _log_time - _log_time = new_timestamp - -def main(): - pass - -if __name__ == '__main__': - main() diff --git a/testrunner/make_tree.py b/testrunner/make_tree.py deleted file mode 100644 index c8bac17e8..000000000 --- a/testrunner/make_tree.py +++ /dev/null @@ -1,116 +0,0 @@ -# -# Copyright 2012, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Data structure for processing makefiles.""" - -import os - -import android_build -import android_mk -import errors - -class MakeNode(object): - """Represents single node in make tree.""" - - def __init__(self, name, parent): - self._name = name - self._children_map = {} - self._is_leaf = False - self._parent = parent - self._includes_submake = None - if parent: - self._path = os.path.join(parent._GetPath(), name) - else: - self._path = "" - - def _AddPath(self, path_segs): - """Adds given path to this node. - - Args: - path_segs: list of path segments - """ - if not path_segs: - # done processing path - return self - current_seg = path_segs.pop(0) - child = self._children_map.get(current_seg) - if not child: - child = MakeNode(current_seg, self) - self._children_map[current_seg] = child - return child._AddPath(path_segs) - - def _SetLeaf(self, is_leaf): - self._is_leaf = is_leaf - - def _GetPath(self): - return self._path - - def _DoesIncludesSubMake(self): - if self._includes_submake is None: - if self._is_leaf: - path = os.path.join(android_build.GetTop(), self._path) - mk_parser = android_mk.CreateAndroidMK(path) - self._includes_submake = mk_parser.IncludesMakefilesUnder() - else: - self._includes_submake = False - return self._includes_submake - - def _DoesParentIncludeMe(self): - return self._parent and self._parent._DoesIncludesSubMake() - - def _BuildPrunedMakeList(self, make_list): - if self._is_leaf and not self._DoesParentIncludeMe(): - make_list.append(os.path.join(self._path, "Android.mk")) - for child in self._children_map.itervalues(): - child._BuildPrunedMakeList(make_list) - - -class MakeTree(MakeNode): - """Data structure for building a non-redundant set of Android.mk paths. - - Used to collapse set of Android.mk files to use to prevent issuing make - command that include same module multiple times due to include rules. - """ - - def __init__(self): - super(MakeTree, self).__init__("", None) - - def AddPath(self, path): - """Adds make directory path to tree. - - Will have no effect if path is already included in make set. - - Args: - path: filesystem path to directory to build, relative to build root. - """ - path = os.path.normpath(path) - mk_path = os.path.join(android_build.GetTop(), path, "Android.mk") - if not os.path.isfile(mk_path): - raise errors.AbortError("%s does not exist" % mk_path) - path_segs = path.split(os.sep) - child = self._AddPath(path_segs) - child._SetLeaf(True) - - def GetPrunedMakeList(self): - """Return as list of the minimum set of Android.mk files necessary to - build all leaf nodes in tree. - """ - make_list = [] - self._BuildPrunedMakeList(make_list) - return make_list - - def IsEmpty(self): - return not self._children_map - diff --git a/testrunner/run_command.py b/testrunner/run_command.py deleted file mode 100755 index d398daa28..000000000 --- a/testrunner/run_command.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2007, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# System imports -import os -import signal -import subprocess -import threading -import time - -# local imports -import errors -import logger - -_abort_on_error = False - -def SetAbortOnError(abort=True): - """Sets behavior of RunCommand to throw AbortError if command process returns - a negative error code""" - global _abort_on_error - _abort_on_error = abort - -def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True, - stdin_input=None): - """Spawn and retry a subprocess to run the given shell command. - - Args: - cmd: shell command to run - timeout_time: time in seconds to wait for command to run before aborting. - retry_count: number of times to retry command - return_output: if True return output of command as string. Otherwise, - direct output of command to stdout. - stdin_input: data to feed to stdin - Returns: - output of command - """ - result = None - while True: - try: - result = RunOnce(cmd, timeout_time=timeout_time, - return_output=return_output, stdin_input=stdin_input) - except errors.WaitForResponseTimedOutError: - if retry_count == 0: - raise - retry_count -= 1 - logger.Log("No response for %s, retrying" % cmd) - else: - # Success - return result - -def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None): - """Spawns a subprocess to run the given shell command. - - Args: - cmd: shell command to run - timeout_time: time in seconds to wait for command to run before aborting. - return_output: if True return output of command as string. Otherwise, - direct output of command to stdout. - stdin_input: data to feed to stdin - Returns: - output of command - Raises: - errors.WaitForResponseTimedOutError if command did not complete within - timeout_time seconds. - errors.AbortError is command returned error code and SetAbortOnError is on. - """ - start_time = time.time() - so = [] - pid = [] - global _abort_on_error, error_occurred - error_occurred = False - - def Run(): - global error_occurred - if return_output: - output_dest = subprocess.PIPE - else: - # None means direct to stdout - output_dest = None - if stdin_input: - stdin_dest = subprocess.PIPE - else: - stdin_dest = None - pipe = subprocess.Popen( - cmd, - executable='/bin/bash', - stdin=stdin_dest, - stdout=output_dest, - stderr=subprocess.STDOUT, - shell=True) - pid.append(pipe.pid) - try: - output = pipe.communicate(input=stdin_input)[0] - if output is not None and len(output) > 0: - so.append(output) - except OSError, e: - logger.SilentLog("failed to retrieve stdout from: %s" % cmd) - logger.Log(e) - so.append("ERROR") - error_occurred = True - if pipe.returncode: - logger.SilentLog("Error: %s returned %d error code" %(cmd, - pipe.returncode)) - error_occurred = True - - t = threading.Thread(target=Run) - t.start() - - break_loop = False - while not break_loop: - if not t.isAlive(): - break_loop = True - - # Check the timeout - if (not break_loop and timeout_time is not None - and time.time() > start_time + timeout_time): - try: - os.kill(pid[0], signal.SIGKILL) - except OSError: - # process already dead. No action required. - pass - - logger.SilentLog("about to raise a timeout for: %s" % cmd) - raise errors.WaitForResponseTimedOutError - if not break_loop: - time.sleep(0.1) - - t.join() - output = "".join(so) - if _abort_on_error and error_occurred: - raise errors.AbortError(msg=output) - - return "".join(so) - - -def RunHostCommand(binary, valgrind=False): - """Run a command on the host (opt using valgrind). - - Runs the host binary and returns the exit code. - If successfull, the output (stdout and stderr) are discarded, - but printed in case of error. - The command can be run under valgrind in which case all the - output are always discarded. - - Args: - binary: full path of the file to be run. - valgrind: If True the command will be run under valgrind. - - Returns: - The command exit code (int) - """ - if not valgrind: - subproc = subprocess.Popen(binary, stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - subproc.wait() - if subproc.returncode != 0: # In case of error print the output - print subproc.communicate()[0] - return subproc.returncode - else: - # Need the full path to valgrind to avoid other versions on the system. - subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck", - "--leak-check=yes", "-q", binary], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - # Cannot rely on the retcode of valgrind. Instead look for an empty output. - valgrind_out = subproc.communicate()[0].strip() - if valgrind_out: - print valgrind_out - return 1 - else: - return 0 - - -def HasValgrind(): - """Check that /usr/bin/valgrind exists. - - We look for the fullpath to avoid picking up 'alternative' valgrind - on the system. - - Returns: - True if a system valgrind was found. - """ - return os.path.exists("/usr/bin/valgrind") diff --git a/testrunner/runtest.py b/testrunner/runtest.py deleted file mode 100755 index 2072cfe0b..000000000 --- a/testrunner/runtest.py +++ /dev/null @@ -1,558 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Command line utility for running Android tests - -runtest helps automate the instructions for building and running tests -- It builds the corresponding test package for the code you want to test -- It pushes the test package to your device or emulator -- It launches InstrumentationTestRunner (or similar) to run the tests you -specify. - -runtest supports running tests whose attributes have been pre-defined in -_TEST_FILE_NAME files, (runtest ), or by specifying the file -system path to the test to run (runtest --path ). - -Do runtest --help to see full list of options. -""" - -# Python imports -import glob -import optparse -import os -import re -from sets import Set -import sys -import time - -# local imports -import adb_interface -import android_build -from coverage import coverage -import errors -import logger -import make_tree -import run_command -from test_defs import test_defs -from test_defs import test_walker - - -class TestRunner(object): - """Command line utility class for running pre-defined Android test(s).""" - - _TEST_FILE_NAME = "test_defs.xml" - - # file path to android core platform tests, relative to android build root - # TODO move these test data files to another directory - _CORE_TEST_PATH = os.path.join("development", "testrunner", - _TEST_FILE_NAME) - - # vendor glob file path patterns to tests, relative to android - # build root - _VENDOR_TEST_PATH = os.path.join("vendor", "*", "tests", "testinfo", - _TEST_FILE_NAME) - - _RUNTEST_USAGE = ( - "usage: runtest.py [options] short-test-name[s]\n\n" - "The runtest script works in two ways. You can query it " - "for a list of tests, or you can launch one or more tests.") - - # default value for make -jX - _DEFAULT_JOBS = 16 - - _DALVIK_VERIFIER_PROP = "dalvik.vm.dexopt-flags" - _DALVIK_VERIFIER_OFF_VALUE = "v=n" - _DALVIK_VERIFIER_OFF_PROP = "%s = %s" %(_DALVIK_VERIFIER_PROP, _DALVIK_VERIFIER_OFF_VALUE) - - # regular expression to match path to artifacts to install in make output - _RE_MAKE_INSTALL = re.compile(r'INSTALL-PATH:\s([^\s]+)\s(.*)$') - - def __init__(self): - # disable logging of timestamp - self._root_path = android_build.GetTop() - out_base_name = os.path.basename(android_build.GetOutDir()) - # regular expression to find remote device path from a file path relative - # to build root - pattern = r'' + out_base_name + r'\/target\/product\/\w+\/(.+)$' - self._re_make_install_path = re.compile(pattern) - logger.SetTimestampLogging(False) - self._adb = None - self._known_tests = None - self._options = None - self._test_args = None - self._tests_to_run = None - - def _ProcessOptions(self): - """Processes command-line options.""" - # TODO error messages on once-only or mutually-exclusive options. - user_test_default = os.path.join(os.environ.get("HOME"), ".android", - self._TEST_FILE_NAME) - - parser = optparse.OptionParser(usage=self._RUNTEST_USAGE) - - parser.add_option("-l", "--list-tests", dest="only_list_tests", - default=False, action="store_true", - help="To view the list of tests") - parser.add_option("-b", "--skip-build", dest="skip_build", default=False, - action="store_true", help="Skip build - just launch") - parser.add_option("-j", "--jobs", dest="make_jobs", - metavar="X", default=self._DEFAULT_JOBS, - help="Number of make jobs to use when building") - parser.add_option("-n", "--skip_execute", dest="preview", default=False, - action="store_true", - help="Do not execute, just preview commands") - parser.add_option("-i", "--build-install-only", dest="build_install_only", default=False, - action="store_true", - help="Do not execute, build tests and install to device only") - parser.add_option("-r", "--raw-mode", dest="raw_mode", default=False, - action="store_true", - help="Raw mode (for output to other tools)") - parser.add_option("-a", "--suite-assign", dest="suite_assign_mode", - default=False, action="store_true", - help="Suite assignment (for details & usage see " - "InstrumentationTestRunner)") - parser.add_option("-v", "--verbose", dest="verbose", default=False, - action="store_true", - help="Increase verbosity of %s" % sys.argv[0]) - parser.add_option("-w", "--wait-for-debugger", dest="wait_for_debugger", - default=False, action="store_true", - help="Wait for debugger before launching tests") - parser.add_option("-c", "--test-class", dest="test_class", - help="Restrict test to a specific class") - parser.add_option("-m", "--test-method", dest="test_method", - help="Restrict test to a specific method") - parser.add_option("-p", "--test-package", dest="test_package", - help="Restrict test to a specific java package") - parser.add_option("-z", "--size", dest="test_size", - help="Restrict test to a specific test size") - parser.add_option("--annotation", dest="test_annotation", - help="Include only those tests tagged with a specific" - " annotation") - parser.add_option("--not-annotation", dest="test_not_annotation", - help="Exclude any tests tagged with a specific" - " annotation") - parser.add_option("-u", "--user-tests-file", dest="user_tests_file", - metavar="FILE", default=user_test_default, - help="Alternate source of user test definitions") - parser.add_option("-o", "--coverage", dest="coverage", - default=False, action="store_true", - help="Generate code coverage metrics for test(s)") - parser.add_option("--coverage-target", dest="coverage_target_path", - default=None, - help="Path to app to collect code coverage target data for.") - parser.add_option("-k", "--skip-permissions", dest="skip_permissions", - default=False, action="store_true", - help="Do not grant runtime permissions during test package" - " installation.") - parser.add_option("-x", "--path", dest="test_path", - help="Run test(s) at given file system path") - parser.add_option("-t", "--all-tests", dest="all_tests", - default=False, action="store_true", - help="Run all defined tests") - parser.add_option("--continuous", dest="continuous_tests", - default=False, action="store_true", - help="Run all tests defined as part of the continuous " - "test set") - parser.add_option("--timeout", dest="timeout", - default=300, help="Set a timeout limit (in sec) for " - "running native tests on a device (default: 300 secs)") - parser.add_option("--suite", dest="suite", - help="Run all tests defined as part of the " - "the given test suite") - parser.add_option("--user", dest="user", - help="The user that test apks are installing to." - " This is the integer user id, e.g. 0 or 10." - " If no user is specified, apk will be installed with" - " adb's default behavior, which is currently all users.") - parser.add_option("--install-filter", dest="filter_re", - help="Regular expression which generated apks have to" - " match to be installed to target device. Default is None" - " and will install all packages built. This is" - " useful when the test path has a lot of apks but you" - " only care about one.") - parser.add_option("--no-hidden-api-checks", dest="no_hidden_api_checks", - default=False, action="store_true", - help="Disable hidden API checks in instrumentation" - " tests.") - group = optparse.OptionGroup( - parser, "Targets", "Use these options to direct tests to a specific " - "Android target") - group.add_option("-e", "--emulator", dest="emulator", default=False, - action="store_true", help="use emulator") - group.add_option("-d", "--device", dest="device", default=False, - action="store_true", help="use device") - group.add_option("-s", "--serial", dest="serial", - help="use specific serial") - parser.add_option_group(group) - self._options, self._test_args = parser.parse_args() - - if (not self._options.only_list_tests - and not self._options.all_tests - and not self._options.continuous_tests - and not self._options.suite - and not self._options.test_path - and len(self._test_args) < 1): - parser.print_help() - logger.SilentLog("at least one test name must be specified") - raise errors.AbortError - - self._adb = adb_interface.AdbInterface() - if self._options.emulator: - self._adb.SetEmulatorTarget() - elif self._options.device: - self._adb.SetDeviceTarget() - elif self._options.serial is not None: - self._adb.SetTargetSerial(self._options.serial) - if self._options.verbose: - logger.SetVerbose(True) - - if self._options.coverage_target_path: - self._options.coverage = True - - self._known_tests = self._ReadTests() - - self._options.host_lib_path = android_build.GetHostLibraryPath() - self._options.test_data_path = android_build.GetTestAppPath() - - def _ReadTests(self): - """Parses the set of test definition data. - - Returns: - A TestDefinitions object that contains the set of parsed tests. - Raises: - AbortError: If a fatal error occurred when parsing the tests. - """ - try: - known_tests = test_defs.TestDefinitions() - # only read tests when not in path mode - if not self._options.test_path: - core_test_path = os.path.join(self._root_path, self._CORE_TEST_PATH) - if os.path.isfile(core_test_path): - known_tests.Parse(core_test_path) - # read all /vendor/*/tests/testinfo/test_defs.xml paths - vendor_tests_pattern = os.path.join(self._root_path, - self._VENDOR_TEST_PATH) - test_file_paths = glob.glob(vendor_tests_pattern) - for test_file_path in test_file_paths: - known_tests.Parse(test_file_path) - if os.path.isfile(self._options.user_tests_file): - known_tests.Parse(self._options.user_tests_file) - return known_tests - except errors.ParseError: - raise errors.AbortError - - def _DumpTests(self): - """Prints out set of defined tests.""" - print "The following tests are currently defined:\n" - print "%-25s %-40s %s" % ("name", "build path", "description") - print "-" * 80 - for test in self._known_tests: - print "%-25s %-40s %s" % (test.GetName(), test.GetBuildPath(), - test.GetDescription()) - print "\nSee %s for more information" % self._TEST_FILE_NAME - - def _DoBuild(self): - logger.SilentLog("Building tests...") - tests = self._GetTestsToRun() - - # Build and install tests that do not get granted permissions - self._DoPermissionAwareBuild(tests, False) - - # Build and install tests that require granted permissions - self._DoPermissionAwareBuild(tests, True) - - def _DoPermissionAwareBuild(self, tests, test_requires_permissions): - # turn off dalvik verifier if necessary - # TODO: skip turning off verifier for now, since it puts device in bad - # state b/14088982 - #self._TurnOffVerifier(tests) - self._DoFullBuild(tests, test_requires_permissions) - - target_tree = make_tree.MakeTree() - - extra_args_set = [] - for test_suite in tests: - if test_suite.IsGrantedPermissions() == test_requires_permissions: - self._AddBuildTarget(test_suite, target_tree, extra_args_set) - - if not self._options.preview: - self._adb.EnableAdbRoot() - else: - logger.Log("adb root") - - if not target_tree.IsEmpty(): - if self._options.coverage: - coverage.EnableCoverageBuild() - target_tree.AddPath("external/emma") - - target_list = target_tree.GetPrunedMakeList() - target_dir_list = [re.sub(r'Android[.]mk$', r'', i) for i in target_list] - target_build_string = " ".join(target_list) - target_dir_build_string = " ".join(target_dir_list) - extra_args_string = " ".join(extra_args_set) - - install_path_goals = [] - mmma_goals = [] - for d in target_dir_list: - if d.startswith("./"): - d = d[2:] - if d.endswith("/"): - d = d[:-1] - install_path_goals.append("GET-INSTALL-PATH-IN-" + d.replace("/","-")) - mmma_goals.append("MODULES-IN-" + d.replace("/","-")) - # mmm cannot be used from python, so perform a similar operation using - # ONE_SHOT_MAKEFILE - cmd = 'ONE_SHOT_MAKEFILE="%s" make -j%s -C "%s" %s %s %s' % ( - target_build_string, self._options.make_jobs, self._root_path, - " ".join(install_path_goals), " ".join(mmma_goals), extra_args_string) - # mmma cannot be used from python, so perform a similar operation - alt_cmd = 'make -j%s -C "%s" -f build/core/main.mk %s %s' % ( - self._options.make_jobs, self._root_path, extra_args_string, " ".join(mmma_goals)) - - logger.Log(cmd) - if not self._options.preview: - run_command.SetAbortOnError() - try: - output = run_command.RunCommand(cmd, return_output=True, timeout_time=600) - ## Chances are this failed because it didn't build the dependencies - except errors.AbortError: - logger.Log("make failed. Trying to rebuild all dependencies.") - logger.Log("mmma -j%s %s" %(self._options.make_jobs, target_dir_build_string)) - # Try again with mma equivalent, which will build the dependencies - run_command.RunCommand(alt_cmd, return_output=False, timeout_time=600) - # Run mmm again to get the install paths only - output = run_command.RunCommand(cmd, return_output=True, timeout_time=600) - run_command.SetAbortOnError(False) - logger.SilentLog(output) - filter_re = re.compile(self._options.filter_re) if self._options.filter_re else None - - self._DoInstall(output, test_requires_permissions, filter_re=filter_re) - - def _DoInstall(self, make_output, test_requires_permissions, filter_re=None): - """Install artifacts from build onto device. - - Looks for 'install:' text from make output to find artifacts to install. - - Files with the .apk extension get 'adb install'ed, all other files - get 'adb push'ed onto the device. - - Args: - make_output: stdout from make command - """ - for line in make_output.split("\n"): - m = self._RE_MAKE_INSTALL.match(line) - if m: - # strip the 'INSTALL: ' from the left hand side - # the remaining string is a space-separated list of build-generated files - install_paths = m.group(2) - for install_path in re.split(r'\s+', install_paths): - if filter_re and not filter_re.match(install_path): - continue - if install_path.endswith(".apk"): - abs_install_path = os.path.join(self._root_path, install_path) - extra_flags = "" - if test_requires_permissions and not self._options.skip_permissions: - extra_flags = "-g" - if self._options.user: - extra_flags += " --user " + self._options.user - logger.Log("adb install -r %s %s" % (extra_flags, abs_install_path)) - logger.Log(self._adb.Install(abs_install_path, extra_flags)) - 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) - remote_dir = os.path.dirname(remote_path) - logger.Log("adb shell mkdir -p %s" % remote_dir) - self._adb.SendShellCommand("mkdir -p %s" % remote_dir) - 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, test_requires_permissions): - """If necessary, run a full 'make' command for the tests that need it.""" - extra_args_set = Set() - - for test in tests: - if test.IsFullMake() and test.IsGrantedPermissions() == test_requires_permissions: - if test.GetExtraBuildArgs(): - # extra args contains the args to pass to 'make' - extra_args_set.add(test.GetExtraBuildArgs()) - else: - logger.Log("Warning: test %s needs a full build but does not specify" - " extra_build_args" % test.GetName()) - - # check if there is actually any tests that required a full build - if extra_args_set: - cmd = ('make -j%s %s' % (self._options.make_jobs, - ' '.join(list(extra_args_set)))) - logger.Log(cmd) - if not self._options.preview: - old_dir = os.getcwd() - os.chdir(self._root_path) - output = run_command.RunCommand(cmd, return_output=True) - logger.SilentLog(output) - os.chdir(old_dir) - self._DoInstall(output, test_requires_permissions) - - def _AddBuildTarget(self, test_suite, target_tree, extra_args_set): - if not test_suite.IsFullMake(): - build_dir = test_suite.GetBuildPath() - if self._AddBuildTargetPath(build_dir, target_tree): - extra_args_set.append(test_suite.GetExtraBuildArgs()) - for path in test_suite.GetBuildDependencies(self._options): - self._AddBuildTargetPath(path, target_tree) - - def _AddBuildTargetPath(self, build_dir, target_tree): - if build_dir is not None: - target_tree.AddPath(build_dir) - return True - return False - - def _GetTestsToRun(self): - """Get a list of TestSuite objects to run, based on command line args.""" - if self._tests_to_run: - return self._tests_to_run - - self._tests_to_run = [] - if self._options.all_tests: - self._tests_to_run = self._known_tests.GetTests() - elif self._options.continuous_tests: - self._tests_to_run = self._known_tests.GetContinuousTests() - elif self._options.suite: - self._tests_to_run = \ - self._known_tests.GetTestsInSuite(self._options.suite) - elif self._options.test_path: - walker = test_walker.TestWalker() - self._tests_to_run = walker.FindTests(self._options.test_path) - - for name in self._test_args: - test = self._known_tests.GetTest(name) - if test is None: - logger.Log("Error: Could not find test %s" % name) - self._DumpTests() - raise errors.AbortError - self._tests_to_run.append(test) - return self._tests_to_run - - def _TurnOffVerifier(self, test_list): - """Turn off the dalvik verifier if needed by given tests. - - 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 frameworks/base tests. If so, turn off verifier - # to allow framework tests to access private/protected/package-private framework api - framework_test = False - for test in test_list: - if os.path.commonprefix([test.GetBuildPath(), "frameworks/base"]): - framework_test = True - if framework_test: - # check if verifier is off already - to avoid the reboot if not - # necessary - output = self._adb.SendShellCommand("cat /data/local.prop") - if not self._DALVIK_VERIFIER_OFF_PROP in output: - - # Read the existing dalvik verifier flags. - old_prop_value = self._adb.SendShellCommand("getprop %s" \ - %(self._DALVIK_VERIFIER_PROP)) - old_prop_value = old_prop_value.strip() if old_prop_value else "" - - # Append our verifier flags to existing flags - new_prop_value = "%s %s" %(self._DALVIK_VERIFIER_OFF_VALUE, old_prop_value) - - # Update property now, as /data/local.prop is not read until reboot - logger.Log("adb shell setprop %s '%s'" \ - %(self._DALVIK_VERIFIER_PROP, new_prop_value)) - if not self._options.preview: - self._adb.SendShellCommand("setprop %s '%s'" \ - %(self._DALVIK_VERIFIER_PROP, new_prop_value)) - - # Write prop to /data/local.prop - # Every time device is booted, it will pick up this value - new_prop_assignment = "%s = %s" %(self._DALVIK_VERIFIER_PROP, new_prop_value) - if self._options.preview: - logger.Log("adb shell \"echo %s >> /data/local.prop\"" - % new_prop_assignment) - logger.Log("adb shell chmod 644 /data/local.prop") - else: - logger.Log("Turning off dalvik verifier and rebooting") - self._adb.SendShellCommand("\"echo %s >> /data/local.prop\"" - % new_prop_assignment) - - # Reset runtime so that dalvik picks up new verifier flags from prop - self._ChmodRuntimeReset() - elif not self._options.preview: - # check the permissions on the file - permout = self._adb.SendShellCommand("ls -l /data/local.prop") - if not "-rw-r--r--" in permout: - logger.Log("Fixing permissions on /data/local.prop and rebooting") - self._ChmodRuntimeReset() - - def _ChmodRuntimeReset(self): - """Perform a chmod of /data/local.prop and reset the runtime. - """ - logger.Log("adb shell chmod 644 /data/local.prop ## u+w,a+r") - if not self._options.preview: - self._adb.SendShellCommand("chmod 644 /data/local.prop") - - self._adb.RuntimeReset(preview_only=self._options.preview) - - if not self._options.preview: - self._adb.EnableAdbRoot() - - - def RunTests(self): - """Main entry method - executes the tests according to command line args.""" - try: - run_command.SetAbortOnError() - self._ProcessOptions() - if self._options.only_list_tests: - self._DumpTests() - return - - if not self._options.skip_build: - self._DoBuild() - - if self._options.build_install_only: - logger.Log("Skipping test execution (due to --build-install-only flag)") - return - - for test_suite in self._GetTestsToRun(): - try: - test_suite.Run(self._options, self._adb) - except errors.WaitForResponseTimedOutError: - logger.Log("Timed out waiting for response") - - except KeyboardInterrupt: - logger.Log("Exiting...") - except errors.AbortError, error: - logger.Log(error.msg) - logger.SilentLog("Exiting due to AbortError...") - except errors.WaitForResponseTimedOutError: - logger.Log("Timed out waiting for response") - - -def RunTests(): - runner = TestRunner() - runner.RunTests() - -if __name__ == "__main__": - RunTests() diff --git a/testrunner/test_defs.xml b/testrunner/test_defs.xml deleted file mode 100644 index 27dad2d89..000000000 --- a/testrunner/test_defs.xml +++ /dev/null @@ -1,484 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/testrunner/test_defs.xsd b/testrunner/test_defs.xsd deleted file mode 100644 index 678194156..000000000 --- a/testrunner/test_defs.xsd +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/testrunner/test_defs/__init__.py b/testrunner/test_defs/__init__.py deleted file mode 100644 index f397d2a74..000000000 --- a/testrunner/test_defs/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['test_defs', 'test_walker'] diff --git a/testrunner/test_defs/gtest.py b/testrunner/test_defs/gtest.py deleted file mode 100644 index 90d8e52ef..000000000 --- a/testrunner/test_defs/gtest.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/python -# -# -# Copyright 2011, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""TestSuite for running C/C++ Android tests using gtest framework.""" - -# python imports -import os -import re - -# local imports -import logger -import run_command -import test_suite - - -class GTestSuite(test_suite.AbstractTestSuite): - """A test suite for running gtest on device.""" - - def __init__(self): - test_suite.AbstractTestSuite.__init__(self) - self._target_exec_path = None - - def GetTargetExecPath(self): - """Get the target path to gtest executable.""" - return self._target_exec_path - - def SetTargetExecPath(self, path): - self._target_exec_path = path - return self - - def Run(self, options, adb): - """Run the provided gtest test suite. - - Args: - options: command line options - adb: adb interface - """ - - test_class = "*" - test_method = "*" - if options.test_class is not None: - test_class = options.test_class.lstrip() - if options.test_method is not None: - test_method = options.test_method.lstrip() - filter_arg = "" - if test_class != "*" or test_method != "*": - filter_arg = "--gtest_filter=%s.%s" % (test_class, test_method) - - shell_cmd = adb.PreviewShellCommand( - " ".join((self.GetTargetExecPath(), filter_arg))) - logger.Log(shell_cmd) - if not options.preview: - # gtest will log to test results to stdout, so no need to do any - # extra processing - run_command.RunCommand(shell_cmd, return_output=False) - - -class GTestFactory(test_suite.AbstractTestFactory): - - def __init__(self, test_root_path, build_path): - test_suite.AbstractTestFactory.__init__(self, test_root_path, - build_path) - - def CreateTests(self, sub_tests_path=None): - """Create tests found in sub_tests_path. - - Looks for test files matching a pattern, and assumes each one is a separate - binary on target. - - Test files must match one of the following pattern: - - test_*.[c|cc|cpp] - - *_test.[c|cc|cpp] - - *_unittest.[c|cc|cpp] - - *Tests.[cc|cpp] - - """ - if not sub_tests_path: - sub_tests_path = self.GetTestRootPath() - test_file_list = [] - if os.path.isfile(sub_tests_path): - self._EvaluateFile(test_file_list, os.path.basename(sub_tests_path)) - else: - os.path.walk(sub_tests_path, self._CollectTestSources, test_file_list) - # TODO: obtain this from makefile instead of hardcoding - target_root_path = os.path.join('/data', 'nativetest') - test_suites = [] - for test_file in test_file_list: - logger.SilentLog('Creating gtest suite for file %s' % test_file) - suite = GTestSuite() - suite.SetBuildPath(self.GetBuildPath()) - # expect tests in /data/nativetest/test_file/test_file - suite.SetTargetExecPath(os.path.join(target_root_path, test_file, test_file)) - test_suites.append(suite) - return test_suites - - def _CollectTestSources(self, test_list, dirname, files): - """For each directory, find tests source file and add them to the list. - - Test files must match one of the following pattern: - - test_*.[cc|cpp] - - *_test.[cc|cpp] - - *_unittest.[cc|cpp] - - *Tests.[cc|cpp] - - This method is a callback for os.path.walk. - - Args: - test_list: Where new tests should be inserted. - dirname: Current directory. - files: List of files in the current directory. - """ - for f in files: - self._EvaluateFile(test_list, f) - - def _EvaluateFile(self, test_list, file): - (name, ext) = os.path.splitext(file) - if ext == ".cc" or ext == ".cpp" or ext == ".c": - if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_|Tests$", name): - logger.SilentLog("Found native test file %s" % file) - test_list.append(name) diff --git a/testrunner/test_defs/host_test.py b/testrunner/test_defs/host_test.py deleted file mode 100644 index ca65c2a94..000000000 --- a/testrunner/test_defs/host_test.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Parser for test definition xml files.""" - -# python imports -import os - -import errors -import logger -import run_command -import test_suite - - -class HostTestSuite(test_suite.AbstractTestSuite): - """A test suite for running hosttestlib java tests.""" - - _JUNIT_JAR_NAME = "junit.jar" - _HOSTTESTLIB_NAME = "hosttestlib.jar" - _DDMLIB_NAME = "ddmlib-prebuilt.jar" - _TRADEFED_NAME = "tradefed-prebuilt.jar" - _lib_names = [_JUNIT_JAR_NAME, _HOSTTESTLIB_NAME, _DDMLIB_NAME, _TRADEFED_NAME] - - _JUNIT_BUILD_PATH = os.path.join("external", "junit") - _HOSTTESTLIB_BUILD_PATH = os.path.join("development", "tools", "hosttestlib") - _LIB_BUILD_PATHS = [_JUNIT_BUILD_PATH, _HOSTTESTLIB_BUILD_PATH ] - - # main class for running host tests - # TODO: should other runners be supported, and make runner an attribute of - # the test suite? - _TEST_RUNNER = "com.android.hosttest.DeviceTestRunner" - - def __init__(self): - test_suite.AbstractTestSuite.__init__(self) - self._jar_name = None - self._class_name = None - - def GetBuildDependencies(self, options): - """Override parent to tag on building host libs.""" - return self._LIB_BUILD_PATHS - - def GetClassName(self): - return self._class_name - - def SetClassName(self, class_name): - self._class_name = class_name - return self - - def GetJarName(self): - """Returns the name of the host jar that contains the tests.""" - return self._jar_name - - def SetJarName(self, jar_name): - self._jar_name = jar_name - return self - - def Run(self, options, adb_interface): - """Runs the host test. - - Results will be displayed on stdout. Assumes 'java' is on system path. - - Args: - options: command line options for running host tests. Expected member - fields: - host_lib_path: path to directory that contains host library files - test_data_path: path to directory that contains test data files - preview: if true, do not execute, display commands only - adb_interface: reference to device under test - - Raises: - errors.AbortError: if fatal error occurs - """ - # get the serial number of the device under test, so it can be passed to - # hosttestlib. - serial_number = adb_interface.GetSerialNumber() - self._lib_names.append(self.GetJarName()) - # gather all the host jars that are needed to run tests - full_lib_paths = [] - for lib in self._lib_names: - path = os.path.join(options.host_lib_path, lib) - # make sure jar file exists on host - if not os.path.exists(path): - raise errors.AbortError(msg="Could not find jar %s" % path) - full_lib_paths.append(path) - - # java -cp -s - # -p - cmd = "java -cp %s %s %s -s %s -p %s" % (":".join(full_lib_paths), - self._TEST_RUNNER, - self.GetClassName(), serial_number, - options.test_data_path) - logger.Log(cmd) - if not options.preview: - run_command.RunOnce(cmd, return_output=False) diff --git a/testrunner/test_defs/instrumentation_test.py b/testrunner/test_defs/instrumentation_test.py deleted file mode 100644 index 5651d2ead..000000000 --- a/testrunner/test_defs/instrumentation_test.py +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""TestSuite definition for Android instrumentation tests.""" - -import os -import re - -# local imports -import android_manifest -from coverage import coverage -import errors -import logger -import test_suite - - -class InstrumentationTestSuite(test_suite.AbstractTestSuite): - """Represents a java instrumentation test suite definition run on device.""" - - DEFAULT_RUNNER = "android.test.InstrumentationTestRunner" - - def __init__(self): - test_suite.AbstractTestSuite.__init__(self) - self._package_name = None - self._runner_name = self.DEFAULT_RUNNER - self._class_name = None - self._target_name = None - self._java_package = None - - def GetPackageName(self): - return self._package_name - - def SetPackageName(self, package_name): - self._package_name = package_name - return self - - def GetRunnerName(self): - return self._runner_name - - def SetRunnerName(self, runner_name): - self._runner_name = runner_name - return self - - def GetClassName(self): - return self._class_name - - def SetClassName(self, class_name): - self._class_name = class_name - return self - - def GetJavaPackageFilter(self): - return self._java_package - - def SetJavaPackageFilter(self, java_package_name): - """Configure the suite to only run tests in given java package.""" - self._java_package = java_package_name - return self - - def GetTargetName(self): - """Retrieve module that this test is targeting. - - Used for generating code coverage metrics. - Returns: - the module target name - """ - return self._target_name - - def SetTargetName(self, target_name): - self._target_name = target_name - return self - - def GetBuildDependencies(self, options): - if options.coverage_target_path: - return [options.coverage_target_path] - return [] - - def Run(self, options, adb): - """Run the provided test suite. - - Builds up an adb instrument command using provided input arguments. - - Args: - options: command line options to provide to test run - adb: adb_interface to device under test - - Raises: - errors.AbortError: if fatal error occurs - """ - - test_class = self.GetClassName() - if options.test_class is not None: - test_class = options.test_class.lstrip() - if test_class.startswith("."): - test_class = self.GetPackageName() + test_class - if options.test_method is not None: - test_class = "%s#%s" % (test_class, options.test_method) - - test_package = self.GetJavaPackageFilter() - if options.test_package: - test_package = options.test_package - - if test_class and test_package: - logger.Log('Error: both class and java package options are specified') - - instrumentation_args = {} - if test_class is not None: - instrumentation_args["class"] = test_class - if test_package: - instrumentation_args["package"] = test_package - if options.test_size: - instrumentation_args["size"] = options.test_size - if options.wait_for_debugger: - instrumentation_args["debug"] = "true" - if options.suite_assign_mode: - instrumentation_args["suiteAssignment"] = "true" - if options.coverage: - instrumentation_args["coverage"] = "true" - if options.test_annotation: - instrumentation_args["annotation"] = options.test_annotation - if options.test_not_annotation: - instrumentation_args["notAnnotation"] = options.test_not_annotation - if options.preview: - adb_cmd = adb.PreviewInstrumentationCommand( - package_name=self.GetPackageName(), - runner_name=self.GetRunnerName(), - raw_mode=options.raw_mode, - instrumentation_args=instrumentation_args) - logger.Log(adb_cmd) - elif options.coverage: - coverage_gen = coverage.CoverageGenerator(adb) - if options.coverage_target_path: - coverage_target = coverage_gen.GetCoverageTargetForPath(options.coverage_target_path) - elif self.GetTargetName(): - coverage_target = coverage_gen.GetCoverageTarget(self.GetTargetName()) - self._CheckInstrumentationInstalled(adb) - # 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) = adb.StartInstrumentationForPackage( - package_name=self.GetPackageName(), - runner_name=self.GetRunnerName(), - timeout_time=60*60, - instrumentation_args=instrumentation_args, - user=options.user, - no_hidden_api_checks=options.no_hidden_api_checks) - 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 = coverage_gen.ExtractReport( - self.GetName(), coverage_target, device_coverage_path, - test_qualifier=options.test_size) - if coverage_file is not None: - logger.Log("Coverage report generated at %s" % coverage_file) - - else: - self._CheckInstrumentationInstalled(adb) - adb.StartInstrumentationNoResults( - package_name=self.GetPackageName(), - runner_name=self.GetRunnerName(), - raw_mode=options.raw_mode, - instrumentation_args=instrumentation_args, - user=options.user, - no_hidden_api_checks=options.no_hidden_api_checks) - - def _CheckInstrumentationInstalled(self, adb): - if not adb.IsInstrumentationInstalled(self.GetPackageName(), - self.GetRunnerName()): - msg=("Could not find instrumentation %s/%s on device. Try forcing a " - "rebuild by updating a source file, and re-executing runtest." % - (self.GetPackageName(), self.GetRunnerName())) - raise errors.AbortError(msg=msg) - - def _PrintTestResults(self, test_results): - """Prints a summary of test result data to stdout. - - 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 HasInstrumentationTest(path): - """Determine if given path defines an instrumentation test. - - Args: - path: file system path to instrumentation test. - """ - manifest_parser = android_manifest.CreateAndroidManifest(path) - if manifest_parser: - return manifest_parser.GetInstrumentationNames() - return False - -class InstrumentationTestFactory(test_suite.AbstractTestFactory): - """A factory for creating InstrumentationTestSuites""" - - def __init__(self, test_root_path, build_path): - test_suite.AbstractTestFactory.__init__(self, test_root_path, - build_path) - - def CreateTests(self, sub_tests_path=None): - """Create tests found in test_path. - - Will create a single InstrumentationTestSuite based on info found in - AndroidManifest.xml found at build_path. Will set additional filters if - test_path refers to a java package or java class. - """ - tests = [] - class_name_arg = None - java_package_name = None - if sub_tests_path: - # if path is java file, populate class name - if self._IsJavaFile(sub_tests_path): - class_name_arg = self._GetClassNameFromFile(sub_tests_path) - logger.SilentLog('Using java test class %s' % class_name_arg) - elif self._IsJavaPackage(sub_tests_path): - java_package_name = self._GetPackageNameFromDir(sub_tests_path) - logger.SilentLog('Using java package %s' % java_package_name) - try: - manifest_parser = android_manifest.AndroidManifest(app_path= - self.GetTestsRootPath()) - instrs = manifest_parser.GetInstrumentationNames() - if not instrs: - logger.Log('Could not find instrumentation declarations in %s at %s' % - (android_manifest.AndroidManifest.FILENAME, - self.GetBuildPath())) - return tests - elif len(instrs) > 1: - logger.Log("Found multiple instrumentation declarations in %s/%s. " - "Only using first declared." % - (self.GetBuildPath(), - android_manifest.AndroidManifest.FILENAME)) - instr_name = manifest_parser.GetInstrumentationNames()[0] - # escape inner class names - instr_name = instr_name.replace('$', '\$') - pkg_name = manifest_parser.GetPackageName() - if instr_name.find(".") < 0: - instr_name = "." + instr_name - logger.SilentLog('Found instrumentation %s/%s' % (pkg_name, instr_name)) - suite = InstrumentationTestSuite() - suite.SetPackageName(pkg_name) - suite.SetBuildPath(self.GetBuildPath()) - suite.SetRunnerName(instr_name) - suite.SetName(pkg_name) - suite.SetClassName(class_name_arg) - suite.SetJavaPackageFilter(java_package_name) - tests.append(suite) - return tests - - except: - logger.Log('Could not find or parse %s at %s' % - (android_manifest.AndroidManifest.FILENAME, - self.GetBuildPath())) - return tests - - def _IsJavaFile(self, path): - """Returns true if given file system path is a java file.""" - return os.path.isfile(path) and self._IsJavaFileName(path) - - def _IsJavaFileName(self, filename): - """Returns true if given file name is a java file name.""" - return os.path.splitext(filename)[1] == '.java' - - def _IsJavaPackage(self, path): - """Returns true if given file path is a java package. - - Currently assumes if any java file exists in this directory, than it - represents a java package. - - Args: - path: file system path of directory to check - - Returns: - True if path is a java package - """ - if not os.path.isdir(path): - return False - for file_name in os.listdir(path): - if self._IsJavaFileName(file_name): - return True - return False - - def _GetClassNameFromFile(self, java_file_path): - """Gets the fully qualified java class name from path. - - Args: - java_file_path: file system path of java file - - Returns: - fully qualified java class name or None. - """ - package_name = self._GetPackageNameFromFile(java_file_path) - if package_name: - filename = os.path.basename(java_file_path) - class_name = os.path.splitext(filename)[0] - return '%s.%s' % (package_name, class_name) - return None - - def _GetPackageNameFromDir(self, path): - """Gets the java package name associated with given directory path. - - Caveat: currently just parses defined java package name from first java - file found in directory. - - Args: - path: file system path of directory - - Returns: - the java package name or None - """ - for filename in os.listdir(path): - if self._IsJavaFileName(filename): - return self._GetPackageNameFromFile(os.path.join(path, filename)) - - def _GetPackageNameFromFile(self, java_file_path): - """Gets the java package name associated with given java file path. - - Args: - java_file_path: file system path of java file - - Returns: - the java package name or None - """ - logger.SilentLog('Looking for java package name in %s' % java_file_path) - re_package = re.compile(r'package\s+(.*);') - file_handle = open(java_file_path, 'r') - for line in file_handle: - match = re_package.match(line) - if match: - return match.group(1) - return None diff --git a/testrunner/test_defs/native_test.py b/testrunner/test_defs/native_test.py deleted file mode 100644 index f1ae82c3c..000000000 --- a/testrunner/test_defs/native_test.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""TestSuite for running native Android tests.""" - -# python imports -import os -import re - -# local imports -import android_build -import logger -import run_command -import test_suite - - -class NativeTestSuite(test_suite.AbstractTestSuite): - """A test suite for running native aka C/C++ tests on device.""" - - def Run(self, options, adb): - """Run the provided *native* test suite. - - The test_suite must contain a build path where the native test - files are. Subdirectories are automatically scanned as well. - - Each test's name must have a .cc or .cpp extension and match one - of the following patterns: - - test_* - - *_test.[cc|cpp] - - *_unittest.[cc|cpp] - A successful test must return 0. Any other value will be considered - as an error. - - Args: - options: command line options - adb: adb interface - """ - # find all test files, convert unicode names to ascii, take the basename - # and drop the .cc/.cpp extension. - source_list = [] - build_path = os.path.join(android_build.GetTop(), self.GetBuildPath()) - os.path.walk(build_path, self._CollectTestSources, source_list) - logger.SilentLog("Tests source %s" % source_list) - - # Host tests are under out/host/-/bin. - host_list = self._FilterOutMissing(android_build.GetHostBin(), source_list) - logger.SilentLog("Host tests %s" % host_list) - - # Target tests are under $ANDROID_PRODUCT_OUT/data/nativetest. - target_list = self._FilterOutMissing(android_build.GetTargetNativeTestPath(), - source_list) - logger.SilentLog("Target tests %s" % target_list) - - # Run on the host - logger.Log("\nRunning on host") - for f in host_list: - if run_command.RunHostCommand(f) != 0: - logger.Log("%s... failed" % f) - else: - if run_command.HasValgrind(): - if run_command.RunHostCommand(f, valgrind=True) == 0: - logger.Log("%s... ok\t\t[valgrind: ok]" % f) - else: - logger.Log("%s... ok\t\t[valgrind: failed]" % f) - else: - logger.Log("%s... ok\t\t[valgrind: missing]" % f) - - # Run on the device - logger.Log("\nRunning on target") - for f in target_list: - full_path = os.path.join(os.sep, "data", "nativetest", f) - - # Single quotes are needed to prevent the shell splitting it. - output = adb.SendShellCommand("'%s 2>&1;echo -n exit code:$?'" % - "(cd /sdcard;%s)" % full_path, - int(options.timeout)) - success = output.endswith("exit code:0") - logger.Log("%s... %s" % (f, success and "ok" or "failed")) - # Print the captured output when the test failed. - if not success or options.verbose: - pos = output.rfind("exit code") - output = output[0:pos] - logger.Log(output) - - # Cleanup - adb.SendShellCommand("rm %s" % full_path) - - def _CollectTestSources(self, test_list, dirname, files): - """For each directory, find tests source file and add them to the list. - - Test files must match one of the following pattern: - - test_*.[cc|cpp] - - *_test.[cc|cpp] - - *_unittest.[cc|cpp] - - This method is a callback for os.path.walk. - - Args: - test_list: Where new tests should be inserted. - dirname: Current directory. - files: List of files in the current directory. - """ - for f in files: - (name, ext) = os.path.splitext(f) - if ext == ".cc" or ext == ".cpp" or ext == ".c": - if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name): - logger.SilentLog("Found %s" % f) - test_list.append(str(os.path.join(dirname, f))) - - def _FilterOutMissing(self, path, sources): - """Filter out from the sources list missing tests. - - Sometimes some test source are not built for the target, i.e there - is no binary corresponding to the source file. We need to filter - these out. - - Args: - path: Where the binaries should be. - sources: List of tests source path. - Returns: - A list of relative paths to the test binaries built from the sources. - """ - binaries = [] - for f in sources: - binary = os.path.basename(f) - binary = os.path.splitext(binary)[0] - found = self._FindFileRecursively(path, binary) - if found: - binary = os.path.relpath(os.path.abspath(found), - os.path.abspath(path)) - binaries.append(binary) - return binaries - - def _FindFileRecursively(self, path, match): - """Finds the first executable binary in a given path that matches the name. - - Args: - path: Where to search for binaries. Can be nested directories. - binary: Which binary to search for. - Returns: - first matched file in the path or None if none is found. - """ - for root, dirs, files in os.walk(path): - for f in files: - if f == match: - return os.path.join(root, f) - for d in dirs: - found = self._FindFileRecursively(os.path.join(root, d), match) - if found: - return found - return None - - def _RunHostCommand(self, binary, valgrind=False): - """Run a command on the host (opt using valgrind). - - Runs the host binary and returns the exit code. - If successfull, the output (stdout and stderr) are discarded, - but printed in case of error. - The command can be run under valgrind in which case all the - output are always discarded. - - Args: - binary: basename of the file to be run. It is expected to be under - $ANDROID_HOST_OUT/bin. - valgrind: If True the command will be run under valgrind. - - Returns: - The command exit code (int) - """ - full_path = os.path.join(android_build.GetHostBin(), binary) - return run_command.RunHostCommand(full_path, valgrind=valgrind) diff --git a/testrunner/test_defs/test_defs.py b/testrunner/test_defs/test_defs.py deleted file mode 100644 index 504b7b9b2..000000000 --- a/testrunner/test_defs/test_defs.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2008, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Parser for test definition xml files.""" - -# Python imports -import xml.dom.minidom -import xml.parsers - -# local imports -import errors -import logger -import xml_suite_helper - - -class TestDefinitions(object): - """Accessor for a test definitions xml file data. - - See test_defs.xsd for expected format. - """ - - def __init__(self): - # dictionary of test name to tests - self._testname_map = {} - - def __iter__(self): - ordered_list = [] - for k in sorted(self._testname_map): - ordered_list.append(self._testname_map[k]) - return iter(ordered_list) - - def Parse(self, file_path): - """Parse the test suite data from from given file path. - - Args: - file_path: absolute file path to parse - Raises: - ParseError if file_path cannot be parsed - """ - try: - doc = xml.dom.minidom.parse(file_path) - self._ParseDoc(doc) - except IOError: - logger.Log("test file %s does not exist" % file_path) - raise errors.ParseError - except xml.parsers.expat.ExpatError: - logger.Log("Error Parsing xml file: %s " % file_path) - raise errors.ParseError - except errors.ParseError, e: - logger.Log("Error Parsing xml file: %s Reason: %s" % (file_path, e.msg)) - raise e - - def ParseString(self, xml_string): - """Alternate parse method that accepts a string of the xml data.""" - doc = xml.dom.minidom.parseString(xml_string) - # TODO: catch exceptions and raise ParseError - return self._ParseDoc(doc) - - def _ParseDoc(self, doc): - root_element = self._GetRootElement(doc) - suite_parser = xml_suite_helper.XmlSuiteParser() - for element in root_element.childNodes: - if element.nodeType != xml.dom.Node.ELEMENT_NODE: - continue - test_suite = suite_parser.Parse(element) - if test_suite: - self._AddTest(test_suite) - - def _GetRootElement(self, doc): - root_elements = doc.getElementsByTagName("test-definitions") - if len(root_elements) != 1: - error_msg = "expected 1 and only one test-definitions tag" - raise errors.ParseError(msg=error_msg) - return root_elements[0] - - def _AddTest(self, test): - """Adds a test to this TestManifest. - - If a test already exists with the same name, it overrides it. - - Args: - test: TestSuite to add - """ - if self.GetTest(test.GetName()) is not None: - logger.SilentLog("Overriding test definition %s" % test.GetName()) - self._testname_map[test.GetName()] = test - - def GetTests(self): - return self._testname_map.values() - - def GetContinuousTests(self): - con_tests = [] - for test in self.GetTests(): - if test.IsContinuous(): - con_tests.append(test) - return con_tests - - def GetTestsInSuite(self, suite): - """Return list of tests in given suite.""" - return [t for t in self.GetTests() if t.GetSuite() == suite] - - def GetTest(self, name): - return self._testname_map.get(name, None) - - -def Parse(file_path): - """Parses out a TestDefinitions from given path to xml file. - - Args: - file_path: string absolute file path - Returns: - a TestDefinitions object containing data parsed from file_path - Raises: - ParseError if xml format is not recognized - """ - tests_result = TestDefinitions() - tests_result.Parse(file_path) - return tests_result diff --git a/testrunner/test_defs/test_suite.py b/testrunner/test_defs/test_suite.py deleted file mode 100644 index 5bd9a1972..000000000 --- a/testrunner/test_defs/test_suite.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Abstract Android test suite.""" - - -class AbstractTestSuite(object): - """Represents a generic test suite definition. - - TODO: rename this as AbstractTestDef. - """ - - def __init__(self): - self._name = None - self._build_path = None - self._build_dependencies = [] - self._is_continuous = False - self._suite = None - self._description = '' - self._extra_build_args = '' - self._is_full_make = False - self._is_granted_permissions = True - - def GetName(self): - return self._name - - def SetName(self, name): - self._name = name - return self - - def GetBuildPath(self): - """Returns the build path of this test, relative to source tree root.""" - return self._build_path - - def SetBuildPath(self, build_path): - self._build_path = build_path - return self - - def GetBuildDependencies(self, options): - """Returns a list of dependent build paths.""" - return self._build_dependencies - - def SetBuildDependencies(self, build_dependencies): - self._build_dependencies = build_dependencies - return self - - def IsContinuous(self): - """Returns true if test is part of the continuous test.""" - return self._is_continuous - - def SetContinuous(self, continuous): - self._is_continuous = continuous - return self._is_continuous - - def IsGrantedPermissions(self): - """Return true if the test should be granted runtime permissions on install.""" - return self._is_granted_permissions - - def SetIsGrantedPermissions(self, is_granted_permissions): - self._is_granted_permissions = is_granted_permissions - return self._is_granted_permissions - - def GetSuite(self): - """Returns the name of test' suite, or None.""" - return self._suite - - def SetSuite(self, suite): - self._suite = suite - return self - - def GetDescription(self): - """Returns a description if available, an empty string otherwise.""" - return self._description - - def SetDescription(self, desc): - self._description = desc - return self - - def GetExtraBuildArgs(self): - """Returns the extra build args if available, an empty string otherwise.""" - return self._extra_build_args - - def SetExtraBuildArgs(self, build_args): - self._extra_build_args = build_args - return self - - def IsFullMake(self): - return self._is_full_make - - def SetIsFullMake(self, full_make): - self._is_full_make = full_make - return self - - def Run(self, options, adb): - """Runs the test. - - Subclasses must implement this. - Args: - options: global command line options - adb: asdb_interface to device under test - """ - raise NotImplementedError - -class AbstractTestFactory(object): - """generic test suite factory.""" - - def __init__(self, test_root_path, build_path): - """Creates a test suite factory. - - Args: - test_root_path: the filesystem path to the tests build directory - upstream_build_path: filesystem path for the directory - to build when running tests, relative to the source tree root. - """ - self._test_root_path = test_root_path - self._build_path = build_path - - def GetBuildPath(self): - return self._build_path - - def GetTestsRootPath(self): - return self._test_root_path - - def CreateTests(self, sub_tests_path=None): - """Creates the tests at given test_path. - - Subclasses must implement this. - - Args: - sub_tests_path: the child path of test_root_path containing the tests to - run. If unspecified will be set to test_root_path. - - Returns: - an array of AbstractTestSuite, or empty AbstractTestSuite if no tests - were defined - """ - raise NotImplementedError diff --git a/testrunner/test_defs/test_walker.py b/testrunner/test_defs/test_walker.py deleted file mode 100755 index fa6ea1baa..000000000 --- a/testrunner/test_defs/test_walker.py +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utility to find instrumentation test definitions from file system.""" - -# python imports -import os - -# local imports -import android_build -import android_mk -import gtest -import instrumentation_test -import logger - - -class TestWalker(object): - """Finds Android tests from filesystem.""" - - def FindTests(self, path): - """Gets list of Android tests found at given path. - - Tests are created from info found in Android.mk and AndroidManifest.xml - files relative to the given path. - - Currently supported tests are: - - Android application tests run via instrumentation - - native C/C++ tests using GTest framework. (note Android.mk must follow - expected GTest template) - - FindTests will first scan sub-folders of path for tests. If none are found, - it will scan the file system upwards until a valid test Android.mk is found - or the Android build root is reached. - - Some sample values for path: - - a parent directory containing many tests: - ie development/samples will return tests for instrumentation's in ApiDemos, - ApiDemos/tests, Notepad/tests etc - - a java test class file - ie ApiDemos/tests/src/../ApiDemosTest.java will return a test for - the instrumentation in ApiDemos/tests, with the class name filter set to - ApiDemosTest - - a java package directory - ie ApiDemos/tests/src/com/example/android/apis will return a test for - the instrumentation in ApiDemos/tests, with the java package filter set - to com.example.android.apis. - - TODO: add GTest examples - - Args: - path: file system path to search - - Returns: - list of test suites that support operations defined by - test_suite.AbstractTestSuite - """ - if not os.path.exists(path): - logger.Log('%s does not exist' % path) - return [] - realpath = os.path.realpath(path) - # ensure path is in ANDROID_BUILD_ROOT - self._build_top = os.path.realpath(android_build.GetTop()) - if not self._IsPathInBuildTree(realpath): - logger.Log('%s is not a sub-directory of build root %s' % - (path, self._build_top)) - return [] - - # first, assume path is a parent directory, which specifies to run all - # tests within this directory - tests = self._FindSubTests(realpath, []) - if not tests: - logger.SilentLog('No tests found within %s, searching upwards' % path) - tests = self._FindUpstreamTests(realpath) - return tests - - def _IsPathInBuildTree(self, path): - """Return true if given path is within current Android build tree. - - Args: - path: absolute file system path - - Returns: - True if path is within Android build tree - """ - return os.path.commonprefix([self._build_top, path]) == self._build_top - - def _MakePathRelativeToBuild(self, path): - """Convert given path to one relative to build tree root. - - Args: - path: absolute file system path to convert. - - Returns: - The converted path relative to build tree root. - - Raises: - ValueError: if path is not within build tree - """ - if not self._IsPathInBuildTree(path): - raise ValueError - build_path_len = len(self._build_top) + 1 - # return string with common build_path removed - return path[build_path_len:] - - def _FindSubTests(self, path, tests, upstream_build_path=None): - """Recursively finds all tests within given path. - - Args: - path: absolute file system path to check - tests: current list of found tests - upstream_build_path: the parent directory where Android.mk that builds - sub-folders was found - - Returns: - updated list of tests - """ - if not os.path.isdir(path): - return tests - android_mk_parser = android_mk.CreateAndroidMK(path) - if android_mk_parser: - build_rel_path = self._MakePathRelativeToBuild(path) - if not upstream_build_path: - # haven't found a parent makefile which builds this dir. Use current - # dir as build path - tests.extend(self._CreateSuites( - android_mk_parser, path, build_rel_path)) - else: - tests.extend(self._CreateSuites(android_mk_parser, path, - upstream_build_path)) - # TODO: remove this logic, and rely on caller to collapse build - # paths via make_tree - - # Try to build as much of original path as possible, so - # keep track of upper-most parent directory where Android.mk was found - # that has rule to build sub-directory makefiles. - # this is also necessary in case of overlapping tests - # ie if a test exists at 'foo' directory and 'foo/sub', attempting to - # build both 'foo' and 'foo/sub' will fail. - - if android_mk_parser.IncludesMakefilesUnder(): - # found rule to build sub-directories. The parent path can be used, - # or if not set, use current path - if not upstream_build_path: - upstream_build_path = self._MakePathRelativeToBuild(path) - else: - upstream_build_path = None - for filename in os.listdir(path): - self._FindSubTests(os.path.join(path, filename), tests, - upstream_build_path) - return tests - - def _FindUpstreamTests(self, path): - """Find tests defined upward from given path. - - Args: - path: the location to start searching. - - Returns: - list of test_suite.AbstractTestSuite found, may be empty - """ - factory = self._FindUpstreamTestFactory(path) - if factory: - return factory.CreateTests(sub_tests_path=path) - else: - return [] - - def _GetTestFactory(self, android_mk_parser, path, build_path): - """Get the test factory for given makefile. - - If given path is a valid tests build path, will return the TestFactory - for creating tests. - - Args: - android_mk_parser: the android mk to evaluate - path: the filesystem path of the makefile - build_path: filesystem path for the directory - to build when running tests, relative to source root. - - Returns: - the TestFactory or None if path is not a valid tests build path - """ - if android_mk_parser.HasGTest(): - return gtest.GTestFactory(path, build_path) - elif instrumentation_test.HasInstrumentationTest(path): - return instrumentation_test.InstrumentationTestFactory(path, - build_path) - else: - # somewhat unusual, but will continue searching - logger.SilentLog('Found makefile at %s, but did not detect any tests.' - % path) - - return None - - def _GetTestFactoryForPath(self, path): - """Get the test factory for given path. - - If given path is a valid tests build path, will return the TestFactory - for creating tests. - - Args: - path: the filesystem path to evaluate - - Returns: - the TestFactory or None if path is not a valid tests build path - """ - android_mk_parser = android_mk.CreateAndroidMK(path) - if android_mk_parser: - build_path = self._MakePathRelativeToBuild(path) - return self._GetTestFactory(android_mk_parser, path, build_path) - else: - return None - - def _FindUpstreamTestFactory(self, path): - """Recursively searches filesystem upwards for a test factory. - - Args: - path: file system path to search - - Returns: - the TestFactory found or None - """ - factory = self._GetTestFactoryForPath(path) - if factory: - return factory - dirpath = os.path.dirname(path) - if self._IsPathInBuildTree(path): - return self._FindUpstreamTestFactory(dirpath) - logger.Log('A tests Android.mk was not found') - return None - - def _CreateSuites(self, android_mk_parser, path, upstream_build_path): - """Creates TestSuites from a AndroidMK. - - Args: - android_mk_parser: the AndroidMK - path: absolute file system path of the makefile to evaluate - upstream_build_path: the build path to use for test. This can be - different than the 'path', in cases where an upstream makefile - is being used. - - Returns: - the list of tests created - """ - factory = self._GetTestFactory(android_mk_parser, path, - build_path=upstream_build_path) - if factory: - return factory.CreateTests(path) - else: - return [] diff --git a/testrunner/test_defs/xml_suite_helper.py b/testrunner/test_defs/xml_suite_helper.py deleted file mode 100644 index 6805fcd27..000000000 --- a/testrunner/test_defs/xml_suite_helper.py +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Utility to parse suite info from xml.""" - -# Python imports -import xml.dom.minidom -import xml.parsers - -# local imports -import errors -import logger -import host_test -import instrumentation_test -import native_test - - -class XmlSuiteParser(object): - """Parses XML attributes common to all TestSuite's.""" - - # common attributes - _NAME_ATTR = 'name' - _BUILD_ATTR = 'build_path' - _CONTINUOUS_ATTR = 'continuous' - _SUITE_ATTR = 'suite' - _DESCRIPTION_ATTR = 'description' - _EXTRA_BUILD_ARGS_ATTR = 'extra_build_args' - _FULL_MAKE_ATTR = 'full_make' - _GRANTED_PERMISSIONS_ATTR = 'granted_permissions' - - def Parse(self, element): - """Populates common suite attributes from given suite xml element. - - Args: - element: xml node to parse - Raises: - ParseError if a required attribute is missing. - Returns: - parsed test suite or None - """ - parser = None - if element.nodeName == InstrumentationParser.TAG_NAME: - parser = InstrumentationParser() - elif element.nodeName == NativeParser.TAG_NAME: - parser = NativeParser() - elif element.nodeName == HostParser.TAG_NAME: - parser = HostParser() - else: - logger.Log('Unrecognized tag %s found' % element.nodeName) - return None - test_suite = parser.Parse(element) - return test_suite - - def _ParseCommonAttributes(self, suite_element, test_suite): - test_suite.SetName(self._ParseAttribute(suite_element, self._NAME_ATTR, - True)) - test_suite.SetBuildPath(self._ParseAttribute(suite_element, - self._BUILD_ATTR, True)) - test_suite.SetContinuous(self._ParseAttribute(suite_element, - self._CONTINUOUS_ATTR, - False, default_value=False)) - test_suite.SetIsGrantedPermissions(self._ParseAttribute(suite_element, - self._GRANTED_PERMISSIONS_ATTR, - False, default_value=True)) - test_suite.SetSuite(self._ParseAttribute(suite_element, self._SUITE_ATTR, False, - default_value=None)) - test_suite.SetDescription(self._ParseAttribute(suite_element, - self._DESCRIPTION_ATTR, - False, - default_value='')) - test_suite.SetExtraBuildArgs(self._ParseAttribute( - suite_element, self._EXTRA_BUILD_ARGS_ATTR, False, default_value='')) - test_suite.SetIsFullMake(self._ParseAttribute( - suite_element, self._FULL_MAKE_ATTR, False, default_value=False)) - - - def _ParseAttribute(self, suite_element, attribute_name, mandatory, - default_value=None): - if suite_element.hasAttribute(attribute_name): - value = suite_element.getAttribute(attribute_name) - if default_value in (True, False): - value = value.lower() == "true" - elif mandatory: - error_msg = ('Could not find attribute %s in %s' % - (attribute_name, self.TAG_NAME)) - raise errors.ParseError(msg=error_msg) - else: - value = default_value - return value - - -class InstrumentationParser(XmlSuiteParser): - """Parses instrumentation suite attributes from xml.""" - - # for legacy reasons, the xml tag name for java (device) tests is 'test' - TAG_NAME = 'test' - - _PKG_ATTR = 'package' - _RUNNER_ATTR = 'runner' - _CLASS_ATTR = 'class' - _TARGET_ATTR = 'coverage_target' - - def Parse(self, suite_element): - """Creates suite and populate with data from xml element.""" - suite = instrumentation_test.InstrumentationTestSuite() - XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite) - suite.SetPackageName(self._ParseAttribute(suite_element, self._PKG_ATTR, - True)) - suite.SetRunnerName(self._ParseAttribute( - suite_element, self._RUNNER_ATTR, False, - instrumentation_test.InstrumentationTestSuite.DEFAULT_RUNNER)) - suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR, - False)) - suite.SetTargetName(self._ParseAttribute(suite_element, self._TARGET_ATTR, - False)) - return suite - - -class NativeParser(XmlSuiteParser): - """Parses native suite attributes from xml.""" - - TAG_NAME = 'test-native' - - def Parse(self, suite_element): - """Creates suite and populate with data from xml element.""" - suite = native_test.NativeTestSuite() - XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite) - return suite - - -class HostParser(XmlSuiteParser): - """Parses host suite attributes from xml.""" - - TAG_NAME = 'test-host' - - _CLASS_ATTR = 'class' - # TODO: consider obsoleting in favor of parsing the Android.mk to find the - # jar name - _JAR_ATTR = 'jar_name' - - def Parse(self, suite_element): - """Creates suite and populate with data from xml element.""" - suite = host_test.HostTestSuite() - XmlSuiteParser._ParseCommonAttributes(self, suite_element, suite) - suite.SetClassName(self._ParseAttribute(suite_element, self._CLASS_ATTR, - True)) - suite.SetJarName(self._ParseAttribute(suite_element, self._JAR_ATTR, True)) - return suite diff --git a/testrunner/tests/AndroidManifest.xml b/testrunner/tests/AndroidManifest.xml deleted file mode 100644 index e867f730f..000000000 --- a/testrunner/tests/AndroidManifest.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - diff --git a/testrunner/tests/Android_gtestlib.mk b/testrunner/tests/Android_gtestlib.mk deleted file mode 100644 index 0566fe955..000000000 --- a/testrunner/tests/Android_gtestlib.mk +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2011 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Build the unit tests. -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := $(call find-subdir-files, *.cpp) - -shared_libraries := \ - libz \ - liblog \ - libcutils \ - libutils \ - -static_libraries := \ - libgtest \ - libgtest_main - -c_includes := \ - external/gtest/include \ - -module_tags := eng tests - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval LOCAL_MODULE_TAGS := $(module_tags)) \ - $(eval include $(BUILD_EXECUTABLE)) \ -) diff --git a/testrunner/tests/Android_java.mk b/testrunner/tests/Android_java.mk deleted file mode 100644 index 2d6ac8836..000000000 --- a/testrunner/tests/Android_java.mk +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2011 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -# We only want this apk build for tests. -LOCAL_MODULE_TAGS := tests -LOCAL_JAVA_LIBRARIES := foo android.test.runner -# Include all test java files. -LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_PACKAGE_NAME := ApiDemosTests -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -LOCAL_INSTRUMENTATION_FOR := ApiDemos -LOCAL_SDK_VERSION := current - -include $(BUILD_PACKAGE) diff --git a/testrunner/tests/Android_native.mk b/testrunner/tests/Android_native.mk deleted file mode 100644 index e7ca0bf85..000000000 --- a/testrunner/tests/Android_native.mk +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (C) 2011 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -include $(CLEAR_VARS) -test_module := foo -LOCAL_MODULE := $(test_module) -LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0 -LOCAL_LICENSE_CONDITIONS := notice -recursive_var := $(recursive_var) -LOCAL_MODULE_TAGS := tags -LOCAL_SRC_FILES := src -include $(BUILD_NATIVE_TEST) diff --git a/testrunner/tests/am_instrument_parser_tests.py b/testrunner/tests/am_instrument_parser_tests.py deleted file mode 100755 index 55356eb4e..000000000 --- a/testrunner/tests/am_instrument_parser_tests.py +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -import sys -import unittest -sys.path.append('../..') - -from testrunner import am_instrument_parser - - -class AmParserTest(unittest.TestCase): - - def testParseAmInstResult(self): - result="""INSTRUMENTATION_RESULT: performance.java_size=4871 -INSTRUMENTATION_RESULT: stream= -Error: Failed to generate emma coverage. -INSTRUMENTATION_RESULT: performance.cpu_time=33846 -INSTRUMENTATION_CODE: -1 -""" - bundle_dict = \ - am_instrument_parser._ParseInstrumentationFinishedBundle(result) - self.assertEquals(4871, bundle_dict['java_size']) - self.assertEquals(33846, bundle_dict['cpu_time']) - self.assertEquals("\nError: Failed to generate emma coverage.", - bundle_dict['stream']) - - def testParseAmInstStatus(self): - # numtests before id - segment1 = """INSTRUMENTATION_STATUS: stream= -INSTRUMENTATION_STATUS: test=testLaunchComplexActivity -INSTRUMENTATION_STATUS: class=LaunchPerformanceTest -INSTRUMENTATION_STATUS: current=1 -INSTRUMENTATION_STATUS: numtests=2 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS_CODE: 1""" - segment2 = """INSTRUMENTATION_STATUS: stream=. -INSTRUMENTATION_STATUS: test=testLaunchComplexActivity -INSTRUMENTATION_STATUS: performance.cpu_time=866 -INSTRUMENTATION_STATUS: performance.execution_time=1242 -INSTRUMENTATION_STATUS: class=LaunchPerformanceTest -INSTRUMENTATION_STATUS: current=1 -INSTRUMENTATION_STATUS: numtests=2 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS_CODE: 0""" - # numtests after id - segment3 = """INSTRUMENTATION_STATUS: stream= -INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity -INSTRUMENTATION_STATUS: class=LaunchPerformanceTest -INSTRUMENTATION_STATUS: current=2 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS: numtests=8 -INSTRUMENTATION_STATUS_CODE: 1""" - segment4 = """INSTRUMENTATION_STATUS: stream=. -INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity -INSTRUMENTATION_STATUS: performance.cpu_time=590 -INSTRUMENTATION_STATUS: performance.execution_time=1122 -INSTRUMENTATION_STATUS: class=LaunchPerformanceTest -INSTRUMENTATION_STATUS: current=2 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS: numtests=8 -INSTRUMENTATION_STATUS_CODE: 0""" - - result = am_instrument_parser.TestResult(segment1) - map = result.GetResultFields() - self.assertEquals('testLaunchComplexActivity', map['test']) - self.assertEquals('LaunchPerformanceTest', map['class']) - self.assertEquals('1', map['current']) - self.assertEquals('2', map['numtests']) - self.assertEquals('InstrumentationTestRunner', map['id']) - self.assertEquals(1, result.GetStatusCode()) - - result = am_instrument_parser.TestResult(segment2) - map = result.GetResultFields() - self.assertEquals('testLaunchComplexActivity', map['test']) - self.assertEquals('866', map['cpu_time']) - self.assertEquals('1242', map['execution_time']) - self.assertEquals('LaunchPerformanceTest', map['class']) - self.assertEquals('1', map['current']) - self.assertEquals('2', map['numtests']) - self.assertEquals('InstrumentationTestRunner', map['id']) - self.assertEquals(0, result.GetStatusCode()) - - result = am_instrument_parser.TestResult(segment3) - map = result.GetResultFields() - self.assertEquals('testLaunchSimpleActivity', map['test']) - self.assertEquals('LaunchPerformanceTest', map['class']) - self.assertEquals('2', map['current']) - self.assertEquals('8', map['numtests']) - self.assertEquals('InstrumentationTestRunner', map['id']) - self.assertEquals(1, result.GetStatusCode()) - - result = am_instrument_parser.TestResult(segment4) - map = result.GetResultFields() - self.assertEquals('testLaunchSimpleActivity', map['test']) - self.assertEquals('590', map['cpu_time']) - self.assertEquals('1122', map['execution_time']) - self.assertEquals('LaunchPerformanceTest', map['class']) - self.assertEquals('2', map['current']) - self.assertEquals('8', map['numtests']) - self.assertEquals('InstrumentationTestRunner', map['id']) - self.assertEquals(0, result.GetStatusCode()) - - def testParseAmInstOutput(self): - result = """INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase -INSTRUMENTATION_STATUS: current=1 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS: numtests=2 -INSTRUMENTATION_STATUS: stream= -LaunchPerformanceTestCase: -INSTRUMENTATION_STATUS: test=testLaunchComplexActivity -INSTRUMENTATION_STATUS_CODE: 1 -INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase -INSTRUMENTATION_STATUS: current=1 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS: numtests=2 -INSTRUMENTATION_STATUS: performance.cpu_time=866 -INSTRUMENTATION_STATUS: performance.execution_time=1242 -INSTRUMENTATION_STATUS: stream=. -INSTRUMENTATION_STATUS: test=testLaunchComplexActivity -INSTRUMENTATION_STATUS_CODE: 0 -INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase -INSTRUMENTATION_STATUS: current=2 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS: numtests=2 -INSTRUMENTATION_STATUS: stream= -INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity -INSTRUMENTATION_STATUS_CODE: 1 -INSTRUMENTATION_STATUS: class=LaunchPerformanceTestCase -INSTRUMENTATION_STATUS: current=2 -INSTRUMENTATION_STATUS: id=InstrumentationTestRunner -INSTRUMENTATION_STATUS: numtests=2 -INSTRUMENTATION_STATUS: performance.cpu_time=590 -INSTRUMENTATION_STATUS: performance.execution_time=1122 -INSTRUMENTATION_STATUS: stream=. -INSTRUMENTATION_STATUS: test=testLaunchSimpleActivity -INSTRUMENTATION_STATUS_CODE: 0 -INSTRUMENTATION_RESULT: performance.cpu_time=829 -INSTRUMENTATION_RESULT: performance.execution_time=1708 -INSTRUMENTATION_RESULT: performance.gc_invocation_count=0 -INSTRUMENTATION_RESULT: performance.global_alloc_count=2848 -INSTRUMENTATION_RESULT: performance.global_alloc_size=193079 -INSTRUMENTATION_RESULT: performance.global_freed_count=1207 -INSTRUMENTATION_RESULT: performance.global_freed_size=93040 -INSTRUMENTATION_RESULT: performance.java_allocated=2175 -INSTRUMENTATION_RESULT: performance.java_free=580 -INSTRUMENTATION_RESULT: performance.java_private_dirty=740 -INSTRUMENTATION_RESULT: performance.java_pss=1609 -INSTRUMENTATION_RESULT: performance.java_shared_dirty=3860 -INSTRUMENTATION_RESULT: performance.java_size=2755 -INSTRUMENTATION_RESULT: performance.native_allocated=2585 -INSTRUMENTATION_RESULT: performance.native_free=34 -INSTRUMENTATION_RESULT: performance.native_private_dirty=632 -INSTRUMENTATION_RESULT: performance.native_pss=701 -INSTRUMENTATION_RESULT: performance.native_shared_dirty=1164 -INSTRUMENTATION_RESULT: performance.native_size=2620 -INSTRUMENTATION_RESULT: performance.other_private_dirty=896 -INSTRUMENTATION_RESULT: performance.other_pss=1226 -INSTRUMENTATION_RESULT: performance.other_shared_dirty=804 -INSTRUMENTATION_RESULT: performance.pre_received_transactions=-1 -INSTRUMENTATION_RESULT: performance.pre_sent_transactions=-1 -INSTRUMENTATION_RESULT: performance.received_transactions=-1 -INSTRUMENTATION_RESULT: performance.sent_transactions=-1 -INSTRUMENTATION_RESULT: stream= -Test results for InstrumentationTestRunner=.. -Time: 2.413 - -OK (2 tests) - - -INSTRUMENTATION_CODE: -1 -""" - (results_list, perf_dict) = \ - am_instrument_parser.ParseAmInstrumentOutput(result) - self.assertEquals(829, perf_dict['cpu_time']) - self.assertEquals(2848, perf_dict['global_alloc_count']) - self.assertEquals(93040, perf_dict['global_freed_size']) - self.assertEquals(740, perf_dict['java_private_dirty']) - self.assertEquals(2755, perf_dict['java_size']) - self.assertEquals(632, perf_dict['native_private_dirty']) - self.assertEquals(2620, perf_dict['native_size']) - self.assertEquals(804, perf_dict['other_shared_dirty']) - self.assertEquals(-1, perf_dict['received_transactions']) - self.assertTrue(len(perf_dict['stream']) > 50) - self.assertEquals('-1', perf_dict['code']) - - -if __name__ == "__main__": - unittest.main() diff --git a/testrunner/tests/android_manifest_tests.py b/testrunner/tests/android_manifest_tests.py deleted file mode 100755 index 2817726c4..000000000 --- a/testrunner/tests/android_manifest_tests.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/python2.4 -# -# -# Copyright 2009, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import unittest -sys.path.append('../..') - -from testrunner import android_manifest - - -class AndroidManifestTest(unittest.TestCase): - """Unit tests for AndroidManifest.""" - - def setUp(self): - """Create android_mainfest for testing from sample file.""" - self._manifest = android_manifest.AndroidManifest(app_path='.') - - def testGetPackageName(self): - self.assertEquals('com.example.android.tests', - self._manifest.GetPackageName()) - - def testGetInstrumentationNames(self): - self.assertEquals(['android.test.InstrumentationTestRunner'], - self._manifest.GetInstrumentationNames()) - - -if __name__ == '__main__': - unittest.main() diff --git a/testrunner/tests/android_mk_tests.py b/testrunner/tests/android_mk_tests.py deleted file mode 100755 index ff1f2896c..000000000 --- a/testrunner/tests/android_mk_tests.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/python -# -# -# Copyright 2011, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys -import unittest -sys.path.append('../..') - -from testrunner import android_mk - - -class AndroidMKTest(unittest.TestCase): - """Unit tests for AndroidMK.""" - - def testHasGTest(self): - """Test for AndroidMK.HasGTest.""" - mk_parser = android_mk.CreateAndroidMK(path='.', - filename='Android_native.mk') - self.assertTrue(mk_parser.HasGTest()) - - def testHasGTest_lib(self): - """Test for AndroidMK.HasGTest.""" - mk_parser = android_mk.CreateAndroidMK(path='.', - filename='Android_gtestlib.mk') - self.assertTrue(mk_parser.HasGTest()) - - def testHasGTest_false(self): - """Negative test for AndroidMK.HasGTest.""" - mk_parser = android_mk.CreateAndroidMK(path='.', filename='Android_java.mk') - self.assertFalse(mk_parser.HasGTest()) - - def testHasJavaLibrary(self): - """Test for AndroidMK.HasJavaLibrary.""" - mk_parser = android_mk.CreateAndroidMK(path='.', - filename='Android_java.mk') - self.assertTrue(mk_parser.HasJavaLibrary('android.test.runner')) - - def testHasJavaLibrary_missing(self): - """Negative test for AndroidMK.HasJavaLibrary. - - Test behavior when LOCAL_JAVA_LIBARIES rule is not present in makefile. - """ - mk_parser = android_mk.CreateAndroidMK(path='.', - filename='Android_native.mk') - self.assertFalse(mk_parser.HasJavaLibrary('android.test.runner')) - - def testHasJavaLibrary_false(self): - """Negative test for AndroidMK.HasJavaLibrary. - - Test behavior when LOCAL_JAVA_LIBARIES rule is present, but does not list - given library. - """ - mk_parser = android_mk.CreateAndroidMK(path='.', filename='Android_java.mk') - self.assertFalse(mk_parser.HasJavaLibrary('doesntexist')) - - def testGetExpandedVariable(self): - """Test for AndroidMK.GetExpandedVariable. - """ - mk_parser = android_mk.CreateAndroidMK(path='.', - filename='Android_native.mk') - self.assertEquals('foo', mk_parser.GetExpandedVariable('LOCAL_MODULE')) - - def testGetExpandedVariable_loop(self): - """Test for AndroidMK.GetExpandedVariable where variable expansion loops - """ - mk_parser = android_mk.CreateAndroidMK(path='.', - filename='Android_native.mk') - try: - mk_parser.GetExpandedVariable('recursive_var') - self.assertTrue(False) - except RuntimeError: - # expected - pass - - -if __name__ == '__main__': - unittest.main()