Merge "Remove unused folder development/testrunner" into main am: 3d6df7c624

Original change: https://android-review.googlesource.com/c/platform/development/+/2825850

Change-Id: I4c2ba5a680302984a1af713fa2199cb10a781864
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-12-06 06:09:29 +00:00
committed by Automerger Merge Worker
37 changed files with 0 additions and 5726 deletions

View File

@@ -1,2 +0,0 @@
*.pyc
.*

View File

@@ -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)

View File

@@ -1 +0,0 @@
__all__ = ['adb_interface', 'android_build', 'errors', 'logger', 'run_command']

View File

@@ -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 <command>" 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)

View File

@@ -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<status_code>-?\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: '
'(?P<status_code>1|0|-1|-2)', result_block_string)
re_fields = re.compile(r'INSTRUMENTATION_STATUS: '
'(?P<key>[\w.]+)=(?P<value>.*?)(?=\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

View File

@@ -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")

View File

@@ -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 <manifest package="...">.
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

View File

@@ -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

View File

@@ -1 +0,0 @@
__all__ = ['coverage', 'coverage_targets', 'coverage_target']

View File

@@ -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
<android_out_path>/<_COVERAGE_REPORT_PATH>/<target>/<test[-qualifier]>
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 <root_path>/*/*.<_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()

View File

@@ -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

View File

@@ -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:
<targets>
<target
name=""
type="JAVA_LIBRARIES|APPS"
build_path=""
[<src path=""/>] (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

View File

@@ -1,112 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 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.
-->
<!--Defines the list of test code coverage targets for core android platform
Intent is to list all modules that are present in a typical 'user' build
TODO: auto-generate this file from build
Expected syntax in this file is
<coverage_targets>
<coverage_target name type build_path
[<src path=""/>] (0..*)
>/coverage_target>
Where
name - unique name of Android target
type - one of JAVA_LIBRARIES,APPS
build_path - path to build directory for this module, relative to android
source tree root
src - optional sub-elements. Contains complete set of source code locations
for target, relative to build_path. If not present, assumes valeu of "src"
-->
<coverage_targets>
<!-- Java libs -->
<coverage_target name="framework" type="JAVA_LIBRARIES"
build_path="frameworks/base">
<src path="core/java" />
<src path="graphics/java" />
<src path="im/java" />
<src path="location/java" />
<src path="media/java" />
<src path="opengl/java" />
<src path="sax/java" />
<src path="telephony/java" />
<src path="wifi/java" />
</coverage_target>
<coverage_target name="android.test.runner"
build_path="frameworks/base/test-runner" type="JAVA_LIBRARIES" />
<!-- apps -->
<coverage_target name="ApiDemos" build_path="development/samples/ApiDemos"
type="APPS" />
<coverage_target name="Calculator" build_path="packages/apps/Calculator"
type="APPS" />
<coverage_target name="Calendar" build_path="packages/apps/Calendar"
type="APPS" />
<coverage_target name="Camera" build_path="packages/apps/Camera"
type="APPS" />
<coverage_target name="Contacts" build_path="packages/apps/Contacts"
type="APPS" />
<coverage_target name="DeskClock" build_path="packages/apps/DeskClock"
type="APPS" />
<coverage_target name="Dialer" build_path="packages/apps/Dialer"
type="APPS" />
<coverage_target name="Email" build_path="packages/apps/Email"
type="APPS" />
<coverage_target name="Exchange" build_path="packages/apps/Exchange"
type="APPS" />
<coverage_target name="Settings" build_path="packages/apps/Settings"
type="APPS" />
<coverage_target name="Phone" build_path="packages/apps/Phone"
type="APPS" />
<coverage_target name="QuickSearchBox" build_path="packages/apps/QuickSearchBox"
type="APPS" />
<coverage_target name="Launcher2" build_path="packages/apps/Launcher2"
type="APPS" />
<coverage_target name="Mms" build_path="packages/apps/Mms" type="APPS" />
<coverage_target name="Music" build_path="packages/apps/Music"
type="APPS" />
<coverage_target name="SystemUI" build_path="frameworks/base/packages/SystemUI"
type="APPS" />
<coverage_target name="VoiceDialer" build_path="packages/apps/VoiceDialer"
type="APPS" />
<!-- content providers -->
<coverage_target name="CalendarProvider"
build_path="packages/providers/CalendarProvider" type="APPS" />
<coverage_target name="ContactsProvider"
build_path="packages/providers/ContactsProvider" type="APPS" />
<coverage_target name="DownloadProvider"
build_path="packages/providers/DownloadProvider" type="APPS" />
<coverage_target name="DrmProvider" build_path="packages/providers/drm"
type="APPS" />
<coverage_target name="MediaProvider"
build_path="packages/providers/MediaProvider" type="APPS" />
<coverage_target name="SettingsProvider"
build_path="frameworks/base/packages/SettingsProvider" type="APPS" />
<coverage_target name="TelephonyProvider"
build_path="packages/providers/telephony" type="APPS" />
<!-- input methods -->
<coverage_target name="LatinIME" build_path="packages/inputmethods/LatinIME"
type="APPS" />
</coverage_targets>

View File

@@ -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 = """<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) $YEAR 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="$PACKAGE_NAME.tests">
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="$PACKAGE_NAME"
android:label="Tests for $MODULE_NAME">
</instrumentation>
</manifest>
"""
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 <app_path>" % 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:])

View File

@@ -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."""

View File

@@ -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()

View File

@@ -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

View File

@@ -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")

View File

@@ -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 <testname>), or by specifying the file
system path to the test to run (runtest --path <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 <android root>/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: <name>' 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()

View File

@@ -1,484 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 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.
-->
<!--
This file contains standard test definitions for the Android platform
The following test types are supported:
- On device Java instrumentation tests are defined by <test> tags.
- native ones (C/C++) are defined by <test-native> tags.
- host java tests are defined by <test-host> tags.
See test_defs.xsd for more information.
-->
<test-definitions xmlns="http://schemas.android.com/testrunner/test_defs/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.android.com/testrunner/test_defs/1.0 test_defs.xsd">
<!-- frameworks tests -->
<test name="frameworks-core"
build_path="frameworks/base/core/tests/coretests"
package="com.android.frameworks.coretests"
runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous="true" />
<test name="frameworks-net"
build_path="frameworks/base/tests/net"
package="com.android.frameworks.tests.net"
runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous = "true" />
<!-- will not run in the continuous test as it needs both Wifi & 3G -->
<test name="frameworks-connectivity"
build_path="frameworks/base/core/tests/ConnectivityManagerTest/"
package="com.android.connectivitymanagertest"
runner=".ConnectivityManagerUnitTestRunner"
coverage_target="framework" />
<test name="frameworks-graphics"
build_path="frameworks/base/graphics/tests/graphicstests"
package="com.android.frameworks.graphicstests"
coverage_target="framework"
continuous="true" />
<test name="frameworks-location"
build_path="frameworks/base/location/tests/locationtests"
package="com.android.frameworks.locationtests"
runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous="true" />
<test name="frameworks-sax"
build_path="frameworks/base/sax/tests/saxtests"
package="com.android.frameworks.saxtests"
coverage_target="framework"
continuous="true" />
<test name="frameworks-services"
build_path="frameworks/base/services/tests/servicestests"
package="com.android.frameworks.servicestests"
runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous="true" />
<test name="frameworks-telephony"
build_path="frameworks/opt/telephony/tests/telephonytests"
package="com.android.frameworks.telephonytests"
runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous="true" />
<test name="frameworks-util"
build_path="frameworks/base/core/tests/utiltests"
package="com.android.frameworks.utiltests"
runner="android.support.test.runner.AndroidJUnitRunner"
continuous="true" />
<test name="frameworks-wifi"
build_path="frameworks/opt/net/wifi/tests/wifitests"
package="com.android.server.wifi.test"
runner="android.support.test.runner.AndroidJUnitRunner"
coverage_target="framework"
continuous="true" />
<test name="frameworks-testrunner"
build_path="frameworks/base/test-runner"
package="com.android.frameworks.testrunner.tests"
coverage_target="android.test.runner"
continuous="true" />
<test name="frameworks-vpn"
build_path="frameworks/base/vpn/tests/vpntests"
package="com.android.frameworks.vpntests"
coverage_target="framework"
continuous="true" />
<test name="frameworks-support"
build_path="frameworks/support/tests"
package="android.support.tests"
continuous="true" />
<test name="core"
build_path="frameworks/base/tests/CoreTests"
package="android.core"
coverage_target="framework"
continuous="true" />
<test name="keystore-unit"
build_path="frameworks/base/keystore/tests"
package="android.security.tests"
coverage_target="framework"
continuous="true" />
<test name="imf"
build_path="frameworks/base/tests/ImfTest"
package="com.android.imftest.tests"
coverage_target="framework"
continuous="true" />
<test name="framework-permission"
build_path="frameworks/base/tests/permission"
package="com.android.framework.permission.tests"
runner="android.test.InstrumentationTestRunner"
coverage_target="framework"
continuous="true" />
<test name="android-common"
build_path="frameworks/base/common/tests"
package="com.android.common.tests"
coverage_target="framework"
continuous="true" />
<test name="android-common-ex"
build_path="frameworks/ex/common/tests"
package="com.android.common.tests"
coverage_target="framework"
continuous="true" />
<test name="ex-variablespeed"
build_path="frameworks/ex/variablespeed/tests"
package="com.android.ex.variablespeed.tests"
coverage_target="framework"
continuous="true"
description="Framework variable speed audio tests" />
<test-native name="libandroidfw"
build_path="frameworks/base/libs/androidfw/tests"
description="Framework libandroidfw unit tests." />
<test-native name="libinput"
build_path="frameworks/native/libs/input/tests"
description="Framework libinput unit tests." />
<test-native name="libinputservice"
build_path="frameworks/base/services/input/tests"
description="Framework libinputservice unit tests." />
<test name="volley"
build_path="frameworks/support/volley/tests"
package="com.android.volley.tests"
continuous="true" />
<test name="networksecurityconfig"
build_path="frameworks/base/tests/NetworkSecurityConfigTest"
package="android.security.net.config"
coverage_target="framework"
description="Android network security config tests." />
<!-- end of framework tests -->
<!-- media framework tests -->
<test name="media"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaFrameworkTestRunner"
coverage_target="framework"
continuous="true" />
<test name="mediaapitest"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
class="com.android.mediaframeworktest.functional.MediaPlayerApiTest"
runner=".MediaFrameworkTestRunner"
coverage_target="framework" />
<test name="mediarecordertest"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
class="com.android.mediaframeworktest.functional.MediaRecorderTest"
runner=".MediaFrameworkTestRunner"
coverage_target="framework" />
<test name="mediastresstest"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaRecorderStressTestRunner"
coverage_target="framework" />
<test name="mediamemorystress"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaFrameworkPerfTestRunner"
coverage_target="framework" />
<test name="mediaunit"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaFrameworkUnitTestRunner"
coverage_target="framework" />
<test name="mediaintegrationtest"
build_path="frameworks/base/media/tests/MediaFrameworkTest"
package="com.android.mediaframeworktest"
runner=".MediaFrameworkIntegrationTestRunner"
coverage_target="framework" />
<test-native name="camera-client-native"
build_path="frameworks/av/camera/tests/"
description="Camera client native tests." />
<test-native name="camera-hal2-native"
build_path="hardware/libhardware/tests/camera2"
description="Camera hal2 native tests." />
<!-- end of media framework tests -->
<!-- targeted framework tests -->
<test name="account"
build_path="frameworks/base/core/tests/coretests"
package="com.android.frameworks.coretests"
class="android.accounts.AccountManagerServiceTest"
coverage_target="framework" />
<test name="smoke"
build_path="frameworks/base/tests/SmokeTest"
package="com.android.smoketest.tests"
coverage_target="framework"
continuous="true" />
<test name="launchperf"
build_path="development/apps/launchperf"
package="com.android.launchperf"
runner=".SimpleActivityLaunchPerformance"
coverage_target="framework" />
<test name="contentprovideroperation"
build_path="frameworks/base/core/tests/coretests"
package="com.android.frameworks.coretests"
class="android.content.ContentProviderOperationTest"
coverage_target="framework" />
<!-- selected app tests -->
<test name="apidemos"
build_path="development/samples/ApiDemos"
package="com.example.android.apis.tests" />
<test name="bluetooth"
build_path="packages/apps/Bluetooth/tests/unit"
package="com.android.bluetooth.tests"
runner="android.support.test.runner.AndroidJUnitRunner"
continuous="true" />
<test name="calculator"
build_path="packages/apps/Calculator"
package="com.android.calculator2.tests"
coverage_target="Calculator"
continuous="true" />
<test name="calendar"
build_path="packages/apps/Calendar"
package="com.android.calendar.tests"
coverage_target="Calendar"
continuous="true" />
<test name="calprov"
build_path="packages/providers/CalendarProvider"
package="com.android.providers.calendar.tests"
coverage_target="CalendarProvider"
continuous="true" />
<test name="camera-functional"
build_path="packages/apps/Camera"
package="com.google.android.camera.tests"
runner="com.android.camera.CameraTestRunner"
coverage_target="Camera"
description="Camera functional test"
continuous="true" />
<test name="contactsprov"
build_path="packages/providers/ContactsProvider"
package="com.android.providers.contacts.tests"
coverage_target="ContactsProvider"
continuous="true" />
<test name="contacts"
build_path="packages/apps/Contacts"
package="com.android.contacts.tests"
runner="android.test.InstrumentationTestRunner"
coverage_target="Contacts"
description="Tests for the Contacts app."
continuous="true" />
<test name="contacts-launch"
build_path="packages/apps/Contacts"
package="com.android.contacts.tests"
runner="com.android.contacts.ContactsLaunchPerformance"
description="Launch performance for Contacts." />
<test name="dialer"
build_path="packages/apps/Dialer"
package="com.android.dialer.tests"
runner="android.test.InstrumentationTestRunner"
coverage_target="Dialer"
description="Tests for the Dialer app."
continuous="true" />
<test name="managed-provisioning"
build_path="packages/apps/ManagedProvisioning/tests"
package="com.android.managedprovisioning.tests"
runner="com.android.managedprovisioning.TestInstrumentationRunner"
coverage_target="ManagedProvisioning"
description="Tests for the ManagedProvisioning app."
continuous="true" />
<test name="downloadprovider"
build_path="packages/providers/DownloadProvider/tests"
package="com.android.providers.downloads.tests"
coverage_target="DownloadProvider"
continuous="true" />
<test name="downloadprovider-permission"
build_path="packages/providers/DownloadProvider/tests/permission"
package="com.android.providers.downloads.permission.tests"
coverage_target="DownloadProvider"
continuous="true" />
<test name="email"
build_path="packages/apps/Email"
package="com.android.email.tests"
coverage_target="Email"
continuous="true" />
<test name="emailsmall"
build_path="packages/apps/Email"
package="com.android.email.tests"
class="com.android.email.SmallTests"
coverage_target="Email" />
<test name="exchange"
build_path="packages/apps/Exchange"
package="com.android.exchange.tests"
coverage_target="Exchange"
continuous="true" />
<test name="musicplayer"
build_path="packages/apps/Music"
package="com.android.music.tests"
runner=".MusicPlayerFunctionalTestRunner"
coverage_target="Music" />
<test name="mms"
build_path="packages/apps/Mms"
package="com.android.mms.tests"
coverage_target="Mms" />
<!-- Unit tests for the phone application. -->
<test name="phone-unit"
build_path="packages/services/Telephony"
package="com.android.phone.tests"
continuous="true"
coverage_target="Phone" />
<test name="carrierconfig-unit"
build_path="packages/apps/CarrierConfig"
package="com.android.carrierconfig.tests"
continuous="true"
coverage_target="Phone"
description="Tests for default carrier config app" />
<test name="telecom-unit"
build_path="packages/services/Telecomm"
package="com.android.server.telecom.tests"
continuous="true"
coverage_target="Phone" />
<test name="quicksearchbox"
build_path="packages/apps/QuickSearchBox"
package="com.android.quicksearchbox.tests"
coverage_target="QuickSearchBox" />
<test name="systemui"
build_path="frameworks/base/packages/SystemUI/tests"
package="com.android.systemui.tests"
coverage_target="SystemUI"
runner="android.testing.TestableInstrumentation"
continuous="true"
description="SystemUI tests" />
<test name="systemui-jank"
build_path="platform_testing/tests/jank/UbSystemUiJankTests"
package="android.platform.systemui.tests.jank"
runner="android.support.test.runner.AndroidJUnitRunner "
continuous="true"
description="SystemUI jank tests" />
<test name="systemui-notification"
build_path="frameworks/base/services/tests/uiservicestests"
package="com.android.frameworks.tests.uiservices"
runner="android.testing.TestableInstrumentation"
continuous="true"
description="SystemUI Services tests" />
<test name="systemui-functional-notification"
build_path="platform_testing/tests/functional/notificationtests"
package="com.android.notification.functional"
runner="android.support.test.runner.AndroidJUnitRunner"
continuous="true"
description="SystemUI functional notification tests" />
<test name="apptransition-perf"
build_path="platform_testing/tests/perf/PerfTransitionTest"
package="com.android.apptransition.tests"
runner="android.support.test.runner.AndroidJUnitRunner"
continuous="true"
description="App transition latency and other latency tests" />
<test name="documentsui"
build_path="frameworks/base/packages/DocumentsUI/tests"
package="com.android.documentsui.tests"
coverage_target="DocumentsUI"
continuous="true"
description="DocumentsUI tests" />
<!-- native tests -->
<!-- Bionic C++ -->
<test-native name="libstdcpp"
build_path="system/extras/tests/bionic/libstdc++"
description="Bionic libstdc++."
extra_build_args="BIONIC_TESTS=1" />
<test-native name="libskia"
build_path="external/skia/tests"
description="Skia tests." />
<!-- Google Test -->
<test-native name="gtest"
build_path="external/gtest"
description="Google test."
extra_build_args="GTEST_TESTS=1" />
<!-- clatd -->
<test-native name="clatd"
build_path="external/android-clat"
description="clatd unit tests." />
<!-- Libjingle -->
<test-native name="libjingle"
build_path="vendor/google/libraries/libjingle"
description="Libjingle."
full_make="true"
extra_build_args="LIBJINGLE_TESTS=1" />
<!-- host java tests -->
<test-host name="frameworks-core-host"
build_path="frameworks/base/core/tests/hosttests"
class="android.content.pm.PackageManagerHostTests"
jar_name="FrameworkCoreHostTests.jar" />
</test-definitions>

View File

@@ -1,141 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 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.
-->
<!-- Contains the schema definition for Android test definitions xml -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.android.com/testrunner/test_defs/1.0"
xmlns="http://schemas.android.com/testrunner/test_defs/1.0"
elementFormDefault="qualified">
<xs:element name="test-definitions">
<xs:complexType>
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="test" type="javaTestType" />
<xs:element name="test-native" type="nativeTestType" />
<xs:element name="test-host" type="hostTestType" />
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- Generic, abstract test definition. Contains attributes common to all
test types. -->
<xs:complexType name="testType">
<!-- Self-descriptive name used to uniquely identify the test. -->
<xs:attribute name="name" type="xs:string" use="required" />
<!-- File system path, relative to Android build root, to this
package's Android.mk file.-->
<xs:attribute name="build_path" type="xs:string" use="required" />
<!-- Include test in continuous test system. -->
<xs:attribute name="continuous" type="xs:boolean" use="optional"
default="false" />
<!-- Include test as part of named suite. -->
<xs:attribute name="suite" type="xs:string" use="optional" />
<!-- Short description (typically less than 60 characters) about this
test. -->
<xs:attribute name="description" type="xs:string" use="optional" />
<!-- Specifies that a full 'make', as opposed to 'mmm' command, is
needed to build this test. The build command used will be
'make extra_build_args' -->
<xs:attribute name="full_make" type="xs:boolean"
use="optional" />
<!-- Extra arguments to append to build command when building this
test. -->
<xs:attribute name="extra_build_args" type="xs:string"
use="optional" />
</xs:complexType>
<!-- Java on device instrumentation test.
The test attributes map to the following commands:
(if class is defined)
adb shell am instrument -w <package>/<runner>
(else)
adb shell am instrument -w -e class <class> <package>/<runner>
-->
<xs:complexType name="javaTestType">
<xs:complexContent>
<xs:extension base="testType">
<!-- Android application package that contains the tests. -->
<xs:attribute name="package" type="xs:string" use="required" />
<!-- Fully qualified Java test class to run. -->
<xs:attribute name="class" type="xs:string" use="optional" />
<!-- Fully qualified InstrumentationTestRunner to execute. -->
<xs:attribute name="runner" type="xs:string" use="optional"
default="android.test.InstrumentationTestRunner" />
<!-- Build name of Android package this test targets. These
targets are defined in the coverage_targets.xml file. Used as
basis for code coverage metrics. If omitted, code coverage will
not be supported for this test. -->
<xs:attribute name="coverage_target" type="xs:string"
use="optional" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!-- Native (C/C++) on device tests.
The native test attributes map to the following commands:
make <build_path>/Android.mk <extra_build_args>
adb sync
for test_prog in <tests built>; do
adb shell "/system/bin/${test_prog} >/dev/null 2>&1;echo \$?"
adb shell "rm /system/bin/${test_prog}"
done
-->
<xs:complexType name="nativeTestType">
<xs:complexContent>
<xs:extension base="testType" />
<!-- no additional attributes -->
</xs:complexContent>
</xs:complexType>
<!-- Host java tests.
Uses hosttestlib to execute tests on host. Maps to following command:
java -cp <libs>:jar_name com.android.hosttest.DeviceTestRunner \
<class> -s <device serial> -p <app build path>
-->
<xs:complexType name="hostTestType">
<xs:complexContent>
<xs:extension base="testType">
<!-- The test class to run. Must extend DeviceTestSuite, and
implement a public static suite() method that returns a Test to
run. -->
<xs:attribute name="class" type="xs:string" use="required" />
<!-- built jar name of host library that includes the tests. -->
<xs:attribute name="jar_name" type="xs:string" use="required" />
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>

View File

@@ -1 +0,0 @@
__all__ = ['test_defs', 'test_walker']

View File

@@ -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)

View File

@@ -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 <libs> <runner class> <test suite class> -s <device serial>
# -p <test data path>
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)

View File

@@ -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

View File

@@ -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/<os>-<arch>/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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 []

View File

@@ -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

View File

@@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 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.
-->
<!-- Sample manifest file used for unit testing -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.tests">
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.android"
android:label="Tests"/>
</manifest>

View File

@@ -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)) \
)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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()

View File

@@ -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()

View File

@@ -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()