| Index: ios/build/bots/scripts/test_runner.py
|
| diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
|
| index 01c0dc241954ce5c3f079c431f91632a62786f7d..432b24101f89b81e517c907a3f1dcd17a60c4980 100644
|
| --- a/ios/build/bots/scripts/test_runner.py
|
| +++ b/ios/build/bots/scripts/test_runner.py
|
| @@ -6,6 +6,7 @@
|
|
|
| import argparse
|
| import collections
|
| +import errno
|
| import os
|
| import shutil
|
| import subprocess
|
| @@ -36,7 +37,14 @@ class AppNotFoundError(TestRunnerError):
|
| """The requested app was not found."""
|
| def __init__(self, app_path):
|
| super(AppNotFoundError, self).__init__(
|
| - 'App does not exist: %s' % app_path)
|
| + 'App does not exist: %s' % app_path)
|
| +
|
| +
|
| +class DeviceDetectionError(TestRunnerError):
|
| + """Unexpected number of devices detected."""
|
| + def __init__(self, udids):
|
| + super(DeviceDetectionError, self).__init__(
|
| + 'Expected one device, found %s:\n%s' % (len(udids), '\n'.join(udids)))
|
|
|
|
|
| class SimulatorNotFoundError(TestRunnerError):
|
| @@ -96,13 +104,15 @@ def get_gtest_filter(tests, invert=False):
|
| class TestRunner(object):
|
| """Base class containing common functionality."""
|
|
|
| - def __init__(self, app_path, xcode_version, out_dir, test_args=None):
|
| + def __init__(
|
| + self, app_path, xcode_version, out_dir, env_vars=None, test_args=None):
|
| """Initializes a new instance of this class.
|
|
|
| Args:
|
| app_path: Path to the compiled .app to run.
|
| xcode_version: Version of Xcode to use when running the test.
|
| out_dir: Directory to emit test data into.
|
| + env_vars: List of environment variables to pass to the test itself.
|
| test_args: List of strings to pass as arguments to the test when
|
| launching.
|
|
|
| @@ -126,9 +136,11 @@ class TestRunner(object):
|
| '-c', 'Print:CFBundleIdentifier',
|
| os.path.join(app_path, 'Info.plist'),
|
| ]).rstrip()
|
| + self.env_vars = env_vars or []
|
| self.logs = collections.OrderedDict()
|
| self.out_dir = out_dir
|
| self.test_args = test_args or []
|
| + self.xcode_version = xcode_version
|
|
|
| def get_launch_command(self, test_filter=None, invert=False):
|
| """Returns the command that can be used to launch the test app.
|
| @@ -267,6 +279,7 @@ class SimulatorTestRunner(TestRunner):
|
| version,
|
| xcode_version,
|
| out_dir,
|
| + env_vars=None,
|
| test_args=None,
|
| ):
|
| """Initializes a new instance of this class.
|
| @@ -280,6 +293,7 @@ class SimulatorTestRunner(TestRunner):
|
| can be found by running "iossim -l". e.g. "9.3", "8.2", "7.1".
|
| xcode_version: Version of Xcode to use when running the test.
|
| out_dir: Directory to emit test data into.
|
| + env_vars: List of environment variables to pass to the test itself.
|
| test_args: List of strings to pass as arguments to the test when
|
| launching.
|
|
|
| @@ -288,7 +302,12 @@ class SimulatorTestRunner(TestRunner):
|
| XcodeVersionNotFoundError: If the given Xcode version does not exist.
|
| """
|
| super(SimulatorTestRunner, self).__init__(
|
| - app_path, xcode_version, out_dir, test_args=test_args)
|
| + app_path,
|
| + xcode_version,
|
| + out_dir,
|
| + env_vars=env_vars,
|
| + test_args=test_args,
|
| + )
|
|
|
| if not os.path.exists(iossim_path):
|
| raise SimulatorNotFoundError(iossim_path)
|
| @@ -417,9 +436,110 @@ class SimulatorTestRunner(TestRunner):
|
| kif_filter = get_kif_test_filter(test_filter, invert=invert)
|
| gtest_filter = get_gtest_filter(test_filter, invert=invert)
|
| cmd.extend(['-e', 'GKIF_SCENARIO_FILTER=%s' % kif_filter])
|
| - args.append('--gtest_filter=%s' % gtest_filter)
|
| +
|
| + if self.xcode_version == '8.0':
|
| + args.extend(['-c', '--gtest_filter=%s' % gtest_filter])
|
| + else:
|
| + args.append('--gtest_filter=%s' % gtest_filter)
|
| +
|
| + for env_var in self.env_vars:
|
| + cmd.extend(['-e', env_var])
|
|
|
| cmd.append(self.app_path)
|
| cmd.extend(self.test_args)
|
| cmd.extend(args)
|
| return cmd
|
| +
|
| +
|
| +class DeviceTestRunner(TestRunner):
|
| + """Class for running tests on devices."""
|
| +
|
| + def __init__(
|
| + self, app_path, xcode_version, out_dir, env_vars=None, test_args=None):
|
| + """Initializes a new instance of this class.
|
| +
|
| + Args:
|
| + app_path: Path to the compiled .app to run.
|
| + xcode_version: Version of Xcode to use when running the test.
|
| + out_dir: Directory to emit test data into.
|
| + env_vars: List of environment variables to pass to the test itself.
|
| + test_args: List of strings to pass as arguments to the test when
|
| + launching.
|
| +
|
| + Raises:
|
| + AppNotFoundError: If the given app does not exist.
|
| + XcodeVersionNotFoundError: If the given Xcode version does not exist.
|
| + """
|
| + super(DeviceTestRunner, self).__init__(
|
| + app_path, xcode_version, out_dir, env_vars=env_vars, test_args=test_args)
|
| +
|
| + self.udid = subprocess.check_output(['idevice_id', '--list']).rstrip()
|
| + if len(self.udid.splitlines()) != 1:
|
| + raise DeviceDetectionError(self.udid)
|
| +
|
| + def uninstall_apps(self):
|
| + """Uninstalls all apps found on the device."""
|
| + for app in subprocess.check_output(
|
| + ['idevicefs', '--udid', self.udid, 'ls', '@']).splitlines():
|
| + subprocess.check_call(
|
| + ['ideviceinstaller', '--udid', self.udid, '--uninstall', app])
|
| +
|
| + def install_app(self):
|
| + """Installs the app."""
|
| + subprocess.check_call(
|
| + ['ideviceinstaller', '--udid', self.udid, '--install', self.app_path])
|
| +
|
| + def set_up(self):
|
| + """Performs setup actions which must occur prior to every test launch."""
|
| + self.uninstall_apps()
|
| + self.install_app()
|
| +
|
| + def extract_test_data(self):
|
| + """Extracts data emitted by the test."""
|
| + subprocess.check_call([
|
| + 'idevicefs',
|
| + '--udid', self.udid,
|
| + 'pull',
|
| + '@%s/Documents' % self.cfbundleid,
|
| + os.path.join(self.out_dir, 'Documents'),
|
| + ])
|
| +
|
| + def tear_down(self):
|
| + """Performs cleanup actions which must occur after every test launch."""
|
| + self.extract_test_data()
|
| + self.screenshot_desktop()
|
| + self.uninstall_apps()
|
| +
|
| + def get_launch_command(self, test_filter=None, invert=False):
|
| + """Returns the command that can be used to launch the test app.
|
| +
|
| + Args:
|
| + test_filter: List of test cases to filter.
|
| + invert: Whether to invert the filter or not. Inverted, the filter will
|
| + match everything except the given test cases.
|
| +
|
| + Returns:
|
| + A list of strings forming the command to launch the test.
|
| + """
|
| + cmd = [
|
| + 'idevice-app-runner',
|
| + '--udid', self.udid,
|
| + '--start', self.cfbundleid,
|
| + ]
|
| + args = []
|
| +
|
| + if test_filter:
|
| + kif_filter = get_kif_test_filter(test_filter, invert=invert)
|
| + gtest_filter = get_gtest_filter(test_filter, invert=invert)
|
| + cmd.extend(['-D', 'GKIF_SCENARIO_FILTER=%s' % kif_filter])
|
| + args.append('--gtest-filter=%s' % gtest_filter)
|
| +
|
| + for env_var in self.env_vars:
|
| + cmd.extend(['-D', env_var])
|
| +
|
| + if args or self.test_args:
|
| + cmd.append('--args')
|
| + cmd.extend(self.test_args)
|
| + cmd.extend(args)
|
| +
|
| + return cmd
|
|
|