def _ValidateSimulatorTypeWithOsVersion(device_type, os_version): """Checks if the simulator type with the given os version is valid. Args: device_type: string, device type of the new simulator. The value corresponds to the output of `xcrun simctl list devicetypes`. E.g., iPhone 6, iPad Air, etc. os_version: string, OS version of the new simulator. The format is {major}.{minor}, such as 9.3, 10.2. Raises: ios_errors.IllegalArgumentError: when the given simulator device type can not match the given OS version. """ os_version_float = float(os_version) sim_profile = simtype_profile.SimTypeProfile(device_type) min_os_version_float = float(sim_profile.min_os_version) if min_os_version_float > os_version_float: raise ios_errors.IllegalArgumentError( 'The min OS version of %s is %s. But current OS version is %s' % (device_type, min_os_version_float, os_version)) max_os_version_float = float(sim_profile.max_os_version) if max_os_version_float < os_version_float: raise ios_errors.IllegalArgumentError( 'The max OS version of %s is %s. But current OS version is %s' % (device_type, max_os_version_float, os_version))
def _FinalizeTestType(test_bundle_dir, sdk, app_under_test_dir=None, original_test_type=None): """Finalizes the test type of the test session according to the args. If original_test_type is not given, will auto detect the test bundle. If Args: test_bundle_dir: string, the path of test bundle folder. sdk: ios_constants.SDK, the sdk of testing device. app_under_test_dir: string, the path of app under test folder. original_test_type: ios_constants.TestType, the original test type. Returns: a ios_constants.TestType object. Raises: ios_errors.IllegalArgumentError: The given arguments are unmatch. """ if not original_test_type: test_type = _DetectTestType(test_bundle_dir) if (test_type == ios_constants.TestType.XCTEST and not app_under_test_dir and sdk == ios_constants.SDK.IPHONESIMULATOR): test_type = ios_constants.TestType.LOGIC_TEST logging.info('Will consider the test as test type %s to run.', test_type) else: test_type = original_test_type if (test_type == ios_constants.TestType.LOGIC_TEST and sdk != ios_constants.SDK.IPHONESIMULATOR): if app_under_test_dir: test_type = ios_constants.TestType.XCTEST logging.info( 'Will consider the test as test type XCTest to run. Because ' 'it is only support running Logic Test on iOS simulator and the ' 'sdk of testing device is %s.', sdk) else: raise ios_errors.IllegalArgumentError( 'It is only support running Logic Test on iOS simulator.' 'The sdk of testing device is %s.' % sdk) elif (test_type == ios_constants.TestType.XCTEST and not app_under_test_dir and sdk == ios_constants.SDK.IPHONESIMULATOR): test_type = ios_constants.TestType.LOGIC_TEST logging.info( 'Will consider the test as test type Logic Test to run. Because the ' 'app under test is not given.') if (not app_under_test_dir and test_type != ios_constants.TestType.LOGIC_TEST): raise ios_errors.IllegalArgumentError( 'The app under test is required in test type %s.' % test_type) return test_type
def _ValidateArguments(self): """Checks whether the arguments of the dummy project is valid. Raises: IllegalArgumentError: when the sdk or test type is not supported. """ if self._sdk not in ios_constants.SUPPORTED_SDKS: raise ios_errors.IllegalArgumentError( 'The sdk %s is not supported. Supported sdks are %s.' % (self._sdk, ios_constants.SUPPORTED_SDKS)) if self._test_type not in ios_constants.SUPPORTED_TEST_TYPES: raise ios_errors.IllegalArgumentError( 'The test type %s is not supported. Supported test types are %s.' % (self._test_type, ios_constants.SUPPORTED_TEST_TYPES))
def GetOsType(device_type): """Gets the OS type of the given simulator. This method can not work fine if the device_type is invalid. Please calls simulator_util.ValidateSimulatorType(device_type, os_version) to validate it first. Args: device_type: string, device type of the new simulator. The value corresponds to the output of `xcrun simctl list devicetypes`. E.g., iPhone 6, iPad Air, etc. Returns: shared.ios_constants.OS. Raises: ios_errors.IllegalArgumentError: when the OS type of the given simulator device type can not be recognized. """ if device_type.startswith('i'): return ios_constants.OS.IOS if 'TV' in device_type: return ios_constants.OS.TVOS if 'Watch' in device_type: return ios_constants.OS.WATCHOS raise ios_errors.IllegalArgumentError( 'Failed to recognize the os type for simulator device type %s.' % device_type)
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
def _PlatformToSdk(platform): """Gets the SDK of the given platform.""" if platform == ios_constants.PLATFORM.IOS_DEVICE: return ios_constants.SDK.IPHONEOS if platform == ios_constants.PLATFORM.IOS_SIMULATOR: return ios_constants.SDK.IPHONESIMULATOR raise ios_errors.IllegalArgumentError( 'The platform %s is not supported. The supported values are %s.' % (platform, ios_constants.SUPPORTED_PLATFORMS))
def _GetJson(json_path): """Gets the json dict from the file.""" if json_path: with open(json_path) as input_file: try: return json.load(input_file) except ValueError as e: raise ios_errors.IllegalArgumentError(e) return None
def _ValidateArguments(self): """Checks whether the arguments of this class are valid. Raises: IllegalArgumentError: when the sdk or test type is not supported. """ if self._sdk not in ios_constants.SUPPORTED_SDKS: raise ios_errors.IllegalArgumentError( 'The sdk %s is not supported. Supported sdks are %s.' % (self._sdk, ios_constants.SUPPORTED_SDKS)) if self._test_type not in ios_constants.SUPPORTED_TEST_TYPES: raise ios_errors.IllegalArgumentError( 'The test type %s is not supported. Supported test types are %s.' % (self._test_type, ios_constants.SUPPORTED_TEST_TYPES)) if (self._test_type == ios_constants.TestType.LOGIC_TEST and self._on_device): raise ios_errors.IllegalArgumentError( 'Only support running logic test on sdk iphonesimulator. ' 'Current sdk is %s' % self._sdk)
def _GetSdk(device_id): """Gets the sdk of the target device with the given device_id.""" devices_list_output = subprocess.check_output( ['xcrun', 'xcdevice', 'list']).decode('utf-8') for device_info in json.loads(devices_list_output): if device_info['identifier'] == device_id: return ios_constants.SDK.IPHONESIMULATOR if device_info[ 'simulator'] else ios_constants.SDK.IPHONEOS raise ios_errors.IllegalArgumentError( 'The device with id %s can not be found. The known devices are %s.' % (device_id, devices_list_output))
def _ValidateSimulatorType(device_type): """Checks if the simulator type is valid. Args: device_type: string, device type of the new simulator. The value corresponds to the output of `xcrun simctl list devicetypes`. E.g., iPhone 6, iPad Air, etc. Raises: ios_errors.IllegalArgumentError: when the given simulator device type is invalid. """ supported_sim_device_types = GetSupportedSimDeviceTypes() if device_type not in supported_sim_device_types: raise ios_errors.IllegalArgumentError( 'The simulator device type %s is not supported. Supported simulator ' 'device types are %s.' % (device_type, supported_sim_device_types))
def GetLastSupportedSimOsVersion(os_type=ios_constants.OS.IOS, device_type=None): """Gets the last supported version of given arguments. If device_type is given, will return the last supported OS version of the device type. Otherwise, will return the last supported OS version of the OS type. Args: os_type: shared.ios_constants.OS, OS type of simulator, such as iOS, watchOS, tvOS. device_type: string, device type of the new simulator. The value corresponds to the output of `xcrun simctl list devicetypes`. E.g., iPhone 6, iPad Air, etc. Returns: a string, the last supported version. Raises: ios_errors.SimError: when there is no supported OS version of the given OS. ios_errors.IllegalArgumentError: when the supported OS version can not match the given simulator type. """ supported_os_versions = GetSupportedSimOsVersions(os_type) if not supported_os_versions: raise ios_errors.SimError('Can not find supported OS version of %s.' % os_type) if not device_type: return supported_os_versions[-1] max_os_version = simtype_profile.SimTypeProfile(device_type).max_os_version # The supported os versions will be from latest to older after reverse(). supported_os_versions.reverse() if not max_os_version: return supported_os_versions[0] for os_version in supported_os_versions: if float(os_version) <= max_os_version: return os_version raise ios_errors.IllegalArgumentError( 'The supported OS version %s can not match simulator type %s. Because ' 'its max OS version is %s' % (supported_os_versions, device_type, max_os_version))
def _GetSdk(device_id): """Gets the sdk of the target device with the given device_id.""" # The command `instruments -s devices` is much slower than # `xcrun simctl list devices`. So use `xcrun simctl list devices` to check # IPHONESIMULATOR SDK first. simlist_devices_output = simulator_util.RunSimctlCommand( ['xcrun', 'simctl', 'list', 'devices']) if device_id in simlist_devices_output: return ios_constants.SDK.IPHONESIMULATOR known_devices_output = subprocess.check_output( ['instruments', '-s', 'devices']) for line in known_devices_output.split('\n'): if device_id in line and '(Simulator)' not in line: return ios_constants.SDK.IPHONEOS raise ios_errors.IllegalArgumentError( 'The device with id %s can not be found. The known devices are %s.' % (device_id, known_devices_output))
def _PrepareBundles(working_dir, app_under_test_path, test_bundle_path): """Prepares the bundles in work directory. If the original bundle is .ipa, the .ipa file will be unzipped under working_dir. If the original bundle is .app/.xctest and the bundle file is not in working_dir, the bundle file will be copied to working_dir. Args: working_dir: string, the working directory. app_under_test_path: string, the path of the application to be tested. It can be .ipa or .app. It can be None. test_bundle_path: string, the path of the test bundle to be tested. It can be .ipa or .xctest. Returns: a tuple with two items: a path of app under test directory (.app) under work directory. a path of test bundle directory (.xctest) under work directory. Raises: ios_errors.IllegalArgumentError: if the app under test/test bundle does not exist or its extension is invaild. """ working_dir = os.path.abspath(working_dir) app_under_test_dir = None if app_under_test_path: if not os.path.exists(app_under_test_path): raise ios_errors.IllegalArgumentError( 'The app under test does not exists: %s' % app_under_test_path) if not (app_under_test_path.endswith('.app') or app_under_test_path.endswith('.ipa')): raise ios_errors.IllegalArgumentError( 'The app under test %s should be with .app or .ipa extension.' % app_under_test_path) app_under_test_dir = os.path.join( working_dir, os.path.splitext(os.path.basename(app_under_test_path))[0] + '.app') if not os.path.exists(app_under_test_dir): if app_under_test_path.endswith('.ipa'): extract_app_under_test_dir = bundle_util.ExtractApp( app_under_test_path, working_dir) shutil.move(extract_app_under_test_dir, app_under_test_dir) elif not os.path.abspath(app_under_test_path).startswith( working_dir): # Only copies the app under test if it is not in working directory. shutil.copytree(app_under_test_path, app_under_test_dir) else: app_under_test_dir = app_under_test_path if not os.path.exists(test_bundle_path): raise ios_errors.IllegalArgumentError( 'The test bundle does not exists: %s' % test_bundle_path) if not (test_bundle_path.endswith('.xctest') or test_bundle_path.endswith('.ipa') or test_bundle_path.endswith('.zip')): raise ios_errors.IllegalArgumentError( 'The test bundle %s should be with .xctest, .ipa or .zip extension.' % test_bundle_path) test_bundle_dir = os.path.join( working_dir, os.path.splitext(os.path.basename(test_bundle_path))[0] + '.xctest') if not os.path.exists(test_bundle_dir): if test_bundle_path.endswith('.ipa') or test_bundle_path.endswith( '.zip'): extract_test_bundle_dir = bundle_util.ExtractTestBundle( test_bundle_path, working_dir) shutil.move(extract_test_bundle_dir, test_bundle_dir) elif not os.path.abspath(test_bundle_path).startswith(working_dir): # Only copies the test bundle if it is not in working directory. shutil.copytree(test_bundle_path, test_bundle_dir) else: test_bundle_dir = test_bundle_path return app_under_test_dir, test_bundle_dir
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
def CreateNewSimulator(device_type=None, os_version=None, name_prefix=None): """Creates a new simulator according to arguments. If neither device_type nor os_version is given, will use the latest iOS version and latest iPhone type. If os_version is given but device_type is not, will use latest iPhone type according to the OS version limitation. E.g., if the given os_version is 9.3, the latest simulator type is iPhone 6s Plus. Because the min OS version of iPhone 7 is 10.0. If device_type is given but os_version is not, will use the min value between max OS version of the simulator type and current latest OS version. E.g., if the given device_type is iPhone 5 and latest OS version is 10.3, will use 10.2. Because the max OS version of iPhone 5 is 10.2. Args: device_type: string, device type of the new simulator. The value corresponds to the output of `xcrun simctl list devicetypes`. E.g., iPhone 6, iPad Air, etc. os_version: string, OS version of the new simulator. The format is {major}.{minor}, such as 9.3, 10.2. name_prefix: string, name prefix of the new simulator. By default, it is "New". Returns: a tuple with four items: string, id of the new simulator. string, simulator device type of the new simulator. string, OS version of the new simulator. string, name of the new simulator. Raises: ios_errors.SimError: when failed to create new simulator. ios_errors.IllegalArgumentError: when the given argument is invalid. """ if not device_type: os_type = ios_constants.OS.IOS else: _ValidateSimulatorType(device_type) os_type = GetOsType(device_type) if not os_version: os_version = GetLastSupportedSimOsVersion(os_type, device_type=device_type) else: supported_sim_os_versions = GetSupportedSimOsVersions(os_type) if os_version not in supported_sim_os_versions: raise ios_errors.IllegalArgumentError( 'The simulator os version %s is not supported. Supported simulator ' 'os versions are %s.' % (os_version, supported_sim_os_versions)) if not device_type: device_type = GetLastSupportedIphoneSimType(os_version) else: _ValidateSimulatorTypeWithOsVersion(device_type, os_version) if not name_prefix: name_prefix = 'New' name = '%s-%s-%s' % (name_prefix, device_type, os_version) # Example # Runtime ID of iOS 10.2: com.apple.CoreSimulator.SimRuntime.iOS-10-2 runtime_id = _PREFIX_RUNTIME_ID + os_type + '-' + os_version.replace( '.', '-') logging.info('Creating a new simulator:\nName: %s\nOS: %s %s\nType: %s', name, os_type, os_version, device_type) for i in range(0, _SIM_OPERATION_MAX_ATTEMPTS): try: new_simulator_id = RunSimctlCommand( ['xcrun', 'simctl', 'create', name, device_type, runtime_id]) except ios_errors.SimError as e: raise ios_errors.SimError('Failed to create simulator: %s' % str(e)) new_simulator_obj = Simulator(new_simulator_id) # After creating a new simulator, its state is CREATING. When the # simulator's state becomes SHUTDOWN, the simulator is created. try: new_simulator_obj.WaitUntilStateShutdown( _SIMULATOR_CREATING_TO_SHUTDOWN_TIMEOUT_SEC) logging.info('Created new simulator %s.', new_simulator_id) return new_simulator_id, device_type, os_version, name except ios_errors.SimError as error: logging.debug('Failed to create simulator %s: %s.', new_simulator_id, error) logging.debug('Deleted half-created simulator %s.', new_simulator_id) new_simulator_obj.Delete() if i != _SIM_OPERATION_MAX_ATTEMPTS - 1: logging.debug('Will sleep %ss and retry again.', _SIM_ERROR_RETRY_INTERVAL_SEC) # If the simulator's state becomes SHUTDOWN, there may be something # wrong in CoreSimulatorService. Sleeps a short interval(2s) can help # reduce flakiness. time.sleep(_SIM_ERROR_RETRY_INTERVAL_SEC) raise ios_errors.SimError('Failed to create simulator in %d attempts.' % _SIM_OPERATION_MAX_ATTEMPTS)
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. 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: 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) if test_type not in ios_constants.SUPPORTED_TEST_TYPES: raise ios_errors.IllegalArgumentError( 'The test type %s is not supported. Supported test types are %s' % (test_type, ios_constants.SUPPORTED_TEST_TYPES)) if test_type != ios_constants.TestType.LOGIC_TEST: xctestrun_factory = xctestrun.XctestRunFactory( app_under_test_dir, test_bundle_dir, self._sdk, self._device_arch, test_type, signing_options, self._work_dir) self._xctestrun_obj = xctestrun_factory.GenerateXctestrun() else: self._logic_test_bundle = test_bundle_dir self._prepared = True
def _PrepareBundles(working_dir, app_under_test_path, test_bundle_path): """Prepares the bundles in work directory. If the original bundle is .ipa, the .ipa file will be unzipped under working_dir. If the original bundle is .app/.xctest and the bundle file is not in working_dir, the bundle file will be copied to working_dir. Args: working_dir: string, the working directory. app_under_test_path: string, the path of the application to be tested. It can be .ipa or .app. It can be None. test_bundle_path: string, the path of the test bundle to be tested. It can be .ipa or .xctest. Returns: a tuple with two items: a path of app under test directory (.app) under work directory. a path of test bundle directory (.xctest) under work directory. Raises: ios_errors.IllegalArgumentError: if the app under test/test bundle does not exist or its extension is invaild. """ working_dir = os.path.abspath(working_dir) app_under_test_dir = None if app_under_test_path: if not os.path.exists(app_under_test_path): raise ios_errors.IllegalArgumentError( 'The app under test does not exists: %s' % app_under_test_path) if not (app_under_test_path.endswith('.app') or app_under_test_path.endswith('.ipa')): raise ios_errors.IllegalArgumentError( 'The app under test %s should be with .app or .ipa extension.' % app_under_test_path) app_under_test_dir = os.path.join( working_dir, os.path.splitext(os.path.basename(app_under_test_path))[0] + '.app') if not os.path.exists(app_under_test_dir): if app_under_test_path.endswith('.ipa'): extract_app_under_test_dir = bundle_util.ExtractApp( app_under_test_path, working_dir) shutil.move(extract_app_under_test_dir, app_under_test_dir) elif not os.path.abspath(app_under_test_path).startswith( working_dir): # Only copies the app under test if it is not in working directory. shutil.copytree(app_under_test_path, app_under_test_dir) else: app_under_test_dir = app_under_test_path if not os.path.exists(test_bundle_path): raise ios_errors.IllegalArgumentError( 'The test bundle does not exists: %s' % test_bundle_path) if not (test_bundle_path.endswith('.xctest') or test_bundle_path.endswith('.ipa') or test_bundle_path.endswith('.zip')): raise ios_errors.IllegalArgumentError( 'The test bundle %s should be with .xctest, .ipa or .zip extension.' % test_bundle_path) bundle_copied = False test_bundle_dir = os.path.join( working_dir, os.path.splitext(os.path.basename(test_bundle_path))[0] + '.xctest') if not os.path.exists(test_bundle_dir): if test_bundle_path.endswith('.ipa') or test_bundle_path.endswith( '.zip'): extract_test_bundle_dir = bundle_util.ExtractTestBundle( test_bundle_path, working_dir) shutil.move(extract_test_bundle_dir, test_bundle_dir) bundle_copied = True elif not os.path.abspath(test_bundle_path).startswith(working_dir): # Only copies the test bundle if it is not in working directory. shutil.copytree(test_bundle_path, test_bundle_dir) bundle_copied = True else: test_bundle_dir = test_bundle_path plugins_path = os.path.join(test_bundle_dir, "PlugIns") if not app_under_test_dir and os.path.isdir(plugins_path): try: app = next( filter(lambda x: x.endswith(".app"), os.listdir(plugins_path))) app = os.path.join(plugins_path, app) app_dest_dir = os.path.join( working_dir, os.path.splitext(os.path.basename(app))[0] + '.app') if bundle_copied: shutil.move(app, app_dest_dir) else: shutil.copy(app, app_dest_dir) # Only set this after the copy/move has successfully completed app_under_test_dir = app_dest_dir except StopIteration: pass return app_under_test_dir, test_bundle_dir