mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 06:31:50 +08:00
android: Run tests by running run_tests.py on the build host
Bug: crashpad:30 Change-Id: Ie432c58c4a2505b6434861276512a5011fd285d4 Reviewed-on: https://chromium-review.googlesource.com/811891 Commit-Queue: Mark Mentovai <mark@chromium.org> Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
parent
914b0d6755
commit
659420bc7d
@ -19,6 +19,8 @@ from __future__ import print_function
|
||||
|
||||
import os
|
||||
import pipes
|
||||
import posixpath
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import uuid
|
||||
@ -28,18 +30,120 @@ CRASHPAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
IS_WINDOWS_HOST = sys.platform.startswith('win')
|
||||
|
||||
|
||||
def _GetFuchsiaSDKRoot():
|
||||
arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64'
|
||||
return os.path.join(CRASHPAD_DIR, 'third_party', 'fuchsia', 'sdk', arch)
|
||||
def _BinaryDirTargetOS(binary_dir):
|
||||
"""Returns the apparent target OS of binary_dir, or None if none appear to be
|
||||
explicitly specified."""
|
||||
|
||||
|
||||
def _BinaryDirLooksLikeFuchsiaBuild(binary_dir):
|
||||
"""Checks whether the provided output directory targets Fuchsia."""
|
||||
# Look for a GN “target_os”.
|
||||
popen = subprocess.Popen(
|
||||
['gn', 'args', binary_dir, '--list=target_os', '--short'],
|
||||
shell=IS_WINDOWS_HOST, stdout=subprocess.PIPE, stderr=open(os.devnull))
|
||||
value = popen.communicate()[0]
|
||||
return popen.returncode == 0 and 'target_os = "fuchsia"' in value
|
||||
if popen.returncode == 0:
|
||||
match = re.match('target_os = "(.*)"$', value.decode('utf-8'))
|
||||
if match:
|
||||
return match.group(1)
|
||||
|
||||
# For GYP with Ninja, look for the appearance of “linux-android” in the path
|
||||
# to ar. This path is configured by gyp_crashpad_android.py.
|
||||
try:
|
||||
with open(os.path.join(binary_dir, 'build.ninja')) as build_ninja_file:
|
||||
build_ninja_content = build_ninja_file.read()
|
||||
match = re.search('^ar = .+-linux-android(eabi)?-ar$',
|
||||
build_ninja_content,
|
||||
re.MULTILINE)
|
||||
if match:
|
||||
return 'android'
|
||||
except FileNotFoundError:
|
||||
# Ninja may not be in use. Assume the best.
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def _RunOnAndroidTarget(binary_dir, test, android_device):
|
||||
local_test_path = os.path.join(binary_dir, test)
|
||||
MAYBE_UNSUPPORTED_TESTS = (
|
||||
'crashpad_client_test',
|
||||
'crashpad_handler_test',
|
||||
'crashpad_minidump_test',
|
||||
'crashpad_snapshot_test',
|
||||
)
|
||||
if not os.path.exists(local_test_path) and test in MAYBE_UNSUPPORTED_TESTS:
|
||||
print(test, 'is not present and may not be supported, skipping')
|
||||
return
|
||||
|
||||
device_temp_dir = subprocess.check_output(
|
||||
['adb', '-s', android_device, 'shell',
|
||||
'mktemp', '-d', '/data/local/tmp/%s.XXXXXXXX' % test],
|
||||
shell=IS_WINDOWS_HOST).decode('utf-8').rstrip()
|
||||
try:
|
||||
# Specify test dependencies that must be pushed to the device. This could be
|
||||
# determined automatically in a GN build, following the example used for
|
||||
# Fuchsia. Since nothing like that exists for GYP, hard-code it for
|
||||
# supported tests.
|
||||
test_build_artifacts = [test]
|
||||
test_data = ['test/test_paths_test_data_root.txt']
|
||||
|
||||
if test == 'crashpad_test_test':
|
||||
test_build_artifacts.append(
|
||||
'crashpad_test_test_multiprocess_exec_test_child')
|
||||
elif test == 'crashpad_util_test':
|
||||
test_data.append('util/net/testdata/')
|
||||
|
||||
def _adb(*args):
|
||||
# Flush all of this script’s own buffered stdout output before running
|
||||
# adb, which will likely produce its own output on stdout.
|
||||
sys.stdout.flush()
|
||||
|
||||
adb_command = ['adb', '-s', android_device]
|
||||
adb_command.extend(args)
|
||||
subprocess.check_call(adb_command, shell=IS_WINDOWS_HOST)
|
||||
|
||||
# Establish the directory structure on the device.
|
||||
device_out_dir = posixpath.join(device_temp_dir, 'out')
|
||||
device_mkdirs = [device_out_dir]
|
||||
for source_path in test_data:
|
||||
# A trailing slash could reasonably mean to copy an entire directory, but
|
||||
# will interfere with what’s needed from the path split. All parent
|
||||
# directories of any source_path need to be be represented in
|
||||
# device_mkdirs, but it’s important that no source_path itself wind up in
|
||||
# device_mkdirs, even if source_path names a directory, because that would
|
||||
# cause the “adb push” of the directory below to behave incorrectly.
|
||||
if source_path.endswith(posixpath.sep):
|
||||
source_path = source_path[:-1]
|
||||
|
||||
device_source_path = posixpath.join(device_temp_dir, source_path)
|
||||
device_mkdir = posixpath.split(device_source_path)[0]
|
||||
if device_mkdir not in device_mkdirs:
|
||||
device_mkdirs.append(device_mkdir)
|
||||
adb_mkdir_command = ['shell', 'mkdir', '-p']
|
||||
adb_mkdir_command.extend(device_mkdirs)
|
||||
_adb(*adb_mkdir_command)
|
||||
|
||||
# Push the test binary and any other build output to the device.
|
||||
adb_push_command = ['push']
|
||||
for artifact in test_build_artifacts:
|
||||
adb_push_command.append(os.path.join(binary_dir, artifact))
|
||||
adb_push_command.append(device_out_dir)
|
||||
_adb(*adb_push_command)
|
||||
|
||||
# Push test data to the device.
|
||||
for source_path in test_data:
|
||||
_adb('push',
|
||||
os.path.join(CRASHPAD_DIR, source_path),
|
||||
posixpath.join(device_temp_dir, source_path))
|
||||
|
||||
# Run the test on the device.
|
||||
_adb('shell', 'env', 'CRASHPAD_TEST_DATA_ROOT=' + device_temp_dir,
|
||||
posixpath.join(device_out_dir, test))
|
||||
finally:
|
||||
_adb('shell', 'rm', '-rf', device_temp_dir)
|
||||
|
||||
|
||||
def _GetFuchsiaSDKRoot():
|
||||
arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64'
|
||||
return os.path.join(CRASHPAD_DIR, 'third_party', 'fuchsia', 'sdk', arch)
|
||||
|
||||
|
||||
def _GenerateFuchsiaRuntimeDepsFiles(binary_dir, tests):
|
||||
@ -170,7 +274,9 @@ def main(args):
|
||||
if os.path.isdir(binary_dir_32):
|
||||
os.environ['CRASHPAD_TEST_32_BIT_OUTPUT'] = binary_dir_32
|
||||
|
||||
is_fuchsia = _BinaryDirLooksLikeFuchsiaBuild(binary_dir)
|
||||
target_os = _BinaryDirTargetOS(binary_dir)
|
||||
is_android = target_os == 'android'
|
||||
is_fuchsia = target_os == 'fuchsia'
|
||||
|
||||
tests = [
|
||||
'crashpad_client_test',
|
||||
@ -181,7 +287,26 @@ def main(args):
|
||||
'crashpad_util_test',
|
||||
]
|
||||
|
||||
if is_fuchsia:
|
||||
if is_android:
|
||||
android_device = os.environ.get('ANDROID_DEVICE')
|
||||
if not android_device:
|
||||
adb_devices = subprocess.check_output(['adb', 'devices'],
|
||||
shell=IS_WINDOWS_HOST)
|
||||
devices = []
|
||||
for line in adb_devices.splitlines():
|
||||
line = line.decode('utf-8')
|
||||
if (line == 'List of devices attached' or
|
||||
re.match('^\* daemon .+ \*$', line) or
|
||||
line == ''):
|
||||
continue
|
||||
(device, ignore) = line.split('\t')
|
||||
devices.append(device)
|
||||
if len(devices) != 1:
|
||||
print("Please set ANDROID_DEVICE to your device's id", file=sys.stderr)
|
||||
return 2
|
||||
android_device = devices[0]
|
||||
print('Using autodetected Android device:', android_device)
|
||||
elif is_fuchsia:
|
||||
zircon_nodename = os.environ.get('ZIRCON_NODENAME')
|
||||
if not zircon_nodename:
|
||||
netls = os.path.join(_GetFuchsiaSDKRoot(), 'tools', 'netls')
|
||||
@ -212,7 +337,9 @@ def main(args):
|
||||
subprocess.check_call(
|
||||
[sys.executable, os.path.join(CRASHPAD_DIR, test), binary_dir])
|
||||
else:
|
||||
if is_fuchsia:
|
||||
if is_android:
|
||||
_RunOnAndroidTarget(binary_dir, test, android_device)
|
||||
elif is_fuchsia:
|
||||
_RunOnFuchsiaTarget(binary_dir, test, zircon_nodename)
|
||||
else:
|
||||
subprocess.check_call(os.path.join(binary_dir, test))
|
||||
|
@ -210,35 +210,18 @@ Software Development Kit.
|
||||
|
||||
### Android
|
||||
|
||||
To test on Android, use [ADB (Android Debug
|
||||
Bridge)](https://developer.android.com/studio/command-line/adb.html) to `adb
|
||||
push` test executables and test data to a device or emulator, then use `adb
|
||||
shell` to get a shell to run the test executables from. ADB is part of the
|
||||
[Android SDK](https://developer.android.com/sdk/). Note that it is sufficient to
|
||||
install just the command-line tools. The entire Android Studio IDE is not
|
||||
necessary to obtain ADB.
|
||||
To test on Android, [ADB (Android Debug
|
||||
Bridge)](https://developer.android.com/studio/command-line/adb.html) from the
|
||||
[Android SDK](https://developer.android.com/sdk/) must be in the `PATH`. Note
|
||||
that it is sufficient to install just the command-line tools from the Android
|
||||
SDK. The entire Android Studio IDE is not necessary to obtain ADB.
|
||||
|
||||
This example runs `crashpad_test_test` on a device. This test executable has a
|
||||
run-time dependency on a second executable and a test data file, which are also
|
||||
transferred to the device prior to running the test.
|
||||
|
||||
```
|
||||
$ cd ~/crashpad/crashpad
|
||||
$ adb push out/android_arm64_api21/out/Debug/crashpad_test_test /data/local/tmp/
|
||||
[100%] /data/local/tmp/crashpad_test_test
|
||||
$ adb push \
|
||||
out/android_arm64_api21/out/Debug/crashpad_test_test_multiprocess_exec_test_child \
|
||||
/data/local/tmp/
|
||||
[100%] /data/local/tmp/crashpad_test_test_multiprocess_exec_test_child
|
||||
$ adb shell mkdir -p /data/local/tmp/crashpad_test_data_root/test
|
||||
$ adb push test/test_paths_test_data_root.txt \
|
||||
/data/local/tmp/crashpad_test_data_root/test/
|
||||
[100%] /data/local/tmp/crashpad_test_data_root/test/test_paths_test_data_root.txt
|
||||
$ adb shell
|
||||
device:/ $ cd /data/local/tmp
|
||||
device:/data/local/tmp $ CRASHPAD_TEST_DATA_ROOT=crashpad_test_data_root \
|
||||
./crashpad_test_test
|
||||
```
|
||||
When asked to test an Android build directory, `run_tests.py` will detect a
|
||||
single connected Android device (including an emulator). If multiple devices are
|
||||
connected, one may be chosen explicitly with the `ANDROID_DEVICE` environment
|
||||
variable. `run_tests.py` will upload test executables and data to a temporary
|
||||
location on the detected or selected device, run them, and clean up after itself
|
||||
when done.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user