Index: test/lib/TestGyp.py |
diff --git a/test/lib/TestGyp.py b/test/lib/TestGyp.py |
index 119417d1c2b0c18197f3131723468fb301758382..3cea15e7bfcf0c52dc30654c08583775f95260db 100644 |
--- a/test/lib/TestGyp.py |
+++ b/test/lib/TestGyp.py |
@@ -409,10 +409,6 @@ class TestGypAndroid(TestGypBase): |
""" |
Subclass for testing the GYP Android makefile generator. Note that |
build/envsetup.sh and lunch must have been run before running tests. |
- |
- TODO: This is currently an incomplete implementation. We do not support |
- run_built_executable(), so we pass only tests which do not use this. As a |
- result, support for host targets is not properly tested. |
""" |
format = 'android' |
@@ -455,6 +451,20 @@ class TestGypAndroid(TestGypBase): |
os.remove(os.path.join(out_dir, x, d)) |
super(TestGypAndroid, self).__init__(*args, **kw) |
+ self._adb_path = os.path.join(os.environ['ANDROID_HOST_OUT'], 'bin', 'adb') |
+ self._device_serial = None |
+ adb_devices_out = self._call_adb(['devices']) |
+ devices = [l.split()[0] for l in adb_devices_out.splitlines()[1:-1] |
+ if l.split()[1] == 'device'] |
+ if len(devices) == 0: |
+ self._device_serial = None |
+ else: |
+ if len(devices) > 1: |
+ self._device_serial = random.choice(devices) |
+ else: |
+ self._device_serial = devices[0] |
+ self._call_adb(['root']) |
+ self._to_install = set() |
def target_name(self, target): |
if target == self.ALL: |
@@ -465,6 +475,8 @@ class TestGypAndroid(TestGypBase): |
return self.ALL |
return target |
+ _INSTALLABLE_PREFIX = 'Install: ' |
+ |
def build(self, gyp_file, target=None, **kw): |
""" |
Runs a build using the Android makefiles generated from the specified |
@@ -479,6 +491,11 @@ class TestGypAndroid(TestGypBase): |
makefile = os.path.join(self.workdir, chdir, 'GypAndroid.mk') |
os.environ['ONE_SHOT_MAKEFILE'] = makefile |
result = self.run(program=self.build_tool, **kw) |
+ for l in self.stdout().splitlines(): |
+ if l.startswith(TestGypAndroid._INSTALLABLE_PREFIX): |
+ self._to_install.add(os.path.abspath(os.path.join( |
+ os.environ['ANDROID_BUILD_TOP'], |
+ l[len(TestGypAndroid._INSTALLABLE_PREFIX):]))) |
del os.environ['ONE_SHOT_MAKEFILE'] |
return result |
@@ -501,15 +518,10 @@ class TestGypAndroid(TestGypBase): |
""" |
# Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from |
# the Android build system. |
- if type == None: |
+ if type == None or type == self.EXECUTABLE: |
return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', 'GYP', |
'shared_intermediates', name) |
subdir = kw.get('subdir') |
- if type == self.EXECUTABLE: |
- # We don't install executables |
- group = 'EXECUTABLES' |
- module_name = self.android_module(group, name, subdir) |
- return os.path.join(self.intermediates_dir(group, module_name), name) |
if type == self.STATIC_LIB: |
group = 'STATIC_LIBRARIES' |
module_name = self.android_module(group, name, subdir) |
@@ -522,23 +534,98 @@ class TestGypAndroid(TestGypBase): |
'%s.so' % module_name) |
assert False, 'Unhandled type' |
+ def _adb_failure(self, command, msg, stdout, stderr): |
+ """ Reports a failed adb command and fails the containing test. |
+ |
+ Args: |
+ command: The adb command that failed. |
+ msg: The error description. |
+ stdout: The standard output. |
+ stderr: The standard error. |
+ """ |
+ print '%s failed%s' % (' '.join(command), ': %s' % msg if msg else '') |
+ print self.banner('STDOUT ') |
+ stdout.seek(0) |
+ print stdout.read() |
+ print self.banner('STDERR ') |
+ stderr.seek(0) |
+ print stderr.read() |
+ self.fail_test() |
+ |
+ def _call_adb(self, command): |
+ """ Calls the provided adb command. |
+ |
+ If the command fails, the test fails. |
+ |
+ Args: |
+ command: The adb command to call. |
+ Returns: |
+ The command's output. |
+ """ |
+ with tempfile.TemporaryFile(bufsize=0) as adb_out: |
+ with tempfile.TemporaryFile(bufsize=0) as adb_err: |
+ adb_command = [self._adb_path] |
+ if self._device_serial: |
+ adb_command += ['-s', self._device_serial] |
+ is_shell = (command[0] == 'shell') |
+ if is_shell: |
+ command = [command[0], '%s; echo "\n$?";' % ' '.join(command[1:])] |
+ adb_command += command |
+ if subprocess.call(adb_command, stdout=adb_out, stderr=adb_err) != 0: |
+ self._adb_failure(adb_command, None, adb_out, adb_err) |
+ else: |
+ adb_out.seek(0) |
+ output = adb_out.read() |
+ if is_shell: |
+ output = output.splitlines(True) |
+ try: |
+ output[-2] = output[-2].rstrip('\r\n') |
+ output, rc = (''.join(output[:-1]), int(output[-1])) |
+ except ValueError: |
+ self._adb_failure(adb_command, 'unexpected output format', |
+ adb_out, adb_err) |
+ if rc != 0: |
+ self._adb_failure(adb_command, 'exited with %d' % rc, adb_out, |
+ adb_err) |
+ return output |
+ |
def run_built_executable(self, name, *args, **kw): |
""" |
Runs an executable program built from a gyp-generated configuration. |
- |
- This is not correctly implemented for Android. For now, we simply check |
- that the executable file exists. |
""" |
- # Running executables requires a device. Even if we build for target x86, |
- # the binary is not built with the correct toolchain options to actually |
- # run on the host. |
- |
- # Copied from TestCommon.run() |
match = kw.pop('match', self.match) |
- status = None |
- if os.path.exists(self.built_file_path(name)): |
- status = 1 |
- self._complete(None, None, None, None, status, match) |
+ |
+ executable_file = self.built_file_path(name, type=self.EXECUTABLE, **kw) |
+ if executable_file not in self._to_install: |
+ self.fail_test() |
+ |
+ if not self._device_serial: |
+ self.skip_test(message='No devices attached.\n') |
+ |
+ storage = self._call_adb(['shell', 'echo', '$ANDROID_DATA']).strip() |
+ if not len(storage): |
+ self.fail_test() |
+ |
+ installed = set() |
+ try: |
+ for i in self._to_install: |
+ a = os.path.abspath( |
+ os.path.join(os.environ['ANDROID_BUILD_TOP'], i)) |
+ dest = '%s/%s' % (storage, os.path.basename(a)) |
+ self._call_adb(['push', os.path.abspath(a), dest]) |
+ installed.add(dest) |
+ if i == executable_file: |
+ device_executable = dest |
+ self._call_adb(['shell', 'chmod', '755', device_executable]) |
+ |
+ out = self._call_adb( |
+ ['shell', 'LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s' % storage, |
+ device_executable]) |
+ out = out.replace('\r\n', '\n') |
+ self._complete(out, kw.pop('stdout', None), None, None, None, match) |
+ finally: |
+ if len(installed): |
+ self._call_adb(['shell', 'rm'] + list(installed)) |
def match_single_line(self, lines = None, expected_line = None): |
""" |