mirror of
https://github.com/chromium/crashpad.git
synced 2025-01-14 01:08:01 +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 os
|
||||||
import pipes
|
import pipes
|
||||||
|
import posixpath
|
||||||
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import uuid
|
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')
|
IS_WINDOWS_HOST = sys.platform.startswith('win')
|
||||||
|
|
||||||
|
|
||||||
def _GetFuchsiaSDKRoot():
|
def _BinaryDirTargetOS(binary_dir):
|
||||||
arch = 'mac-amd64' if sys.platform == 'darwin' else 'linux-amd64'
|
"""Returns the apparent target OS of binary_dir, or None if none appear to be
|
||||||
return os.path.join(CRASHPAD_DIR, 'third_party', 'fuchsia', 'sdk', arch)
|
explicitly specified."""
|
||||||
|
|
||||||
|
# Look for a GN “target_os”.
|
||||||
def _BinaryDirLooksLikeFuchsiaBuild(binary_dir):
|
|
||||||
"""Checks whether the provided output directory targets Fuchsia."""
|
|
||||||
popen = subprocess.Popen(
|
popen = subprocess.Popen(
|
||||||
['gn', 'args', binary_dir, '--list=target_os', '--short'],
|
['gn', 'args', binary_dir, '--list=target_os', '--short'],
|
||||||
shell=IS_WINDOWS_HOST, stdout=subprocess.PIPE, stderr=open(os.devnull))
|
shell=IS_WINDOWS_HOST, stdout=subprocess.PIPE, stderr=open(os.devnull))
|
||||||
value = popen.communicate()[0]
|
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):
|
def _GenerateFuchsiaRuntimeDepsFiles(binary_dir, tests):
|
||||||
@ -170,7 +274,9 @@ def main(args):
|
|||||||
if os.path.isdir(binary_dir_32):
|
if os.path.isdir(binary_dir_32):
|
||||||
os.environ['CRASHPAD_TEST_32_BIT_OUTPUT'] = 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 = [
|
tests = [
|
||||||
'crashpad_client_test',
|
'crashpad_client_test',
|
||||||
@ -181,7 +287,26 @@ def main(args):
|
|||||||
'crashpad_util_test',
|
'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')
|
zircon_nodename = os.environ.get('ZIRCON_NODENAME')
|
||||||
if not zircon_nodename:
|
if not zircon_nodename:
|
||||||
netls = os.path.join(_GetFuchsiaSDKRoot(), 'tools', 'netls')
|
netls = os.path.join(_GetFuchsiaSDKRoot(), 'tools', 'netls')
|
||||||
@ -212,7 +337,9 @@ def main(args):
|
|||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
[sys.executable, os.path.join(CRASHPAD_DIR, test), binary_dir])
|
[sys.executable, os.path.join(CRASHPAD_DIR, test), binary_dir])
|
||||||
else:
|
else:
|
||||||
if is_fuchsia:
|
if is_android:
|
||||||
|
_RunOnAndroidTarget(binary_dir, test, android_device)
|
||||||
|
elif is_fuchsia:
|
||||||
_RunOnFuchsiaTarget(binary_dir, test, zircon_nodename)
|
_RunOnFuchsiaTarget(binary_dir, test, zircon_nodename)
|
||||||
else:
|
else:
|
||||||
subprocess.check_call(os.path.join(binary_dir, test))
|
subprocess.check_call(os.path.join(binary_dir, test))
|
||||||
|
@ -210,35 +210,18 @@ Software Development Kit.
|
|||||||
|
|
||||||
### Android
|
### Android
|
||||||
|
|
||||||
To test on Android, use [ADB (Android Debug
|
To test on Android, [ADB (Android Debug
|
||||||
Bridge)](https://developer.android.com/studio/command-line/adb.html) to `adb
|
Bridge)](https://developer.android.com/studio/command-line/adb.html) from the
|
||||||
push` test executables and test data to a device or emulator, then use `adb
|
[Android SDK](https://developer.android.com/sdk/) must be in the `PATH`. Note
|
||||||
shell` to get a shell to run the test executables from. ADB is part of the
|
that it is sufficient to install just the command-line tools from the Android
|
||||||
[Android SDK](https://developer.android.com/sdk/). Note that it is sufficient to
|
SDK. The entire Android Studio IDE is not necessary to obtain ADB.
|
||||||
install just the command-line tools. 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
|
When asked to test an Android build directory, `run_tests.py` will detect a
|
||||||
run-time dependency on a second executable and a test data file, which are also
|
single connected Android device (including an emulator). If multiple devices are
|
||||||
transferred to the device prior to running the test.
|
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
|
||||||
$ cd ~/crashpad/crashpad
|
when done.
|
||||||
$ 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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user