Exemplo n.º 1
0
    def profile_plist_obj(self):
        """Gets the Plist object of the simulator device type's profile.plist.

    Returns:
      plist_util.Plist, the Plist object of the simulator device type's
      profile.plist.
    """
        if not self._profile_plist_obj:
            if xcode_info_util.GetXcodeVersionNumber() >= 900:
                platform_path = xcode_info_util.GetSdkPlatformPath(
                    ios_constants.SDK.IPHONEOS)
            else:
                platform_path = xcode_info_util.GetSdkPlatformPath(
                    ios_constants.SDK.IPHONESIMULATOR)
            if xcode_info_util.GetXcodeVersionNumber() >= 1100:
                sim_profiles_dir = os.path.join(
                    platform_path, 'Library/Developer/CoreSimulator/Profiles')
            else:
                sim_profiles_dir = os.path.join(
                    platform_path, 'Developer/Library/CoreSimulator/Profiles')
            profile_plist_path = os.path.join(
                sim_profiles_dir,
                'DeviceTypes/%s.simdevicetype/Contents/Resources/profile.plist'
                % self._device_type)
            self._profile_plist_obj = plist_util.Plist(profile_plist_path)
        return self._profile_plist_obj
Exemplo n.º 2
0
    def GetAppDocumentsPath(self, app_bundle_id):
        """Gets the path of the app's Documents directory."""
        if xcode_info_util.GetXcodeVersionNumber() >= 830:
            try:
                app_data_container = RunSimctlCommand([
                    'xcrun', 'simctl', 'get_app_container', self._simulator_id,
                    app_bundle_id, 'data'
                ])
                return os.path.join(app_data_container, 'Documents')
            except ios_errors.SimError as e:
                raise ios_errors.SimError(
                    'Failed to get data container of the app %s in simulator %s: %s'
                    % (app_bundle_id, self._simulator_id, str(e)))

        apps_dir = os.path.join(self.simulator_root_dir,
                                'data/Containers/Data/Application')
        for sub_dir_name in os.listdir(apps_dir):
            container_manager_plist = plist_util.Plist(
                os.path.join(
                    apps_dir, sub_dir_name,
                    '.com.apple.mobile_container_manager.metadata.plist'))
            current_app_bundle_id = container_manager_plist.GetPlistField(
                'MCMMetadataIdentifier')
            if current_app_bundle_id == app_bundle_id:
                return os.path.join(apps_dir, sub_dir_name, 'Documents')
        raise ios_errors.SimError(
            'Failed to get Documents directory of the app %s in simulator %s' %
            (app_bundle_id, self._simulator_id))
Exemplo n.º 3
0
    def Delete(self):
        """Deletes the simulator asynchronously.

    The simulator state should be SHUTDOWN when deleting it. Otherwise, it will
    raise exception.

    Raises:
      ios_errors.SimError: The simulator's state is not SHUTDOWN.
    """
        # In Xcode 9+, simctl can delete Booted simulator. In prior of Xcode 9,
        # we have to shutdown the simulator first before deleting it.
        if xcode_info_util.GetXcodeVersionNumber() < 900:
            sim_state = self.GetSimulatorState()
            if sim_state != ios_constants.SimState.SHUTDOWN:
                raise ios_errors.SimError(
                    'Can only delete the simulator with state SHUTDOWN. The current '
                    'state of simulator %s is %s.' %
                    (self._simulator_id, sim_state))
        logging.info('Deleting simulator %s asynchronously.',
                     self.simulator_id)
        subprocess.Popen(['xcrun', 'simctl', 'delete', self.simulator_id],
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         preexec_fn=os.setpgrp)
        # The delete command won't delete the simulator log directory.
        if os.path.exists(self.simulator_log_root_dir):
            shutil.rmtree(self.simulator_log_root_dir)
        self._simulator_id = None
Exemplo n.º 4
0
def RunLogicTestOnSim(sim_id,
                      test_bundle_path,
                      env_vars=None,
                      args=None,
                      tests_to_run=None,
                      os_version=None):
    """Runs logic tests on the simulator. The output prints on system stdout.

  Args:
    sim_id: string, the id of the simulator.
    test_bundle_path: string, the path of the logic test bundle.
    env_vars: dict, the additionl environment variables passing to test's
        process.
    args: array, the additional arguments passing to test's process.
    tests_to_run: array, the format of each item is TestClass[/TestMethod].
        If it is empty, then runs with All methods.
    os_version: string, the OS version of the simulator.

  Returns:
    exit_code: A value of type runner_exit_codes.EXITCODE.

  Raises:
    ios_errors.SimError: The command to launch logic test has error.
  """
    simctl_env_vars = {}
    if env_vars:
        for key in env_vars:
            simctl_env_vars[_SIMCTL_ENV_VAR_PREFIX + key] = env_vars[key]
    simctl_env_vars['NSUnbufferedIO'] = 'YES'
    # When running tests on iOS 12.1 or earlier simulator under Xcode 11 or later,
    # it is required to add swift5 fallback libraries to environment variable.
    # See https://github.com/bazelbuild/rules_apple/issues/684 for context.
    if (xcode_info_util.GetXcodeVersionNumber() >= 1100 and os_version
            and version_util.GetVersionNumber(os_version) < 1220):
        key = _SIMCTL_ENV_VAR_PREFIX + 'DYLD_FALLBACK_LIBRARY_PATH'
        simctl_env_vars[key] = xcode_info_util.GetSwift5FallbackLibsDir()
    # We need to set the DEVELOPER_DIR to ensure xcrun works correctly
    developer_dir = os.environ.get('DEVELOPER_DIR')
    if developer_dir:
        simctl_env_vars['DEVELOPER_DIR'] = developer_dir

    command = [
        'xcrun', 'simctl', 'spawn', '-s', sim_id,
        xcode_info_util.GetXctestToolPath(ios_constants.SDK.IPHONESIMULATOR)
    ]
    if args:
        command += args
    if not tests_to_run:
        tests_to_run_str = 'All'
    else:
        tests_to_run_str = ','.join(tests_to_run)

    return_code = subprocess.Popen(
        command + ['-XCTest', tests_to_run_str, test_bundle_path],
        env=simctl_env_vars,
        stdout=sys.stdout,
        stderr=subprocess.STDOUT).wait()
    if return_code != 0:
        return runner_exit_codes.EXITCODE.FAILED
    return runner_exit_codes.EXITCODE.SUCCEEDED
Exemplo n.º 5
0
  def RunXcTest(self, device_id, built_products_dir, derived_data_dir,
                startup_timeout_sec):
    """Runs `xcodebuild test` with the dummy project.

    If app under test or test bundle are not in built_products_dir, will copy
    the file into built_products_dir.

    Args:
      device_id: string, id of the device.
      built_products_dir: path of the built products dir in this build session.
      derived_data_dir: path of the derived data dir in this build session.
      startup_timeout_sec: Seconds until the xcodebuild command is deemed stuck.

    Returns:
      A value of type runner_exit_codes.EXITCODE.

    Raises:
      IllegalArgumentError: when test type is not xctest.
    """
    if self._test_type != ios_constants.TestType.XCTEST:
      raise ios_errors.IllegalArgumentError(
          'Only xctest dummy project is supported to run `xcodebuild test`. '
          'The test type %s is not supported.' % self._test_type)
    self.GenerateDummyProject()
    # In Xcode 7.3+, the folder structure of app under test is changed.
    if xcode_info_util.GetXcodeVersionNumber() >= 730:
      app_under_test_plugin_path = os.path.join(self._app_under_test_dir,
                                                'PlugIns')
      if not os.path.exists(app_under_test_plugin_path):
        os.mkdir(app_under_test_plugin_path)
      test_bundle_under_plugin_path = os.path.join(
          app_under_test_plugin_path, os.path.basename(self._test_bundle_dir))
      if not os.path.exists(test_bundle_under_plugin_path):
        shutil.copytree(self._test_bundle_dir, test_bundle_under_plugin_path)
    self._PrepareBuildProductsDir(built_products_dir)

    logging.info('Running `xcodebuild test` with dummy project.\n'
                 'device_id= %s\n'
                 'built_product_dir = %s\nderived_data_path = %s\n',
                 device_id,
                 built_products_dir,
                 derived_data_dir)
    command = ['xcodebuild', 'test',
               'BUILT_PRODUCTS_DIR=' + built_products_dir,
               '-project', self._xcodeproj_dir_path,
               '-scheme', self._test_scheme,
               '-destination', 'id=' + device_id,
               '-derivedDataPath', derived_data_dir]
    app_bundle_id = bundle_util.GetBundleId(self._app_under_test_dir)
    exit_code, _ = xcodebuild_test_executor.XcodebuildTestExecutor(
        command,
        succeeded_signal=_SIGNAL_XCODEBUILD_TEST_SUCCEEDED,
        failed_signal=_SIGNAL_XCODEBUILD_TEST_FAILED,
        sdk=self._sdk,
        test_type=self._test_type,
        device_id=device_id,
        app_bundle_id=app_bundle_id,
        startup_timeout_sec=startup_timeout_sec).Execute(return_output=False)
    return exit_code
Exemplo n.º 6
0
def GetSupportedSimOsVersions(os_type=ios_constants.OS.IOS):
    """Gets the supported version of given simulator OS type.

  Args:
    os_type: shared.ios_constants.OS, OS type of simulator, such as iOS,
      watchOS, tvOS.

  Returns:
    a list of string, each item is an OS version number. E.g., ["10.1", "11.0"]
  """
    # Example output:
    # {
    # "runtimes" : [
    #   {
    #     "bundlePath" : "\/Applications\/Xcode10.app\/Contents\/Developer\
    #                     /Platforms\/iPhoneOS.platform\/Developer\/Library\
    #                     /CoreSimulator\/Profiles\/Runtimes\/iOS.simruntime",
    #     "availabilityError" : "",
    #     "buildversion" : "16A366",
    #     "availability" : "(available)",
    #     "isAvailable" : true,
    #     "identifier" : "com.apple.CoreSimulator.SimRuntime.iOS-12-0",
    #     "version" : "12.0",
    #     "name" : "iOS 12.0"
    #   }
    # }
    # See more examples in testdata/simctl_list_runtimes.json
    xcode_version_num = xcode_info_util.GetXcodeVersionNumber()
    sim_runtime_infos_json = json.loads(
        RunSimctlCommand(('xcrun', 'simctl', 'list', 'runtimes', '-j')))
    sim_versions = []
    for sim_runtime_info in sim_runtime_infos_json['runtimes']:
        # Normally, the json does not contain unavailable runtimes. To be safe,
        # also checks the 'availability' field.
        if 'availability' in sim_runtime_info and sim_runtime_info[
                'availability'].find('unavailable') >= 0:
            continue
        elif 'isAvailable' in sim_runtime_info and not sim_runtime_info[
                'isAvailable']:
            continue

        listed_os_type, listed_os_version = sim_runtime_info['name'].split(
            ' ', 1)
        if listed_os_type == os_type:
            if os_type == ios_constants.OS.IOS:
                ios_major_version, ios_minor_version = listed_os_version.split(
                    '.', 1)
                # Ingores the potential build version
                ios_minor_version = ios_minor_version[0]
                ios_version_num = int(ios_major_version) * 100 + int(
                    ios_minor_version) * 10
                # One Xcode version always maps to one max simulator's iOS version.
                # The rules is almost max_sim_ios_version <= xcode_version + 200.
                # E.g., Xcode 8.3.1/8.3.3 maps to iOS 10.3, Xcode 7.3.1 maps to iOS 9.3.
                if ios_version_num > xcode_version_num + 200:
                    continue
            sim_versions.append(listed_os_version)
    return sim_versions
Exemplo n.º 7
0
def QuitSimulatorApp():
    """Quits the Simulator.app."""
    if xcode_info_util.GetXcodeVersionNumber() >= 700:
        simulator_name = 'Simulator'
    else:
        simulator_name = 'iOS Simulator'
    subprocess.Popen(['killall', simulator_name],
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT)
Exemplo n.º 8
0
    def Run(self,
            device_id,
            sdk,
            derived_data_dir,
            startup_timeout_sec,
            destination_timeout_sec=None,
            os_version=None):
        """Runs the test with generated xctestrun file in the specific device.

    Args:
      device_id: ID of the device.
      sdk: shared.ios_constants.SDK, sdk of the device.
      derived_data_dir: path of derived data directory of this test session.
      startup_timeout_sec: seconds until the xcodebuild command is deemed stuck.
      destination_timeout_sec: Wait for the given seconds while searching for
          the destination device.
      os_version: os version of the device.

    Returns:
      A value of type runner_exit_codes.EXITCODE.
    """
        # When running tests on iOS 12.1 or earlier simulator under Xcode 11 or
        # later, it is required to add swift5 fallback libraries to environment
        # variable.
        # See https://github.com/bazelbuild/rules_apple/issues/684 for context.
        if (xcode_info_util.GetXcodeVersionNumber() >= 1100
                and sdk == ios_constants.SDK.IPHONESIMULATOR and os_version
                and version_util.GetVersionNumber(os_version) < 1220):
            new_env_var = {
                'DYLD_FALLBACK_LIBRARY_PATH':
                xcode_info_util.GetSwift5FallbackLibsDir()
            }
            self.SetTestEnvVars(new_env_var)
        logging.info('Running test-without-building with device %s', device_id)
        command = [
            'xcodebuild', 'test-without-building', '-xctestrun',
            self._xctestrun_file_path, '-destination',
            'id=%s' % device_id, '-derivedDataPath', derived_data_dir
        ]
        if destination_timeout_sec:
            command.extend(
                ['-destination-timeout',
                 str(destination_timeout_sec)])
        exit_code, _ = xcodebuild_test_executor.XcodebuildTestExecutor(
            command,
            succeeded_signal=_SIGNAL_TEST_WITHOUT_BUILDING_SUCCEEDED,
            failed_signal=_SIGNAL_TEST_WITHOUT_BUILDING_FAILED,
            sdk=sdk,
            test_type=self.test_type,
            device_id=device_id,
            app_bundle_id=self._aut_bundle_id,
            startup_timeout_sec=startup_timeout_sec).Execute(
                return_output=False)
        return exit_code
Exemplo n.º 9
0
    def RunTest(self, device_id, os_version=None):
        """Runs test on the target device with the given device_id.

    Args:
      device_id: string, id of the device.
      os_version: string, OS version of the device.

    Returns:
      A value of type runner_exit_codes.EXITCODE.

    Raises:
      XcodebuildTestError: when the XctestSession.Prepare has not been called.
    """
        if not self._prepared:
            raise ios_errors.XcodebuildTestError(
                'The session has not been prepared. Please call '
                'XctestSession.Prepare first.')

        if self._xctestrun_obj:
            result_bundle_path = os.path.join(self._output_dir,
                                              'test.xcresult')
            exit_code = self._xctestrun_obj.Run(
                device_id,
                self._sdk,
                self._output_dir,
                self._startup_timeout_sec,
                self._destination_timeout_sec,
                os_version=os_version,
                result_bundle_path=result_bundle_path)
            # The xcresult only contains raw data in Xcode 11 or later.
            if xcode_info_util.GetXcodeVersionNumber() >= 1100:
                expose_xcresult = os.path.join(self._output_dir,
                                               'ExposeXcresult')
                try:
                    xcresult_util.ExpoesXcresult(result_bundle_path,
                                                 expose_xcresult)
                    if not self._keep_xcresult_data:
                        shutil.rmtree(result_bundle_path)
                except subprocess.CalledProcessError as e:
                    logging.warning(e.output)
            return exit_code
        elif self._logic_test_bundle:
            return logic_test_util.RunLogicTestOnSim(device_id,
                                                     self._logic_test_bundle,
                                                     self._logic_test_env_vars,
                                                     self._logic_test_args,
                                                     self._logic_tests_to_run,
                                                     os_version=os_version)
        else:
            raise ios_errors.XcodebuildTestError('Unexpected runtime error.')
Exemplo n.º 10
0
    def RunTest(self, device_id, os_version=None):
        """Runs test on the target device with the given device_id.

    Args:
      device_id: string, id of the device.
      os_version: string, OS version of the device.

    Returns:
      A value of type runner_exit_codes.EXITCODE.

    Raises:
      XcodebuildTestError: when the XctestSession.Prepare has not been called.
    """
        if not self._prepared:
            raise ios_errors.XcodebuildTestError(
                'The session has not been prepared. Please call '
                'XctestSession.Prepare first.')

        if self._xctestrun_obj:
            exit_code = self._xctestrun_obj.Run(device_id,
                                                self._sdk,
                                                self._output_dir,
                                                self._startup_timeout_sec,
                                                self._destination_timeout_sec,
                                                os_version=os_version)
            # The xcresult only contains raw data in Xcode 11 or later.
            if xcode_info_util.GetXcodeVersionNumber() >= 1100:
                test_log_dir = '%s/Logs/Test' % self._output_dir
                xcresults = glob.glob('%s/*.xcresult' % test_log_dir)
                for xcresult in xcresults:
                    xcresult_util.ExposeDiagnosticsRef(xcresult, test_log_dir)
                    shutil.rmtree(xcresult)
            return exit_code
        elif self._logic_test_bundle:
            return logic_test_util.RunLogicTestOnSim(device_id,
                                                     self._logic_test_bundle,
                                                     self._logic_test_env_vars,
                                                     self._logic_test_args,
                                                     self._logic_tests_to_run,
                                                     os_version=os_version)
        else:
            raise ios_errors.XcodebuildTestError('Unexpected runtime error.')
Exemplo n.º 11
0
  def Prepare(self, app_under_test=None, test_bundle=None,
              xctestrun_file_path=None, test_type=None, signing_options=None):
    """Prepares the test session.

    If xctestrun_file is not provided, will use app under test and test bundle
    path to generate a new xctest file or dummy project.

    Args:
      app_under_test: string, the path of the application to be tested. It can
          be .ipa or .app.
      test_bundle: string, the path of the test bundle to be tested. It can
          be .ipa or .xctest.
      xctestrun_file_path: string, the path of the xctestrun file. It is the
          configure file to launch test in Xcode 8+.
      test_type: ios_constants.TestType. The type of test bundle.
      signing_options: dict, the signing app options. See
          ios_constants.SIGNING_OPTIONS_JSON_HELP for details.

    Raises:
      ios_errors.IllegalArgumentError:
          1) the app under test/test bundle does not exist;
          2) the app under test/test bundle's extension is invaild.
    """
    if not signing_options:
      signing_options = {}

    if self._work_dir:
      if not os.path.exists(self._work_dir):
        os.mkdir(self._work_dir)
      self._work_dir = os.path.abspath(self._work_dir)
      self._delete_work_dir = False
    else:
      self._work_dir = tempfile.mkdtemp()
      self._delete_work_dir = True

    if self._output_dir:
      if not os.path.exists(self._output_dir):
        os.mkdir(self._output_dir)
      self._delete_output_dir = False
    else:
      self._output_dir = tempfile.mkdtemp()
      self._delete_output_dir = True

    if xctestrun_file_path:
      xcode_version_num = xcode_info_util.GetXcodeVersionNumber()
      if xcode_version_num < 800:
        raise ios_errors.IllegalArgumentError(
            'The xctestrun file is only supported in Xcode 8+. But current '
            'Xcode version number is %s' % xcode_version_num)
      self._xctestrun_obj = xctestrun.XctestRun(
          xctestrun_file_path, test_type)
    else:
      if not test_bundle:
        raise ios_errors.IllegalArgumentError(
            'Without providing xctestrun file, test bundle is required.')
      app_under_test_dir, test_bundle_dir = _PrepareBundles(
          self._work_dir, app_under_test, test_bundle)
      test_type = _FinalizeTestType(
          test_bundle_dir, self._sdk, app_under_test_dir=app_under_test_dir,
          original_test_type=test_type)

      # xctestrun can only support in Xcode 8+.
      # Since xctestrun approach is more flexiable to local debug and is easy to
      # support tests_to_run feature. So in Xcode 8+, use xctestrun approach to
      # run XCTest and Logic Test.
      if (test_type in ios_constants.SUPPORTED_TEST_TYPES and
          test_type != ios_constants.TestType.LOGIC_TEST and
          xcode_info_util.GetXcodeVersionNumber() >= 800):
        xctestrun_factory = xctestrun.XctestRunFactory(
            app_under_test_dir, test_bundle_dir, self._sdk, test_type,
            signing_options, self._work_dir)
        self._xctestrun_obj = xctestrun_factory.GenerateXctestrun()
      elif test_type == ios_constants.TestType.XCUITEST:
        raise ios_errors.IllegalArgumentError(
            'Only supports running XCUITest under Xcode 8+. '
            'Current xcode version is %s' %
            xcode_info_util.GetXcodeVersionNumber())
      elif test_type == ios_constants.TestType.XCTEST:
        self._dummy_project_obj = dummy_project.DummyProject(
            app_under_test_dir,
            test_bundle_dir,
            self._sdk,
            ios_constants.TestType.XCTEST,
            self._work_dir,
            keychain_path=signing_options.get('keychain_path') or None)
        self._dummy_project_obj.GenerateDummyProject()
      elif test_type == ios_constants.TestType.LOGIC_TEST:
        self._logic_test_bundle = test_bundle_dir
      else:
        raise ios_errors.IllegalArgumentError(
            'The test type %s is not supported. Supported test types are %s'
            % (test_type, ios_constants.SUPPORTED_TEST_TYPES))
    self._prepared = True
Exemplo n.º 12
0
    def _GenerateTestRootForXctest(self):
        """Generates the test root for XCTest.

    The approach constructs xctestrun.plist from Xcode. Then copies app under
    test, test bundle and xctestrun.plist to test root directory.
    """
        app_under_test_plugins_dir = os.path.join(self._app_under_test_dir,
                                                  'PlugIns')
        if not os.path.exists(app_under_test_plugins_dir):
            os.mkdir(app_under_test_plugins_dir)
        new_test_bundle_path = os.path.join(
            app_under_test_plugins_dir,
            os.path.basename(self._test_bundle_dir))
        # The test bundle under PlugIns can not be symlink since it will cause
        # app installation error.
        if os.path.islink(self._test_bundle_dir):
            shutil.copytree(self._test_bundle_dir, new_test_bundle_path)
            self._test_bundle_dir = new_test_bundle_path
        elif new_test_bundle_path != self._test_bundle_dir:
            self._test_bundle_dir = _MoveAndReplaceFile(
                self._test_bundle_dir, app_under_test_plugins_dir)

        platform_path = xcode_info_util.GetSdkPlatformPath(self._sdk)
        app_under_test_frameworks_dir = os.path.join(self._app_under_test_dir,
                                                     'Frameworks')
        if not os.path.exists(app_under_test_frameworks_dir):
            os.mkdir(app_under_test_frameworks_dir)
        xctest_framework = os.path.join(app_under_test_frameworks_dir,
                                        'XCTest.framework')
        if not os.path.exists(xctest_framework):
            shutil.copytree(
                os.path.join(platform_path,
                             'Developer/Library/Frameworks/XCTest.framework'),
                xctest_framework)
        if xcode_info_util.GetXcodeVersionNumber() < 1000:
            insert_libs_framework = os.path.join(
                app_under_test_frameworks_dir, 'IDEBundleInjection.framework')
            if not os.path.exists(insert_libs_framework):
                shutil.copytree(
                    os.path.join(
                        platform_path, 'Developer/Library/PrivateFrameworks/'
                        'IDEBundleInjection.framework'), insert_libs_framework)
        else:
            insert_libs_framework = os.path.join(
                app_under_test_frameworks_dir, 'libXCTestBundleInject.dylib')
            if not os.path.exists(insert_libs_framework):
                shutil.copyfile(
                    os.path.join(
                        platform_path,
                        'Developer/usr/lib/libXCTestBundleInject.dylib'),
                    insert_libs_framework)

        if self._on_device:
            app_under_test_signing_identity = bundle_util.GetCodesignIdentity(
                self._app_under_test_dir)
            bundle_util.CodesignBundle(
                xctest_framework, identity=app_under_test_signing_identity)
            bundle_util.CodesignBundle(
                insert_libs_framework,
                identity=app_under_test_signing_identity)
            bundle_util.CodesignBundle(self._test_bundle_dir)
            bundle_util.CodesignBundle(self._app_under_test_dir)

        app_under_test_name = os.path.splitext(
            os.path.basename(self._app_under_test_dir))[0]
        platform_name = 'iPhoneOS' if self._on_device else 'iPhoneSimulator'
        if xcode_info_util.GetXcodeVersionNumber() < 1000:
            dyld_insert_libs = (
                '__PLATFORMS__/%s.platform/Developer/Library/'
                'PrivateFrameworks/IDEBundleInjection.framework/'
                'IDEBundleInjection' % platform_name)
        else:
            dyld_insert_libs = ('__PLATFORMS__/%s.platform/Developer/usr/lib/'
                                'libXCTestBundleInject.dylib' % platform_name)
        test_envs = {
            'XCInjectBundleInto':
            os.path.join('__TESTHOST__', app_under_test_name),
            'DYLD_FRAMEWORK_PATH':
            '__TESTROOT__:__PLATFORMS__/%s.platform/Developer/'
            'Library/Frameworks' % platform_name,
            'DYLD_INSERT_LIBRARIES':
            dyld_insert_libs,
            'DYLD_LIBRARY_PATH':
            '__TESTROOT__:__PLATFORMS__/%s.platform/Developer/Library/'
            'Frameworks' % platform_name,
        }
        self._xctestrun_dict = {
            'TestHostPath': self._app_under_test_dir,
            'TestBundlePath': self._test_bundle_dir,
            'IsAppHostedTestBundle': True,
            'TestingEnvironmentVariables': test_envs
        }
Exemplo n.º 13
0
    def _GenerateTestRootForXcuitest(self):
        """Generates the test root for XCUITest.

    The approach constructs xctestrun.plist and uitest runner app from Xcode.
    Then copies app under test, test bundle, xctestrun.plist and uitest
    runner app to test root directory.
    """
        platform_library_path = os.path.join(
            xcode_info_util.GetSdkPlatformPath(self._sdk), 'Developer/Library')
        uitest_runner_app = self._GetUitestRunnerAppFromXcode(
            platform_library_path)

        runner_app_frameworks_dir = os.path.join(uitest_runner_app,
                                                 'Frameworks')
        os.mkdir(runner_app_frameworks_dir)
        xctest_framework = os.path.join(runner_app_frameworks_dir,
                                        'XCTest.framework')
        shutil.copytree(
            os.path.join(platform_library_path, 'Frameworks/XCTest.framework'),
            xctest_framework)
        if xcode_info_util.GetXcodeVersionNumber() >= 900:
            xct_automation_framework = os.path.join(
                runner_app_frameworks_dir, 'XCTAutomationSupport.framework')
            shutil.copytree(
                os.path.join(
                    platform_library_path,
                    'PrivateFrameworks/XCTAutomationSupport.framework'),
                xct_automation_framework)

        self._PrepareUitestInRunerApp(uitest_runner_app)

        if self._on_device:
            runner_app_embedded_provision = os.path.join(
                uitest_runner_app, 'embedded.mobileprovision')
            use_customized_provision = False
            if self._signing_options:
                customized_runner_app_provision = self._signing_options.get(
                    'xctrunner_app_provisioning_profile')
                if customized_runner_app_provision:
                    shutil.copyfile(customized_runner_app_provision,
                                    runner_app_embedded_provision)
                    use_customized_provision = True
                if self._signing_options.get(
                        'xctrunner_app_enable_ui_file_sharing'):
                    try:
                        # Don't resign the uitest runner app here since it will be resigned
                        # with passing entitlements and identity later.
                        bundle_util.EnableUIFileSharing(uitest_runner_app,
                                                        resigning=False)
                    except ios_errors.BundleError as e:
                        logging.warning(str(e))

            # If customized runner app provision is not provided, runner app will
            # use app under test's embedded provision as embedded provision.
            if not use_customized_provision:
                app_under_test_embedded_provision = os.path.join(
                    self._app_under_test_dir, 'embedded.mobileprovision')
                shutil.copyfile(app_under_test_embedded_provision,
                                runner_app_embedded_provision)

            test_bundle_team_id = bundle_util.GetDevelopmentTeam(
                self._test_bundle_dir)
            full_test_bundle_id = '%s.%s' % (test_bundle_team_id,
                                             bundle_util.GetBundleId(
                                                 self._test_bundle_dir))
            entitlements_dict = {
                'application-identifier': full_test_bundle_id,
                'com.apple.developer.team-identifier': test_bundle_team_id,
                'get-task-allow': True,
                'keychain-access-groups': [full_test_bundle_id],
            }
            entitlements_plist_path = os.path.join(uitest_runner_app,
                                                   'RunnerEntitlements.plist')
            plist_util.Plist(entitlements_plist_path).SetPlistField(
                None, entitlements_dict)

            test_bundle_signing_identity = bundle_util.GetCodesignIdentity(
                self._test_bundle_dir)
            bundle_util.CodesignBundle(xctest_framework,
                                       identity=test_bundle_signing_identity)
            if xcode_info_util.GetXcodeVersionNumber() >= 900:
                bundle_util.CodesignBundle(
                    xct_automation_framework,
                    identity=test_bundle_signing_identity)
            bundle_util.CodesignBundle(
                uitest_runner_app,
                entitlements_plist_path=entitlements_plist_path,
                identity=test_bundle_signing_identity)

            bundle_util.CodesignBundle(self._test_bundle_dir)
            bundle_util.CodesignBundle(self._app_under_test_dir)

        platform_name = 'iPhoneOS' if self._on_device else 'iPhoneSimulator'
        test_envs = {
            'DYLD_FRAMEWORK_PATH':
            '__TESTROOT__:__PLATFORMS__/%s.platform/Developer/'
            'Library/Frameworks' % platform_name,
            'DYLD_LIBRARY_PATH':
            '__TESTROOT__:__PLATFORMS__/%s.platform/Developer/'
            'Library/Frameworks' % platform_name
        }
        self._xctestrun_dict = {
            'IsUITestBundle': True,
            'SystemAttachmentLifetime': 'keepNever',
            'TestBundlePath': self._test_bundle_dir,
            'TestHostPath': uitest_runner_app,
            'UITargetAppPath': self._app_under_test_dir,
            'UserAttachmentLifetime': 'keepNever',
            'TestingEnvironmentVariables': test_envs
        }
Exemplo n.º 14
0
    def _GenerateTestRootForXctest(self):
        """Generates the test root for XCTest.

    The approach constructs xctestrun.plist from Xcode. Then copies app under
    test, test bundle and xctestrun.plist to test root directory.
    """
        app_under_test_plugins_dir = os.path.join(self._app_under_test_dir,
                                                  'PlugIns')
        if not os.path.exists(app_under_test_plugins_dir):
            os.mkdir(app_under_test_plugins_dir)
        new_test_bundle_path = os.path.join(
            app_under_test_plugins_dir,
            os.path.basename(self._test_bundle_dir))
        # The test bundle under PlugIns can not be symlink since it will cause
        # app installation error.
        if os.path.islink(self._test_bundle_dir):
            shutil.copytree(self._test_bundle_dir, new_test_bundle_path)
            self._test_bundle_dir = new_test_bundle_path
        elif new_test_bundle_path != self._test_bundle_dir:
            self._test_bundle_dir = _MoveAndReplaceFile(
                self._test_bundle_dir, app_under_test_plugins_dir)

        if self._on_device:
            platform_path = xcode_info_util.GetSdkPlatformPath(self._sdk)
            app_under_test_frameworks_dir = os.path.join(
                self._app_under_test_dir, 'Frameworks')
            if not os.path.exists(app_under_test_frameworks_dir):
                os.mkdir(app_under_test_frameworks_dir)
            app_under_test_signing_identity = bundle_util.GetCodesignIdentity(
                self._app_under_test_dir)
            _CopyAndSignFramework(
                os.path.join(platform_path,
                             'Developer/Library/Frameworks/XCTest.framework'),
                app_under_test_frameworks_dir, app_under_test_signing_identity)
            xcode_version_num = xcode_info_util.GetXcodeVersionNumber()
            if xcode_version_num < 1000:
                bundle_injection_lib = os.path.join(
                    platform_path, 'Developer/Library/PrivateFrameworks/'
                    'IDEBundleInjection.framework')
                _CopyAndSignFramework(bundle_injection_lib,
                                      app_under_test_frameworks_dir,
                                      app_under_test_signing_identity)
            else:
                bundle_injection_lib = os.path.join(
                    platform_path,
                    'Developer/usr/lib/libXCTestBundleInject.dylib')
                _CopyAndSignLibFile(bundle_injection_lib,
                                    app_under_test_frameworks_dir,
                                    app_under_test_signing_identity)
            if xcode_version_num >= 1100:
                _CopyAndSignFramework(
                    os.path.join(
                        platform_path, 'Developer/Library/PrivateFrameworks/'
                        'XCTAutomationSupport.framework'),
                    app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
                _CopyAndSignLibFile(
                    os.path.join(platform_path,
                                 _LIB_XCTEST_SWIFT_RELATIVE_PATH),
                    app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
            bundle_util.CodesignBundle(self._test_bundle_dir)
            bundle_util.CodesignBundle(self._app_under_test_dir)

        app_under_test_name = os.path.splitext(
            os.path.basename(self._app_under_test_dir))[0]
        platform_name = 'iPhoneOS' if self._on_device else 'iPhoneSimulator'
        developer_path = '__PLATFORMS__/%s.platform/Developer' % platform_name
        if xcode_info_util.GetXcodeVersionNumber() < 1000:
            dyld_insert_libs = (
                '%s/Library/PrivateFrameworks/'
                'IDEBundleInjection.framework/IDEBundleInjection' %
                developer_path)
        else:
            dyld_insert_libs = ('%s/usr/lib/libXCTestBundleInject.dylib' %
                                developer_path)
        test_envs = {
            'XCInjectBundleInto':
            os.path.join('__TESTHOST__', app_under_test_name),
            'DYLD_FRAMEWORK_PATH':
            '__TESTROOT__:{developer}/Library/Frameworks:'
            '{developer}/Library/PrivateFrameworks'.format(
                developer=developer_path),
            'DYLD_INSERT_LIBRARIES':
            dyld_insert_libs,
            'DYLD_LIBRARY_PATH':
            '__TESTROOT__:%s/usr/lib:' % developer_path
        }

        # Fixes failures for test targets that depend on Swift libraries when running with Xcode 11
        # on pre-iOS 12.2 simulators.
        # Example failure message this resolves: "The bundle couldn’t be loaded because it is damaged
        # or missing necessary resources."
        swift5FallbackLibsDir = xcode_info_util.GetSwift5FallbackLibsDir()
        if swift5FallbackLibsDir:
            test_envs["DYLD_FALLBACK_LIBRARY_PATH"] = swift5FallbackLibsDir

        self._xctestrun_dict = {
            'TestHostPath': self._app_under_test_dir,
            'TestBundlePath': self._test_bundle_dir,
            'IsAppHostedTestBundle': True,
            'TestingEnvironmentVariables': test_envs
        }
Exemplo n.º 15
0
    def _GenerateTestRootForXcuitest(self):
        """Generates the test root for XCUITest.

    The approach constructs xctestrun.plist and uitest runner app from Xcode.
    Then copies app under test, test bundle, xctestrun.plist and uitest
    runner app to test root directory.
    """
        platform_path = xcode_info_util.GetSdkPlatformPath(self._sdk)
        platform_library_path = os.path.join(platform_path,
                                             'Developer/Library')
        uitest_runner_app = self._GetUitestRunnerAppFromXcode(
            platform_library_path)
        self._PrepareUitestInRunerApp(uitest_runner_app)

        if self._on_device:
            runner_app_embedded_provision = os.path.join(
                uitest_runner_app, 'embedded.mobileprovision')
            use_customized_provision = False
            if self._signing_options:
                customized_runner_app_provision = self._signing_options.get(
                    'xctrunner_app_provisioning_profile')
                if customized_runner_app_provision:
                    shutil.copyfile(customized_runner_app_provision,
                                    runner_app_embedded_provision)
                    use_customized_provision = True
                if self._signing_options.get(
                        'xctrunner_app_enable_ui_file_sharing'):
                    try:
                        # Don't resign the uitest runner app here since it will be resigned
                        # with passing entitlements and identity later.
                        bundle_util.EnableUIFileSharing(uitest_runner_app,
                                                        resigning=False)
                    except ios_errors.BundleError as e:
                        logging.warning(str(e))

            # If customized runner app provision is not provided, runner app will
            # use app under test's embedded provision as embedded provision.
            if not use_customized_provision:
                app_under_test_embedded_provision = os.path.join(
                    self._app_under_test_dir, 'embedded.mobileprovision')
                shutil.copyfile(app_under_test_embedded_provision,
                                runner_app_embedded_provision)

            test_bundle_team_id = bundle_util.GetDevelopmentTeam(
                self._test_bundle_dir)
            full_test_bundle_id = '%s.%s' % (test_bundle_team_id,
                                             bundle_util.GetBundleId(
                                                 self._test_bundle_dir))
            entitlements_dict = {
                'application-identifier': full_test_bundle_id,
                'com.apple.developer.team-identifier': test_bundle_team_id,
                'get-task-allow': True,
                'keychain-access-groups': [full_test_bundle_id],
            }
            entitlements_plist_path = os.path.join(uitest_runner_app,
                                                   'RunnerEntitlements.plist')
            plist_util.Plist(entitlements_plist_path).SetPlistField(
                None, entitlements_dict)

            test_bundle_signing_identity = bundle_util.GetCodesignIdentity(
                self._test_bundle_dir)

            runner_app_frameworks_dir = os.path.join(uitest_runner_app,
                                                     'Frameworks')
            os.mkdir(runner_app_frameworks_dir)
            _CopyAndSignFramework(
                os.path.join(platform_library_path,
                             'Frameworks/XCTest.framework'),
                runner_app_frameworks_dir, test_bundle_signing_identity)
            xcode_version_num = xcode_info_util.GetXcodeVersionNumber()
            if xcode_version_num >= 900:
                _CopyAndSignFramework(
                    os.path.join(
                        platform_library_path,
                        'PrivateFrameworks/XCTAutomationSupport.framework'),
                    runner_app_frameworks_dir, test_bundle_signing_identity)
            if xcode_version_num >= 1100:
                _CopyAndSignLibFile(
                    os.path.join(platform_path,
                                 _LIB_XCTEST_SWIFT_RELATIVE_PATH),
                    runner_app_frameworks_dir, test_bundle_signing_identity)
            bundle_util.CodesignBundle(
                uitest_runner_app,
                entitlements_plist_path=entitlements_plist_path,
                identity=test_bundle_signing_identity)

            bundle_util.CodesignBundle(self._test_bundle_dir)
            bundle_util.CodesignBundle(self._app_under_test_dir)

        platform_name = 'iPhoneOS' if self._on_device else 'iPhoneSimulator'
        developer_path = '__PLATFORMS__/%s.platform/Developer' % platform_name
        test_envs = {
            'DYLD_FRAMEWORK_PATH':
            '__TESTROOT__:{developer}/Library/Frameworks:'
            '{developer}/Library/PrivateFrameworks'.format(
                developer=developer_path),
            'DYLD_LIBRARY_PATH':
            '__TESTROOT__:%s/usr/lib' % developer_path
        }

        # Fixes failures for UI test targets that depend on Swift libraries when running with Xcode 11
        # on pre-iOS 12.2 simulators.
        # Example failure message this resolves: "The bundle couldn’t be loaded because it is damaged
        # or missing necessary resources."
        swift5FallbackLibsDir = xcode_info_util.GetSwift5FallbackLibsDir()
        if swift5FallbackLibsDir:
            test_envs["DYLD_FALLBACK_LIBRARY_PATH"] = swift5FallbackLibsDir

        self._xctestrun_dict = {
            'IsUITestBundle':
            True,
            'SystemAttachmentLifetime':
            'keepAlways',
            'TestBundlePath':
            self._test_bundle_dir,
            'TestHostPath':
            uitest_runner_app,
            'UITargetAppPath':
            self._app_under_test_dir,
            'UserAttachmentLifetime':
            'keepAlways',
            'TestingEnvironmentVariables':
            test_envs,
            'DependentProductPaths':
            [self._app_under_test_dir, self._test_bundle_dir],
        }
Exemplo n.º 16
0
    def _RunSimulatorTest(args):
        """The function of running test with new simulator."""
        with xctest_session.XctestSession(
                sdk=ios_constants.SDK.IPHONESIMULATOR,
                work_dir=args.work_dir,
                output_dir=args.output_dir) as session:
            session.Prepare(app_under_test=args.app_under_test_path,
                            test_bundle=args.test_bundle_path,
                            xctestrun_file_path=args.xctestrun,
                            test_type=args.test_type,
                            signing_options=_GetJson(
                                args.signing_options_json_path))
            session.SetLaunchOptions(_GetJson(args.launch_options_json_path))

            # In prior of Xcode 9, `xcodebuild test` will launch the Simulator.app
            # process. If there is Simulator.app before running test, it will cause
            # error later.
            if xcode_info_util.GetXcodeVersionNumber() < 900:
                simulator_util.QuitSimulatorApp()
            max_attempts = 3
            reboot_sim = False
            for i in range(max_attempts):
                if not reboot_sim:
                    simulator_id, _, _, _ = simulator_util.CreateNewSimulator(
                        device_type=args.device_type,
                        os_version=args.os_version,
                        name=args.new_simulator_name)
                reboot_sim = False

                try:
                    # Don't use command "{Xcode_developer_dir}Applications/ \
                    # Simulator.app/Contents/MacOS/Simulator" to launch the Simulator.app.
                    # 1) `xcodebuild test` will handle the launch Simulator.
                    # 2) If there are two Simulator.app processes launched by command line
                    # and `xcodebuild test` starts to run on one of Simulator, the another
                    # Simulator.app will popup 'Unable to boot device in current state: \
                    # Booted' dialog and may cause potential error.
                    exit_code = session.RunTest(simulator_id)
                    if i < max_attempts - 1:
                        if exit_code == runner_exit_codes.EXITCODE.NEED_RECREATE_SIM:
                            logging.warning(
                                'Will create a new simulator to retry running test.'
                            )
                            continue
                        if exit_code == runner_exit_codes.EXITCODE.NEED_REBOOT_DEVICE:
                            reboot_sim = True
                            logging.warning(
                                'Will reboot the simulator to retry running test.'
                            )
                            continue
                    return exit_code
                finally:
                    # 1. In prior of Xcode 9, `xcodebuild test` will launch the
                    # Simulator.app process. Quit the Simulator.app to avoid side effect.
                    # 2. Quit Simulator.app can also shutdown the simulator. To make sure
                    # the Simulator state to be SHUTDOWN, still call shutdown command
                    # later.
                    if xcode_info_util.GetXcodeVersionNumber() < 900:
                        simulator_util.QuitSimulatorApp()
                    simulator_obj = simulator_util.Simulator(simulator_id)
                    if reboot_sim:
                        simulator_obj.Shutdown()
                    else:
                        # In Xcode 9+, simctl can delete the Booted simulator.
                        # In prior of Xcode 9, we have to shutdown the simulator first
                        # before deleting it.
                        if xcode_info_util.GetXcodeVersionNumber() < 900:
                            simulator_obj.Shutdown()
                        simulator_obj.Delete()
Exemplo n.º 17
0
    def _GenerateTestRootForXctest(self):
        """Generates the test root for XCTest.

    The approach constructs xctestrun.plist from Xcode. Then copies app under
    test, test bundle and xctestrun.plist to test root directory.
    """
        app_under_test_plugins_dir = os.path.join(self._app_under_test_dir,
                                                  'PlugIns')
        if not os.path.exists(app_under_test_plugins_dir):
            os.mkdir(app_under_test_plugins_dir)
        new_test_bundle_path = os.path.join(
            app_under_test_plugins_dir,
            os.path.basename(self._test_bundle_dir))
        # The test bundle under PlugIns can not be symlink since it will cause
        # app installation error.
        if os.path.islink(self._test_bundle_dir):
            shutil.copytree(self._test_bundle_dir, new_test_bundle_path)
            self._test_bundle_dir = new_test_bundle_path
        elif new_test_bundle_path != self._test_bundle_dir:
            self._test_bundle_dir = _MoveAndReplaceFile(
                self._test_bundle_dir, app_under_test_plugins_dir)

        if self._on_device:
            platform_path = xcode_info_util.GetSdkPlatformPath(self._sdk)
            app_under_test_frameworks_dir = os.path.join(
                self._app_under_test_dir, 'Frameworks')
            if not os.path.exists(app_under_test_frameworks_dir):
                os.mkdir(app_under_test_frameworks_dir)
            app_under_test_signing_identity = bundle_util.GetCodesignIdentity(
                self._app_under_test_dir)
            _CopyAndSignFramework(
                os.path.join(platform_path,
                             'Developer/Library/Frameworks/XCTest.framework'),
                app_under_test_frameworks_dir, app_under_test_signing_identity)
            bundle_injection_lib = os.path.join(
                platform_path, 'Developer/usr/lib/libXCTestBundleInject.dylib')
            _CopyAndSignLibFile(bundle_injection_lib,
                                app_under_test_frameworks_dir,
                                app_under_test_signing_identity)
            if xcode_info_util.GetXcodeVersionNumber() >= 1100:
                _CopyAndSignFramework(
                    os.path.join(
                        platform_path, 'Developer/Library/PrivateFrameworks/'
                        'XCTAutomationSupport.framework'),
                    app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
                _CopyAndSignLibFile(
                    os.path.join(platform_path,
                                 _LIB_XCTEST_SWIFT_RELATIVE_PATH),
                    app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
            if xcode_info_util.GetXcodeVersionNumber() >= 1300:
                _CopyAndSignFramework(
                    os.path.join(
                        platform_path, 'Developer/Library/PrivateFrameworks/'
                        'XCUIAutomation.framework'),
                    app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
                _CopyAndSignFramework(
                    os.path.join(
                        platform_path, 'Developer/Library/PrivateFrameworks/'
                        'XCTestCore.framework'), app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
                _CopyAndSignFramework(
                    os.path.join(
                        platform_path, 'Developer/Library/PrivateFrameworks/'
                        'XCUnit.framework'), app_under_test_frameworks_dir,
                    app_under_test_signing_identity)
            bundle_util.CodesignBundle(self._test_bundle_dir)
            bundle_util.CodesignBundle(self._app_under_test_dir)

        app_under_test_name = os.path.splitext(
            os.path.basename(self._app_under_test_dir))[0]
        platform_name = 'iPhoneOS' if self._on_device else 'iPhoneSimulator'
        developer_path = '__PLATFORMS__/%s.platform/Developer' % platform_name

        if self._on_device:
            dyld_insert_libs = '__TESTHOST__/Frameworks/libXCTestBundleInject.dylib'
        else:
            dyld_insert_libs = ('%s/usr/lib/libXCTestBundleInject.dylib' %
                                developer_path)
        test_envs = {
            'XCInjectBundleInto':
            os.path.join('__TESTHOST__', app_under_test_name),
            'DYLD_FRAMEWORK_PATH':
            '__TESTROOT__:{developer}/Library/Frameworks:'
            '{developer}/Library/PrivateFrameworks'.format(
                developer=developer_path),
            'DYLD_INSERT_LIBRARIES':
            dyld_insert_libs,
            'DYLD_LIBRARY_PATH':
            '__TESTROOT__:%s/usr/lib:' % developer_path
        }
        self._xctestrun_dict = {
            'ProductModuleName': self._test_name,
            'TestHostPath': self._app_under_test_dir,
            'TestBundlePath': self._test_bundle_dir,
            'IsAppHostedTestBundle': True,
            'TestingEnvironmentVariables': test_envs
        }