Пример #1
0
    def _DecodeProvisioningProfile(self):
        """Decodes the provisioning profile. It only works on MacOS."""
        if self._decode_provisioning_profile_plist:
            return

        if not self._work_dir:
            self._work_dir = tempfile.mkdtemp()
        decode_provisioning_profile = os.path.join(
            self._work_dir, 'decode_provision_%s.plist' % str(uuid.uuid1()))
        command = [
            'security', 'cms', '-D', '-i', self._provisioning_profile_path,
            '-o', decode_provisioning_profile
        ]
        if self._keychain_path:
            command.extend(['-k', self._keychain_path])
        process = subprocess.Popen(command,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.STDOUT)
        output = process.communicate()[0].decode('utf-8')
        if process.poll() != 0:
            raise ios_errors.ProvisioningProfileError(output)
        if not os.path.exists(decode_provisioning_profile):
            raise ios_errors.ProvisioningProfileError(
                'Failed to decode the provisioning profile.')

        self._decode_provisioning_profile_plist = plist_util.Plist(
            decode_provisioning_profile)
Пример #2
0
    def _GetUitestRunnerAppFromXcode(self, platform_library_path):
        """Gets the test runner app for uitest from Xcode directory.

    The test runner app will be copied to TEST_ROOT and renamed to
    {test-bundle-name}-Runner.app.

    Args:
      platform_library_path: string, the library path of the sdk platform.
    Returns:
      A string, the path of uitest runner app.
    """
        test_bundle_name = os.path.splitext(
            os.path.basename(self._test_bundle_dir))[0]
        xctrunner_app = os.path.join(platform_library_path,
                                     'Xcode/Agents/XCTRunner.app')
        uitest_runner_app_name = '%s-Runner' % test_bundle_name
        uitest_runner_app = os.path.join(self._test_root_dir,
                                         uitest_runner_app_name + '.app')
        shutil.copytree(xctrunner_app, uitest_runner_app)
        shutil.move(os.path.join(uitest_runner_app, 'XCTRunner'),
                    os.path.join(uitest_runner_app, uitest_runner_app_name))

        runner_app_info_plist_path = os.path.join(uitest_runner_app,
                                                  'Info.plist')
        info_plist = plist_util.Plist(runner_app_info_plist_path)
        info_plist.SetPlistField('CFBundleName', uitest_runner_app_name)
        info_plist.SetPlistField('CFBundleExecutable', uitest_runner_app_name)
        info_plist.SetPlistField('CFBundleIdentifier',
                                 'com.apple.test.' + uitest_runner_app_name)

        return uitest_runner_app
Пример #3
0
def ParseTestSummaries(test_summaries_path, attachments_dir_path,
                       delete_uitest_auto_screenshots):
    """Parse the TestSummaries.plist and structure the attachments' files.

  Only the screenshots file from failure test methods and .crash files will be
  stored. Other files will be removed.

  Args:
    test_summaries_path: string, the path of TestSummaries.plist file.
    attachments_dir_path: string, the path of Attachments directory.
    delete_uitest_auto_screenshots: bool, whether deletes the auto screenshots.
  """
    test_summaries_plist = plist_util.Plist(test_summaries_path)
    tests_obj = test_summaries_plist.GetPlistField(
        'TestableSummaries:0:Tests:0')
    # Store the required screenshots and crash files under temp directory first.
    # Then use the temp directory to replace the original Attachments directory.
    # If delete_uitest_auto_screenshots is true, only move crash files to
    # temp directory and the left screenshots will be deleted.
    temp_dir = tempfile.mkdtemp(dir=os.path.dirname(attachments_dir_path))
    if not delete_uitest_auto_screenshots:
        _ParseTestObject(tests_obj, attachments_dir_path, temp_dir)
    for crash_file in glob.glob('%s/*.crash' % attachments_dir_path):
        shutil.move(crash_file, temp_dir)
    shutil.rmtree(attachments_dir_path)
    shutil.move(temp_dir, attachments_dir_path)
Пример #4
0
def _ParseTestObject(test_obj, attachments_dir_path, parent_test_obj_dir_path):
    """Parse the test method object and structure its attachment files."""
    test_obj_dir_path = os.path.join(
        parent_test_obj_dir_path,
        test_obj['TestIdentifier'].replace('.', '_').replace('/', '_'))
    if 'Subtests' in test_obj:
        # If the test suite only has one sub test, don't create extra folder which
        # causes extra directory hierarchy.
        if len(test_obj['Subtests']) > 1:
            if not os.path.exists(test_obj_dir_path):
                os.mkdir(test_obj_dir_path)
        else:
            test_obj_dir_path = parent_test_obj_dir_path
        for sub_test_obj in test_obj['Subtests']:
            _ParseTestObject(sub_test_obj, attachments_dir_path,
                             test_obj_dir_path)
        return
    # Only parse the failure test methods. The succeed test method's attachment
    # files will be removed later.
    if test_obj['TestStatus'] == 'Success':
        return
    if not os.path.exists(test_obj_dir_path):
        os.mkdir(test_obj_dir_path)
    test_result_plist_path = os.path.join(test_obj_dir_path,
                                          'TestMethodResult.plist')
    plist_util.Plist(test_result_plist_path).SetPlistField('', test_obj)
    if 'ActivitySummaries' in test_obj:
        for test_activity_obj in test_obj['ActivitySummaries']:
            _ExploreTestActivity(test_activity_obj, attachments_dir_path,
                                 test_obj_dir_path)
Пример #5
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:
            xcode_version = xcode_info_util.GetXcodeVersionNumber()
            if xcode_version >= 900:
                platform_path = xcode_info_util.GetSdkPlatformPath(
                    ios_constants.SDK.IPHONEOS)
            else:
                platform_path = xcode_info_util.GetSdkPlatformPath(
                    ios_constants.SDK.IPHONESIMULATOR)
            if xcode_version >= 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
Пример #6
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))
Пример #7
0
    def __init__(self,
                 xctestrun_file_path,
                 test_type=None,
                 aut_bundle_id=None):
        """Initializes the XctestRun object.

    If arg work_dir is provided, the original app under test file and test
    bundle file will be moved to work_dir/TEST_ROOT.

    Args:
      xctestrun_file_path: string, path of the xctest run file.
      test_type: string, test type of the test bundle. See supported test types
          in module xctestrunner.shared.ios_constants.
      aut_bundle_id: string, the bundle id of app under test.

    Raises:
      IllegalArgumentError: when the sdk or test type is not supported.
    """
        self._xctestrun_file_path = xctestrun_file_path
        self._xctestrun_file_plist_obj = plist_util.Plist(xctestrun_file_path)
        # xctestrun file always has only key at root dict.
        self._root_key = self._xctestrun_file_plist_obj.GetPlistField(
            None).keys()[0]
        self._test_type = test_type
        self._aut_bundle_id = aut_bundle_id
Пример #8
0
 def _SetIosDeploymentTarget(self):
   """Sets the iOS deployment target in dummy project's pbxproj."""
   pbxproj_plist_obj = plist_util.Plist(self.pbxproj_file_path)
   pbxproj_plist_obj.SetPlistField(
       'objects:TestProjectBuildConfig:buildSettings:'
       'IPHONEOS_DEPLOYMENT_TARGET',
       bundle_util.GetMinimumOSVersion(self._app_under_test_dir))
Пример #9
0
  def _SetPbxprojForXctest(self):
    """Sets the dummy project's pbxproj for xctest."""
    pbxproj_plist_obj = plist_util.Plist(self.pbxproj_file_path)
    pbxproj_objects = pbxproj_plist_obj.GetPlistField('objects')

    # Sets the build setting for app under test and unit test bundle signing.
    # 1) If run with iphonesimulator, don't need to set any fields in build
    # setting. xcodebuild will sign bundles with identity '-' and no
    # provisioning profile by default.
    # 2) If runs with iphoneos and the app under test's embedded provisioning
    # profile is 'iOS Team Provisioning Profile: *', set build setting for using
    # Xcode managed provisioning profile to sign bundles.
    # 3) If runs with iphoneos and the app under test's embedded provisioning
    # profile is specific, set build setting with using app under test's
    # embedded provisioning profile.
    if self._sdk == ios_constants.SDK.IPHONEOS:
      aut_build_setting = pbxproj_objects[
          'AppUnderTestBuildConfig']['buildSettings']
      test_build_setting = pbxproj_objects[
          'XCTestBundleBuildConfig']['buildSettings']
      aut_build_setting['CODE_SIGNING_REQUIRED'] = 'YES'
      aut_build_setting['PRODUCT_BUNDLE_IDENTIFIER'] = bundle_util.GetBundleId(
          self._app_under_test_dir)
      embedded_provision = provisioning_profile.ProvisiongProfile(
          os.path.join(self._app_under_test_dir, 'embedded.mobileprovision'),
          self._work_dir,
          keychain_path=self._keychain_path)
      embedded_provision.Install()
      # Case 2)
      if embedded_provision.name.startswith('iOS Team Provisioning Profile: '):
        aut_build_setting['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
        test_build_setting['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
        app_under_test_dev_team = bundle_util.GetDevelopmentTeam(
            self._app_under_test_dir)
        aut_build_setting['DEVELOPMENT_TEAM'] = app_under_test_dev_team
        test_build_setting['DEVELOPMENT_TEAM'] = app_under_test_dev_team
      else:
        # Case 3)
        app_under_test_sign_identity = bundle_util.GetCodesignIdentity(
            self._app_under_test_dir)
        aut_build_setting['CODE_SIGN_IDENTITY'] = app_under_test_sign_identity
        test_build_setting['CODE_SIGN_IDENTITY'] = app_under_test_sign_identity
        (aut_build_setting[
            'PROVISIONING_PROFILE_SPECIFIER']) = embedded_provision.name

    # Sets the app under test and test bundle.
    test_project_build_setting = pbxproj_objects[
        'TestProjectBuildConfig']['buildSettings']
    app_under_test_name = os.path.splitext(
        os.path.basename(self._app_under_test_dir))[0]
    pbxproj_objects['AppUnderTestTarget']['name'] = app_under_test_name
    pbxproj_objects['AppUnderTestTarget']['productName'] = app_under_test_name
    test_project_build_setting['APP_UNDER_TEST_NAME'] = app_under_test_name
    test_bundle_name = os.path.splitext(
        os.path.basename(self._test_bundle_dir))[0]
    pbxproj_objects['XCTestBundleTarget']['name'] = test_bundle_name
    pbxproj_objects['XCTestBundleTarget']['productName'] = test_bundle_name
    test_project_build_setting['XCTEST_BUNDLE_NAME'] = test_bundle_name

    pbxproj_plist_obj.SetPlistField('objects', pbxproj_objects)
Пример #10
0
  def _SetPbxprojForXcuitest(self):
    """Sets the dummy project's pbxproj for xcuitest."""
    pbxproj_plist_obj = plist_util.Plist(self.pbxproj_file_path)
    pbxproj_objects = pbxproj_plist_obj.GetPlistField('objects')

    # Sets the build setting of test bundle for generated XCTRunner.app signing.
    # 1) If run with iphonesimulator, don't need to set any fields in build
    # setting. xcodebuild will sign the XCTRunner.app with identity '-' and no
    # provisioning profile by default.
    # 2) If runs with iphoneos and the app under test's embedded provisioning
    # profile is 'iOS Team Provisioning Profile: *', set build setting for using
    # Xcode managed provisioning profile to sign the XCTRunner.app.
    # 3) If runs with iphoneos and the app under test's embedded provisioning
    # profile is specific, set build setting for using app under test's
    # embedded provisioning profile to sign the XCTRunner.app. If the
    # provisioning profile is not installed in the Mac machine, also installs
    # it.
    # 4) The test bundle's provisioning profile can be overwrited by method
    # SetTestBundleProvisioningProfile.
    if self._sdk == ios_constants.SDK.IPHONEOS:
      build_setting = pbxproj_objects[
          'XCUITestBundleBuildConfig']['buildSettings']
      build_setting['PRODUCT_BUNDLE_IDENTIFIER'] = bundle_util.GetBundleId(
          self._test_bundle_dir)
      build_setting['DEVELOPMENT_TEAM'] = bundle_util.GetDevelopmentTeam(
          self._test_bundle_dir)
      embedded_provision = provisioning_profile.ProvisiongProfile(
          os.path.join(self._app_under_test_dir, 'embedded.mobileprovision'),
          self._work_dir,
          keychain_path=self._keychain_path)
      embedded_provision.Install()
      # Case 2)
      if embedded_provision.name.startswith('iOS Team Provisioning Profile: '):
        build_setting['CODE_SIGN_IDENTITY'] = 'iPhone Developer'
      else:
        # Case 3)
        build_setting['CODE_SIGN_IDENTITY'] = bundle_util.GetCodesignIdentity(
            self._app_under_test_dir)
        (build_setting[
            'PROVISIONING_PROFILE_SPECIFIER']) = embedded_provision.name

    # Sets the app under test and test bundle.
    test_project_build_setting = pbxproj_objects[
        'TestProjectBuildConfig']['buildSettings']
    app_under_test_name = os.path.splitext(
        os.path.basename(self._app_under_test_dir))[0]
    pbxproj_objects['AppUnderTestTarget']['name'] = app_under_test_name
    pbxproj_objects['AppUnderTestTarget']['productName'] = app_under_test_name
    test_project_build_setting['APP_UNDER_TEST_NAME'] = app_under_test_name
    test_bundle_name = os.path.splitext(
        os.path.basename(self._test_bundle_dir))[0]
    pbxproj_objects['XCUITestBundleTarget']['name'] = test_bundle_name
    pbxproj_objects['XCUITestBundleTarget']['productName'] = test_bundle_name
    test_project_build_setting['XCUITEST_BUNDLE_NAME'] = test_bundle_name

    pbxproj_plist_obj.SetPlistField('objects', pbxproj_objects)
Пример #11
0
    def _GetUitestRunnerAppFromXcode(self, platform_library_path):
        """Gets the test runner app for uitest from Xcode directory.

    The test runner app will be copied to TEST_ROOT and renamed to
    {test-bundle-name}-Runner.app.

    Args:
      platform_library_path: string, the library path of the sdk platform.
    Returns:
      A string, the path of uitest runner app.
    """
        test_bundle_name = os.path.splitext(
            os.path.basename(self._test_bundle_dir))[0]
        xctrunner_app = os.path.join(platform_library_path,
                                     'Xcode/Agents/XCTRunner.app')
        uitest_runner_app_name = '%s-Runner' % test_bundle_name
        uitest_runner_app = os.path.join(self._test_root_dir,
                                         uitest_runner_app_name + '.app')
        if os.path.exists(uitest_runner_app):
            shutil.rmtree(uitest_runner_app)
        shutil.copytree(xctrunner_app, uitest_runner_app)
        uitest_runner_exec = os.path.join(uitest_runner_app,
                                          uitest_runner_app_name)
        shutil.move(os.path.join(uitest_runner_app, 'XCTRunner'),
                    uitest_runner_exec)
        # XCTRunner is multi-archs. When launching XCTRunner on arm64e device, it
        # will be launched as arm64e process by default. If the test bundle is arm64
        # bundle, the XCTRunner which hosts the test bundle will fail to be
        # launched. So removing the arm64e arch from XCTRunner can resolve this
        # case.
        test_executable = os.path.join(self._test_bundle_dir, test_bundle_name)
        if self._device_arch == ios_constants.ARCH.ARM64E:
            test_archs = bundle_util.GetFileArchTypes(test_executable)
            if ios_constants.ARCH.ARM64E not in test_archs:
                bundle_util.RemoveArchType(uitest_runner_exec,
                                           ios_constants.ARCH.ARM64E)
        # XCTRunner is multi-archs. When launching XCTRunner on Apple silicon
        # simulator, it will be launched as arm64 process by default. If the test
        # bundle is still x86_64, the XCTRunner which hosts the test bundle will
        # fail to be launched. So removing the arm64 arch from XCTRunner can
        # resolve this case.
        elif not self._on_device:
            test_archs = bundle_util.GetFileArchTypes(test_executable)
            if ios_constants.ARCH.X86_64 in test_archs:
                bundle_util.RemoveArchType(uitest_runner_exec,
                                           ios_constants.ARCH.ARM64)

        runner_app_info_plist_path = os.path.join(uitest_runner_app,
                                                  'Info.plist')
        info_plist = plist_util.Plist(runner_app_info_plist_path)
        info_plist.SetPlistField('CFBundleName', uitest_runner_app_name)
        info_plist.SetPlistField('CFBundleExecutable', uitest_runner_app_name)
        info_plist.SetPlistField('CFBundleIdentifier',
                                 'com.apple.test.' + uitest_runner_app_name)

        return uitest_runner_app
  def device_plist_object(self):
    """Gets the plist_util.Plist object of device.plist of the simulator.

    Returns:
      a plist_util.Plist object of device.plist of the simulator or None when
      the simulator does not exist or is being created.
    """
    if not self._device_plist_object:
      device_plist_path = os.path.join(self.simulator_root_dir, 'device.plist')
      if not os.path.exists(device_plist_path):
        return None
      self._device_plist_object = plist_util.Plist(device_plist_path)
    return self._device_plist_object
Пример #13
0
def EnableUIFileSharing(bundle_path, resigning=True):
    """Enable the UIFileSharingEnabled field in the bundle's Info.plist.

  Args:
    bundle_path: string, full path of bundle folder.
    resigning: bool, whether resigning the bundle after enable
               UIFileSharingEnabled.

  Raises:
    ios_errors.BundleError: when failed to codesign the bundle.
  """
    info_plist = plist_util.Plist(os.path.join(bundle_path, 'Info.plist'))
    info_plist.SetPlistField('UIFileSharingEnabled', True)
    if resigning:
        CodesignBundle(bundle_path)
Пример #14
0
def GetMinimumOSVersion(bundle_path):
    """Gets the minimum OS version of the bundle deployment.

  Args:
    bundle_path: string, full path of bundle folder.

  Returns:
    string, the minimum OS version of the provided bundle.

  Raises:
    ios_errors.PlistError: the MinimumOSVersion does not exist in the bundle's
      Info.plist.
  """
    info_plist = os.path.join(bundle_path, 'Info.plist')
    return plist_util.Plist(info_plist).GetPlistField('MinimumOSVersion')
Пример #15
0
def GetBundleId(bundle_path):
    """Gets the bundle ID of the bundle.

  Args:
    bundle_path: string, full path of bundle folder.

  Returns:
    string, the bundle ID of the provided bundle.

  Raises:
    ios_errors.PlistError: the CFBundleIdentifier does not exist in the bundle's
      Info.plist.
  """
    info_plist = os.path.join(bundle_path, 'Info.plist')
    return plist_util.Plist(info_plist).GetPlistField('CFBundleIdentifier')
Пример #16
0
  def SetTestBundleProvisioningProfile(self, test_bundle_provisioning_profile):
    """Sets the provisioning profile specifier to the test bundle.

    If the given provisioning profile is a path, will also install it in the
    host.

    Args:
      test_bundle_provisioning_profile: string, name/path of the provisioning
        profile of test bundle.
    """
    if not test_bundle_provisioning_profile:
      return
    provisioning_profile_is_file = False
    if (test_bundle_provisioning_profile.startswith('/') and
        os.path.exists(test_bundle_provisioning_profile)):
      provisioning_profile_is_file = True

    if self._sdk != ios_constants.SDK.IPHONEOS:
      logging.warning(
          'Can only set provisioning profile to test bundle in iphoneos SDK. '
          'But current SDK is %s', self._sdk)
      return
    self.GenerateDummyProject()
    if self._test_type == ios_constants.TestType.XCUITEST:
      pbxproj_plist_obj = plist_util.Plist(self.pbxproj_file_path)
      pbxproj_objects = pbxproj_plist_obj.GetPlistField('objects')
      settings = pbxproj_objects['XCUITestBundleBuildConfig']['buildSettings']
      settings['CODE_SIGN_IDENTITY'] = bundle_util.GetCodesignIdentity(
          self._test_bundle_dir)
      if not provisioning_profile_is_file:
        settings[
            'PROVISIONING_PROFILE_SPECIFIER'] = test_bundle_provisioning_profile
      else:
        profile_obj = provisioning_profile.ProvisiongProfile(
            test_bundle_provisioning_profile,
            self._work_dir,
            keychain_path=self._keychain_path)
        profile_obj.Install()
        settings['PROVISIONING_PROFILE_SPECIFIER'] = profile_obj.name
      pbxproj_plist_obj.SetPlistField('objects', pbxproj_objects)
    else:
      logging.warning(
          'Setting provisioning profile specifier to test bundle in test type '
          '%s is not supported.', self._test_type)
Пример #17
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
        }
Пример #18
0
    def GenerateXctestrun(self):
        """Generates a xctestrun object according to arguments.

    The xctestrun file will be generated under work_dir/TEST_ROOT. The app under
    test and test bundle will also be moved under work_dir/TEST_ROOT.

    Returns:
      a xctestrun.XctestRun object.
    """
        if self._xctestrun_obj:
            return self._xctestrun_obj
        if self._work_dir:
            self._test_root_dir = os.path.join(self._work_dir, 'TEST_ROOT')
            xctestrun_file_path = os.path.join(self._test_root_dir,
                                               'xctestrun.plist')
            if os.path.exists(xctestrun_file_path):
                logging.info(
                    'Skips generating xctestrun file which is generated.')
                self._xctestrun_obj = XctestRun(xctestrun_file_path)
                return self._xctestrun_obj

        logging.info('Generating xctestrun file.')
        if self._work_dir:
            if not os.path.exists(self._work_dir):
                os.mkdir(self._work_dir)
        else:
            self._work_dir = tempfile.mkdtemp()
            self._delete_work_dir = True
        self._test_root_dir = os.path.join(self._work_dir, 'TEST_ROOT')
        if not os.path.exists(self._test_root_dir):
            os.mkdir(self._test_root_dir)

        if self._test_type != ios_constants.TestType.LOGIC_TEST:
            self._app_under_test_dir = _MoveAndReplaceFile(
                self._app_under_test_dir, self._test_root_dir)

        if self._test_type == ios_constants.TestType.XCUITEST:
            self._GenerateTestRootForXcuitest()
        elif self._test_type == ios_constants.TestType.XCTEST:
            self._GenerateTestRootForXctest()
        elif self._test_type == ios_constants.TestType.LOGIC_TEST:
            self._GenerateTestRootForLogicTest()

        xctestrun_file_path = os.path.join(self._test_root_dir,
                                           'xctestrun.plist')
        plist_util.Plist(xctestrun_file_path).SetPlistField(
            'Runner', self._xctestrun_dict)

        # Replace the TESTROOT absolute path with __TESTROOT__ in xctestrun file.
        # Then the xctestrun file is not only used in the local machine, but also
        # other mac machines.
        with open(xctestrun_file_path, 'r') as xctestrun_file:
            xctestrun_file_content = xctestrun_file.read()
        xctestrun_file_content = xctestrun_file_content.replace(
            self._test_root_dir, TESTROOT_RELATIVE_PATH)
        with open(xctestrun_file_path, 'w+') as xctestrun_file:
            xctestrun_file.write(xctestrun_file_content)
        self._xctestrun_obj = XctestRun(
            xctestrun_file_path,
            test_type=self._test_type,
            aut_bundle_id=(bundle_util.GetBundleId(self._app_under_test_dir)
                           if self._app_under_test_dir else None))
        return self._xctestrun_obj
Пример #19
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],
        }
Пример #20
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"]
  """
    if os_type is None:
        os_type = ios_constants.OS.IOS
    # 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:
            # `bundlePath` key may not exist in the old Xcode/macOS version.
            if 'bundlePath' in sim_runtime_info:
                runtime_path = sim_runtime_info['bundlePath']
                info_plist_object = plist_util.Plist(
                    os.path.join(runtime_path, 'Contents/Info.plist'))
                min_xcode_version_num = int(
                    info_plist_object.GetPlistField('DTXcode'))
                if xcode_version_num >= min_xcode_version_num:
                    sim_versions.append(listed_os_version)
            else:
                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