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