def _GenerateTestRootForLogicTest(self): """Generates the test root for Logic test. The approach constructs xctestrun.plist from Xcode. Then copies test bundle and xctestrun.plist to test root directory. """ dyld_framework_path = os.path.join( xcode_info_util.GetSdkPlatformPath(self._sdk), 'Developer/Library/Frameworks') test_envs = { 'DYLD_FRAMEWORK_PATH': dyld_framework_path, 'DYLD_LIBRARY_PATH': dyld_framework_path } # Fixes failures for unit 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 = { 'TestBundlePath': self._test_bundle_dir, 'TestHostPath': xcode_info_util.GetXctestToolPath(self._sdk), 'TestingEnvironmentVariables': test_envs, }
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
def RunLogicTestOnSim(sim_id, test_bundle_path, env_vars=None, args=None, tests_to_run=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. 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' # Fixes failures for unit 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: simctl_env_vars[_SIMCTL_ENV_VAR_PREFIX + "DYLD_FALLBACK_LIBRARY_PATH"] = swift5FallbackLibsDir 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
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
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 }
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], }