Index: test/lib/TestGyp.py |
diff --git a/test/lib/TestGyp.py b/test/lib/TestGyp.py |
index e085b7b9a8f074131a2f8ad962537bd8ebaa9e97..bf7afe1bbf7b9fc84ca16c9dcd66d504c578ada9 100644 |
--- a/test/lib/TestGyp.py |
+++ b/test/lib/TestGyp.py |
@@ -10,14 +10,11 @@ import collections |
from contextlib import contextmanager |
import itertools |
import os |
-import random |
import re |
import shutil |
-import stat |
import subprocess |
import sys |
import tempfile |
-import time |
import TestCmd |
import TestCommon |
@@ -411,276 +408,6 @@ class TestGypCustom(TestGypBase): |
super(TestGypCustom, self).__init__(*args, **kw) |
-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. |
- """ |
- format = 'android' |
- |
- # Note that we can't use mmm as the build tool because ... |
- # - it builds all targets, whereas we need to pass a target |
- # - it is a function, whereas the test runner assumes the build tool is a file |
- # Instead we use make and duplicate the logic from mmm. |
- build_tool_list = ['make'] |
- |
- # We use our custom target 'gyp_all_modules', as opposed to the 'all_modules' |
- # target used by mmm, to build only those targets which are part of the gyp |
- # target 'all'. |
- ALL = 'gyp_all_modules' |
- |
- def __init__(self, gyp=None, *args, **kw): |
- # Android requires build and test output to be inside its source tree. |
- # We use the following working directory for the test's source, but the |
- # test's build output still goes to $ANDROID_PRODUCT_OUT. |
- # Note that some tests explicitly set format='gypd' to invoke the gypd |
- # backend. This writes to the source tree, but there's no way around this. |
- kw['workdir'] = os.path.join('/tmp', 'gyptest', |
- kw.get('workdir', 'testworkarea')) |
- # We need to remove all gyp outputs from out/. Ths is because some tests |
- # don't have rules to regenerate output, so they will simply re-use stale |
- # output if present. Since the test working directory gets regenerated for |
- # each test run, this can confuse things. |
- # We don't have a list of build outputs because we don't know which |
- # dependent targets were built. Instead we delete all gyp-generated output. |
- # This may be excessive, but should be safe. |
- out_dir = os.environ['ANDROID_PRODUCT_OUT'] |
- obj_dir = os.path.join(out_dir, 'obj') |
- shutil.rmtree(os.path.join(obj_dir, 'GYP'), ignore_errors = True) |
- for x in ['EXECUTABLES', 'STATIC_LIBRARIES', 'SHARED_LIBRARIES']: |
- for d in os.listdir(os.path.join(obj_dir, x)): |
- if d.endswith('_gyp_intermediates'): |
- shutil.rmtree(os.path.join(obj_dir, x, d), ignore_errors = True) |
- for x in [os.path.join('obj', 'lib'), os.path.join('system', 'lib')]: |
- for d in os.listdir(os.path.join(out_dir, x)): |
- if d.endswith('_gyp.so'): |
- 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: |
- return self.ALL |
- # The default target is 'droid'. However, we want to use our special target |
- # to build only the gyp target 'all'. |
- if target in (None, self.DEFAULT): |
- 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 |
- gyp_file. This logic is taken from Android's mmm. |
- """ |
- arguments = kw.get('arguments', [])[:] |
- arguments.append(self.target_name(target)) |
- arguments.append('-C') |
- arguments.append(os.environ['ANDROID_BUILD_TOP']) |
- kw['arguments'] = arguments |
- chdir = kw.get('chdir', '') |
- 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 |
- |
- def android_module(self, group, name, subdir): |
- if subdir: |
- name = '%s_%s' % (subdir, name) |
- if group == 'SHARED_LIBRARIES': |
- name = 'lib_%s' % name |
- return '%s_gyp' % name |
- |
- def intermediates_dir(self, group, module_name): |
- return os.path.join(os.environ['ANDROID_PRODUCT_OUT'], 'obj', group, |
- '%s_intermediates' % module_name) |
- |
- def built_file_path(self, name, type=None, **kw): |
- """ |
- Returns a path to the specified file name, of the specified type, |
- as built by Android. Note that we don't support the configuration |
- parameter. |
- """ |
- # Built files are in $ANDROID_PRODUCT_OUT. This requires copying logic from |
- # the Android build system. |
- 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.STATIC_LIB: |
- group = 'STATIC_LIBRARIES' |
- module_name = self.android_module(group, name, subdir) |
- return os.path.join(self.intermediates_dir(group, module_name), |
- '%s.a' % module_name) |
- if type == self.SHARED_LIB: |
- group = 'SHARED_LIBRARIES' |
- module_name = self.android_module(group, name, subdir) |
- return os.path.join(self.intermediates_dir(group, module_name), 'LINKED', |
- '%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, timeout=15, retry=3): |
- """ 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 |
- |
- for attempt in xrange(1, retry + 1): |
- adb_out.seek(0) |
- adb_out.truncate(0) |
- adb_err.seek(0) |
- adb_err.truncate(0) |
- proc = subprocess.Popen(adb_command, stdout=adb_out, stderr=adb_err) |
- deadline = time.time() + timeout |
- timed_out = False |
- while proc.poll() is None and not timed_out: |
- time.sleep(1) |
- timed_out = time.time() > deadline |
- if timed_out: |
- print 'Timeout for command %s (attempt %d of %s)' % ( |
- adb_command, attempt, retry) |
- try: |
- proc.kill() |
- except: |
- pass |
- else: |
- break |
- |
- if proc.returncode != 0: # returncode is None in the case of a timeout. |
- self._adb_failure( |
- adb_command, 'retcode=%s' % proc.returncode, adb_out, adb_err) |
- return |
- |
- 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. |
- """ |
- match = kw.pop('match', self.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], |
- timeout=60, |
- retry=1) |
- 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): |
- """ |
- Checks that specified line appears in the text. |
- """ |
- for line in lines.split('\n'): |
- if line == expected_line: |
- return 1 |
- return |
- |
- def up_to_date(self, gyp_file, target=None, **kw): |
- """ |
- Verifies that a build of the specified target is up to date. |
- """ |
- kw['stdout'] = ("make: Nothing to be done for `%s'." % |
- self.target_name(target)) |
- |
- # We need to supply a custom matcher, since we don't want to depend on the |
- # exact stdout string. |
- kw['match'] = self.match_single_line |
- return self.build(gyp_file, target, **kw) |
- |
- |
class TestGypCMake(TestGypBase): |
""" |
Subclass for testing the GYP CMake generator, using cmake's ninja backend. |
@@ -1399,7 +1126,6 @@ class TestGypXcodeNinja(TestGypXcode): |
format_class_list = [ |
TestGypGypd, |
- TestGypAndroid, |
TestGypCMake, |
TestGypMake, |
TestGypMSVS, |