Chromium Code Reviews| Index: test/lib/TestGyp.py |
| diff --git a/test/lib/TestGyp.py b/test/lib/TestGyp.py |
| index cde04cac19bf7fa45fc8205249349038cbf6aa52..f50b33726d331a401761a62c3803bcea2968bdfa 100644 |
| --- a/test/lib/TestGyp.py |
| +++ b/test/lib/TestGyp.py |
| @@ -406,10 +406,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' |
| @@ -452,6 +448,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 = [] |
| def target_name(self, target): |
| if target == self.ALL: |
| @@ -462,6 +472,8 @@ class TestGypAndroid(TestGypBase): |
| return self.ALL |
| return target |
| + _installable_target_regex = re.compile('target Strip:\s*\S+\s+\((\S+)\)') |
| + |
| def build(self, gyp_file, target=None, **kw): |
| """ |
| Runs a build using the Android makefiles generated from the specified |
| @@ -476,6 +488,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(): |
| + target_result = TestGypAndroid._installable_target_regex.match(l) |
| + if target_result: |
| + self._to_install.append(os.path.abspath(os.path.join( |
| + os.environ['ANDROID_BUILD_TOP'], target_result.group(1)))) |
| del os.environ['ONE_SHOT_MAKEFILE'] |
| return result |
| @@ -519,23 +536,73 @@ class TestGypAndroid(TestGypBase): |
| '%s.so' % module_name) |
| assert False, 'Unhandled type' |
| + 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] |
| + adb_command += command |
| + if subprocess.call(adb_command, stdout=adb_out, stderr=adb_err) != 0: |
|
jbudorick
2014/06/11 16:30:22
(tests should fail here for nonzero exit codes)
|
| + print '%s failed:' % ' '.join(adb_command) |
| + print self.banner('STDOUT ') |
| + adb_out.seek(0) |
| + print adb_out.read() |
| + print self.banner('STDERR ') |
| + adb_err.seek(0) |
| + print adb_err.read() |
| + self.fail_test() |
| + else: |
| + adb_out.seek(0) |
| + output = adb_out.read() |
| + 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 = [] |
| + 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.append(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) |
|
Torne
2014/06/11 12:44:18
Is there a way to return the program's exit status
jbudorick
2014/06/11 16:30:22
If a program exits with a nonzero exit code, _call
Torne
2014/06/11 16:41:39
adb does not return the error code of the program
|
| + finally: |
| + if len(installed): |
| + self._call_adb(['shell', 'rm'] + installed) |
| def match_single_line(self, lines = None, expected_line = None): |
| """ |