def testNonExistentExtensionPath(self): """Test that a non-existent extension path will raise an exception.""" extension_path = os.path.join(util.GetUnittestDataDir(), 'foo') options = options_for_unittests.GetCopy() self.assertRaises(extension_to_load.ExtensionPathNonExistentException, lambda: extension_to_load.ExtensionToLoad( extension_path, options.browser_type))
def _CreateBrowser(self, autotest_ext=False, auto_login=True, gaia_login=False, username=None, password=None): """Finds and creates a browser for tests. if autotest_ext is True, also loads the autotest extension""" options = options_for_unittests.GetCopy() if autotest_ext: extension_path = os.path.join(util.GetUnittestDataDir(), 'autotest_ext') assert os.path.isdir(extension_path) self._load_extension = extension_to_load.ExtensionToLoad( path=extension_path, browser_type=options.browser_type, is_component=True) options.extensions_to_load = [self._load_extension] browser_to_create = browser_finder.FindBrowser(options) self.assertTrue(browser_to_create) browser_options = options.browser_options browser_options.create_browser_with_oobe = True browser_options.auto_login = auto_login browser_options.gaia_login = gaia_login if username is not None: browser_options.username = username if password is not None: browser_options.password = password return browser_to_create.Create(options)
def setUp(self): """ Copy the manifest and background.js files of simple_extension to a number of temporary directories to load as extensions""" self._extension_dirs = [tempfile.mkdtemp() for _ in range(3)] src_extension_dir = os.path.join( util.GetUnittestDataDir(), 'simple_extension') manifest_path = os.path.join(src_extension_dir, 'manifest.json') script_path = os.path.join(src_extension_dir, 'background.js') for d in self._extension_dirs: shutil.copy(manifest_path, d) shutil.copy(script_path, d) options = options_for_unittests.GetCopy() self._extensions_to_load = [ extension_to_load.ExtensionToLoad(d, options.browser_type) for d in self._extension_dirs ] options.browser_options.extensions_to_load = self._extensions_to_load browser_to_create = browser_finder.FindBrowser(options) self._platform = None self._browser = None # May not find a browser that supports extensions. if browser_to_create: self._platform = browser_to_create.platform self._platform.network_controller.InitializeIfNeeded() self._browser = browser_to_create.Create(options)
def testComponentExtensionBasic(self): extension_path = os.path.join(util.GetUnittestDataDir(), 'component_extension') options = options_for_unittests.GetCopy() load_extension = extension_to_load.ExtensionToLoad( extension_path, options.browser_type, is_component=True) options.browser_options.extensions_to_load = [load_extension] browser_to_create = browser_finder.FindBrowser(options) if not browser_to_create: logging.warning('Did not find a browser that supports extensions, ' 'skipping test.') return try: browser_to_create.platform.network_controller.InitializeIfNeeded() with browser_to_create.Create(options) as b: extension = b.extensions[load_extension] self.assertTrue( extension.EvaluateJavaScript('chrome.runtime != null')) extension.ExecuteJavaScript('setTestVar("abcdef")') self.assertEquals('abcdef', extension.EvaluateJavaScript('_testVar')) finally: browser_to_create.platform.network_controller.Close()
def _CreateBrowser(self, autotest_ext=False, auto_login=True, gaia_login=False, username=None, password=None, gaia_id=None, dont_override_profile=False): """Finds and creates a browser for tests. if autotest_ext is True, also loads the autotest extension""" finder_options = options_for_unittests.GetCopy() browser_options = finder_options.browser_options if autotest_ext: extension_path = os.path.join(util.GetUnittestDataDir(), 'autotest_ext') assert os.path.isdir(extension_path) self._load_extension = extension_to_load.ExtensionToLoad( path=extension_path, browser_type=finder_options.browser_type) browser_options.extensions_to_load = [self._load_extension] browser_to_create = browser_finder.FindBrowser(finder_options) self.assertTrue(browser_to_create) browser_options.create_browser_with_oobe = True browser_options.auto_login = auto_login browser_options.gaia_login = gaia_login browser_options.dont_override_profile = dont_override_profile if username is not None: browser_options.username = username if password is not None: browser_options.password = password if gaia_id is not None: browser_options.gaia_id = gaia_id return browser_to_create.BrowserSession(browser_options)
def Start(self, local_app_path=None): """ Connects to the ChromeOS device and logs in. Args: local_app_path: A path on the local device containing the Smart Lock app to use instead of the app on the ChromeOS device. Return: |self| for using in a "with" statement. """ assert(self._browser is None) finder_opts = browser_options.BrowserFinderOptions('cros-chrome') finder_opts.CreateParser().parse_args(args=[]) finder_opts.cros_remote = self._remote_address if self._ssh_port is not None: finder_opts.cros_remote_ssh_port = self._ssh_port finder_opts.verbosity = 1 browser_opts = finder_opts.browser_options browser_opts.create_browser_with_oobe = True browser_opts.disable_component_extensions_with_background_pages = False browser_opts.gaia_login = True browser_opts.username = self._username browser_opts.password = self._password browser_opts.auto_login = True self._cros_interface = cros_interface.CrOSInterface( finder_opts.cros_remote, finder_opts.cros_remote_ssh_port, finder_opts.cros_ssh_identity) browser_opts.disable_default_apps = local_app_path is not None if local_app_path is not None: easy_unlock_app = extension_to_load.ExtensionToLoad( path=local_app_path, browser_type='cros-chrome', is_component=True) finder_opts.extensions_to_load.append(easy_unlock_app) self._browser_to_create = browser_finder.FindBrowser(finder_opts) self._browser_to_create.SetUpEnvironment(browser_opts) retries = 3 while self._browser is not None or retries > 0: try: self._browser = self._browser_to_create.Create() break; except (exceptions.LoginException) as e: logger.error('Timed out logging in: %s' % e); if retries == 1: raise bg_page_path = '/_generated_background_page.html' util.WaitFor( lambda: self._FindSmartLockAppPage(bg_page_path) is not None, 10); self._background_page = self._FindSmartLockAppPage(bg_page_path) return self
def testComponentExtensionNoPublicKey(self): # simple_extension does not have a public key. extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension') options = options_for_unittests.GetCopy() self.assertRaises( extension_to_load.MissingPublicKeyException, lambda: extension_to_load.ExtensionToLoad(extension_path, browser_type=options. browser_type, is_component=True))
def testExtensionNotLoaded(self): """Querying an extension that was not loaded will return None""" extension_path = os.path.join(util.GetUnittestDataDir(), 'simple_extension') options = options_for_unittests.GetCopy() load_extension = extension_to_load.ExtensionToLoad( extension_path, options.browser_type) browser_to_create = browser_finder.FindBrowser(options) with browser_to_create.Create(options) as b: if b.supports_extensions: self.assertRaises(KeyError, lambda: b.extensions[load_extension])
def CreateBrowserWithExtension(self, ext_path): extension_path = os.path.join(util.GetUnittestDataDir(), ext_path) options = options_for_unittests.GetCopy() load_extension = extension_to_load.ExtensionToLoad( extension_path, options.browser_type) options.extensions_to_load = [load_extension] browser_to_create = browser_finder.FindBrowser(options) if not browser_to_create: # May not find a browser that supports extensions. return False self._browser = browser_to_create.Create(options) self._extension = self._browser.extensions[load_extension] self._extension_id = load_extension.extension_id self.assertTrue(self._extension) return True
def ClonedExtensions(self): """ Copy the manifest and background.js files of simple_extension to a number of temporary directories to load as extensions""" extension_dirs = [tempfile.mkdtemp() for _ in range(3)] try: src_dir = os.path.join(util.GetUnittestDataDir(), 'simple_extension') manifest_path = os.path.join(src_dir, 'manifest.json') script_path = os.path.join(src_dir, 'background.js') for tmp_dir in extension_dirs: shutil.copy(manifest_path, tmp_dir) shutil.copy(script_path, tmp_dir) yield [ extension_to_load.ExtensionToLoad(d, self._options.browser_type) for d in extension_dirs] finally: for tmp_dir in extension_dirs: shutil.rmtree(tmp_dir)
def _CreateBrowser(self, autotest_ext=False, auto_login=True): """Finds and creates a browser for tests. if autotest_ext is True, also loads the autotest extension""" options = options_for_unittests.GetCopy() if autotest_ext: extension_path = os.path.join(os.path.dirname(__file__), 'autotest_ext') self._load_extension = extension_to_load.ExtensionToLoad( path=extension_path, browser_type=options.browser_type, is_component=True) options.extensions_to_load = [self._load_extension] browser_to_create = browser_finder.FindBrowser(options) self.assertTrue(browser_to_create) options.browser_options.create_browser_with_oobe = True options.browser_options.auto_login = auto_login b = browser_to_create.Create(options) b.Start() return b
def __init__(self, logged_in=True, extension_paths=None, autotest_ext=False, num_tries=3, extra_browser_args=None, clear_enterprise_policy=True, expect_policy_fetch=False, dont_override_profile=False, disable_gaia_services=True, disable_default_apps=True, auto_login=True, gaia_login=False, username=None, password=None, gaia_id=None, arc_mode=None, arc_timeout=None, disable_arc_opt_in=True, disable_arc_opt_in_verification=True, disable_arc_cpu_restriction=True, disable_app_sync=False, disable_play_auto_install=False, disable_locale_sync=True, disable_play_store_auto_update=True, enable_assistant=False, enterprise_arc_test=False, init_network_controller=False, mute_audio=False, proxy_server=None, login_delay=0): """ Constructor of telemetry wrapper. @param logged_in: Regular user (True) or guest user (False). @param extension_paths: path of unpacked extension to install. @param autotest_ext: Load a component extension with privileges to invoke chrome.autotestPrivate. @param num_tries: Number of attempts to log in. @param extra_browser_args: Additional argument(s) to pass to the browser. It can be a string or a list. @param clear_enterprise_policy: Clear enterprise policy before logging in. @param expect_policy_fetch: Expect that chrome can reach the device management server and download policy. @param dont_override_profile: Don't delete cryptohome before login. Telemetry will output a warning with this option. @param disable_gaia_services: For enterprise autotests, this option may be used to enable policy fetch. @param disable_default_apps: For tests that exercise default apps. @param auto_login: Does not login automatically if this is False. Useful if you need to examine oobe. @param gaia_login: Logs in to real gaia. @param username: Log in using this username instead of the default. @param password: Log in using this password instead of the default. @param gaia_id: Log in using this gaia_id instead of the default. @param arc_mode: How ARC instance should be started. Default is to not start. @param arc_timeout: Timeout to wait for ARC to boot. @param disable_arc_opt_in: For opt in flow autotest. This option is used to disable the arc opt in flow. @param disable_arc_opt_in_verification: Adds --disable-arc-opt-in-verification to browser args. This should generally be enabled when disable_arc_opt_in is enabled. However, for data migration tests where user's home data is already set up with opted-in state before login, this option needs to be set to False with disable_arc_opt_in=True to make ARC container work. @param disable_arc_cpu_restriction: Adds --disable-arc-cpu-restriction to browser args. This is enabled by default and will make tests run faster and is generally desirable unless a test is actually trying to test performance where ARC is running in the background for some porition of the test. @param disable_app_sync: Adds --arc-disable-app-sync to browser args and this disables ARC app sync flow. By default it is enabled. @param disable_play_auto_install: Adds --arc-disable-play-auto-install to browser args and this disables ARC Play Auto Install flow. By default it is enabled. @param enable_assistant: For tests that require to enable Google Assistant service. Default is False. @param enterprise_arc_test: Skips opt_in causing enterprise tests to fail @param disable_locale_sync: Adds --arc-disable-locale-sync to browser args and this disables locale sync between Chrome and Android container. In case of disabling sync, Android container is started with language and preference language list as it was set on the moment of starting full instance. Used to prevent random app restarts caused by racy locale change, coming from profile sync. By default locale sync is disabled. @param disable_play_store_auto_update: Adds --arc-play-store-auto-update=off to browser args and this disables Play Store, GMS Core and third-party apps auto-update. By default auto-update is off to have stable autotest environment. @param mute_audio: Mute audio. @param proxy_server: To launch the chrome with --proxy-server Adds '--proxy-server="http://$HTTP_PROXY:PORT"' to browser args. By default proxy-server is disabled @param login_delay: Time for idle in login screen to simulate the time required for password typing. """ self._autotest_ext_path = None # Force autotest extension if we need enable Play Store. if (utils.is_arc_available() and (arc_util.should_start_arc(arc_mode) or not disable_arc_opt_in)): autotest_ext = True if extension_paths is None: extension_paths = [] finder_options = browser_options.BrowserFinderOptions() if proxy_server: finder_options.browser_options.AppendExtraBrowserArgs( ['--proxy-server="%s"' % proxy_server]) if utils.is_arc_available() and arc_util.should_start_arc(arc_mode): if disable_arc_opt_in and disable_arc_opt_in_verification: finder_options.browser_options.AppendExtraBrowserArgs( ['--disable-arc-opt-in-verification']) if disable_arc_cpu_restriction: finder_options.browser_options.AppendExtraBrowserArgs( ['--disable-arc-cpu-restriction']) if disable_app_sync: finder_options.browser_options.AppendExtraBrowserArgs( ['--arc-disable-app-sync']) if disable_play_auto_install: finder_options.browser_options.AppendExtraBrowserArgs( ['--arc-disable-play-auto-install']) if disable_locale_sync: finder_options.browser_options.AppendExtraBrowserArgs( ['--arc-disable-locale-sync']) if disable_play_store_auto_update: finder_options.browser_options.AppendExtraBrowserArgs( ['--arc-play-store-auto-update=off']) logged_in = True if autotest_ext: self._autotest_ext_path = os.path.join(os.path.dirname(__file__), 'autotest_private_ext') extension_paths.append(self._autotest_ext_path) finder_options.browser_options.AppendExtraBrowserArgs( ['--whitelisted-extension-id=%s' % self.AUTOTEST_EXT_ID]) self._browser_type = (self.BROWSER_TYPE_LOGIN if logged_in else self.BROWSER_TYPE_GUEST) finder_options.browser_type = self.browser_type if extra_browser_args: finder_options.browser_options.AppendExtraBrowserArgs( extra_browser_args) # finder options must be set before parse_args(), browser options must # be set before Create(). # TODO(crbug.com/360890) Below MUST be '2' so that it doesn't inhibit # autotest debug logs finder_options.verbosity = 2 finder_options.CreateParser().parse_args(args=[]) b_options = finder_options.browser_options b_options.disable_component_extensions_with_background_pages = False b_options.create_browser_with_oobe = True b_options.clear_enterprise_policy = clear_enterprise_policy b_options.dont_override_profile = dont_override_profile b_options.disable_gaia_services = disable_gaia_services b_options.disable_default_apps = disable_default_apps b_options.disable_component_extensions_with_background_pages = disable_default_apps b_options.disable_background_networking = False b_options.expect_policy_fetch = expect_policy_fetch b_options.auto_login = auto_login b_options.gaia_login = gaia_login b_options.mute_audio = mute_audio b_options.login_delay = login_delay if utils.is_arc_available() and not disable_arc_opt_in: arc_util.set_browser_options_for_opt_in(b_options) self.username = b_options.username if username is None else username self.password = b_options.password if password is None else password self.username = NormalizeEmail(self.username) b_options.username = self.username b_options.password = self.password self.gaia_id = b_options.gaia_id if gaia_id is None else gaia_id b_options.gaia_id = self.gaia_id self.arc_mode = arc_mode if logged_in: extensions_to_load = b_options.extensions_to_load for path in extension_paths: extension = extension_to_load.ExtensionToLoad( path, self.browser_type) extensions_to_load.append(extension) self._extensions_to_load = extensions_to_load # Turn on collection of Chrome coredumps via creation of a magic file. # (Without this, Chrome coredumps are trashed.) open(constants.CHROME_CORE_MAGIC_FILE, 'w').close() self._browser_to_create = browser_finder.FindBrowser(finder_options) self._browser_to_create.SetUpEnvironment(b_options) for i in range(num_tries): try: self._browser = self._browser_to_create.Create() self._browser_pid = \ cros_interface.CrOSInterface().GetChromePid() if utils.is_arc_available(): if disable_arc_opt_in: if arc_util.should_start_arc(arc_mode): arc_util.enable_play_store(self.autotest_ext, True) else: if not enterprise_arc_test: wait_for_provisioning = \ arc_mode != arc_common.ARC_MODE_ENABLED_ASYNC arc_util.opt_in( browser=self.browser, autotest_ext=self.autotest_ext, wait_for_provisioning=wait_for_provisioning) arc_util.post_processing_after_browser(self, arc_timeout) if enable_assistant: assistant_util.enable_assistant(self.autotest_ext) break except exceptions.LoginException as e: logging.error('Timed out logging in, tries=%d, error=%s', i, repr(e)) if i == num_tries - 1: raise if init_network_controller: self._browser.platform.network_controller.Open()
def __init__(self, logged_in=True, extension_paths=[], autotest_ext=False, num_tries=3, extra_browser_args=None, clear_enterprise_policy=True, dont_override_profile=False, disable_gaia_services=True, disable_default_apps=True, auto_login=True, gaia_login=False, username=None, password=None, gaia_id=None, arc_mode=None, disable_arc_opt_in=True, init_network_controller=False): """ Constructor of telemetry wrapper. @param logged_in: Regular user (True) or guest user (False). @param extension_paths: path of unpacked extension to install. @param autotest_ext: Load a component extension with privileges to invoke chrome.autotestPrivate. @param num_tries: Number of attempts to log in. @param extra_browser_args: Additional argument(s) to pass to the browser. It can be a string or a list. @param clear_enterprise_policy: Clear enterprise policy before logging in. @param dont_override_profile: Don't delete cryptohome before login. Telemetry will output a warning with this option. @param disable_gaia_services: For enterprise autotests, this option may be used to enable policy fetch. @param disable_default_apps: For tests that exercise default apps. @param auto_login: Does not login automatically if this is False. Useful if you need to examine oobe. @param gaia_login: Logs in to real gaia. @param username: Log in using this username instead of the default. @param password: Log in using this password instead of the default. @param gaia_id: Log in using this gaia_id instead of the default. @param arc_mode: How ARC instance should be started. Default is to not start. @param disable_arc_opt_in: For opt in flow autotest. This option is used to disable the arc opt in flow. """ self._autotest_ext_path = None # Force autotest extension if we need enable Play Store. if (utils.is_arc_available() and (arc_util.should_start_arc(arc_mode) or not disable_arc_opt_in)): autotest_ext = True if autotest_ext: self._autotest_ext_path = os.path.join(os.path.dirname(__file__), 'autotest_private_ext') extension_paths.append(self._autotest_ext_path) finder_options = browser_options.BrowserFinderOptions() if utils.is_arc_available() and arc_util.should_start_arc(arc_mode): if disable_arc_opt_in: finder_options.browser_options.AppendExtraBrowserArgs( arc_util.get_extra_chrome_flags()) logged_in = True self._browser_type = (self.BROWSER_TYPE_LOGIN if logged_in else self.BROWSER_TYPE_GUEST) finder_options.browser_type = self.browser_type if extra_browser_args: finder_options.browser_options.AppendExtraBrowserArgs( extra_browser_args) # finder options must be set before parse_args(), browser options must # be set before Create(). # TODO(crbug.com/360890) Below MUST be '2' so that it doesn't inhibit # autotest debug logs finder_options.verbosity = 2 finder_options.CreateParser().parse_args(args=[]) b_options = finder_options.browser_options b_options.disable_component_extensions_with_background_pages = False b_options.create_browser_with_oobe = True b_options.clear_enterprise_policy = clear_enterprise_policy b_options.dont_override_profile = dont_override_profile b_options.disable_gaia_services = disable_gaia_services b_options.disable_default_apps = disable_default_apps b_options.disable_component_extensions_with_background_pages = disable_default_apps b_options.auto_login = auto_login b_options.gaia_login = gaia_login if utils.is_arc_available() and not disable_arc_opt_in: arc_util.set_browser_options_for_opt_in(b_options) self.username = b_options.username if username is None else username self.password = b_options.password if password is None else password self.username = NormalizeEmail(self.username) b_options.username = self.username b_options.password = self.password self.gaia_id = b_options.gaia_id if gaia_id is None else gaia_id b_options.gaia_id = self.gaia_id self.arc_mode = arc_mode if logged_in: extensions_to_load = b_options.extensions_to_load for path in extension_paths: extension = extension_to_load.ExtensionToLoad( path, self.browser_type) extensions_to_load.append(extension) self._extensions_to_load = extensions_to_load # Turn on collection of Chrome coredumps via creation of a magic file. # (Without this, Chrome coredumps are trashed.) open(constants.CHROME_CORE_MAGIC_FILE, 'w').close() for i in range(num_tries): try: browser_to_create = browser_finder.FindBrowser(finder_options) self._browser = browser_to_create.Create(finder_options) if utils.is_arc_available(): if disable_arc_opt_in: if arc_util.should_start_arc(arc_mode): arc_util.enable_play_store(self.autotest_ext) else: arc_util.opt_in(self.browser, self.autotest_ext) arc_util.post_processing_after_browser(self) break except exceptions.LoginException as e: logging.error('Timed out logging in, tries=%d, error=%s', i, repr(e)) if i == num_tries - 1: raise if init_network_controller: self._browser.platform.network_controller.InitializeIfNeeded()
def GetExtensionToLoad(self, ext_path): extension_path = os.path.join(util.GetUnittestDataDir(), ext_path) return extension_to_load.ExtensionToLoad( extension_path, self._options.browser_type)
def __init__(self, logged_in=True, extension_paths=[], autotest_ext=False, is_component=True, num_tries=3, extra_browser_args=None, clear_enterprise_policy=True, dont_override_profile=False, disable_gaia_services=True, disable_default_apps = True, auto_login=True, gaia_login=False, username=None, password=None, gaia_id=None): """ Constructor of telemetry wrapper. @param logged_in: Regular user (True) or guest user (False). @param extension_paths: path of unpacked extension to install. @param autotest_ext: Load a component extension with privileges to invoke chrome.autotestPrivate. @param is_component: Whether extensions should be loaded as component extensions. @param num_tries: Number of attempts to log in. @param extra_browser_args: Additional argument(s) to pass to the browser. It can be a string or a list. @param clear_enterprise_policy: Clear enterprise policy before logging in. @param dont_override_profile: Don't delete cryptohome before login. Telemetry will output a warning with this option. @param disable_gaia_services: For enterprise autotests, this option may be used to enable policy fetch. @param disable_default_apps: For tests that exercise default apps. @param auto_login: Does not login automatically if this is False. Useful if you need to examine oobe. @param gaia_login: Logs in to real gaia. @param username: Log in using this username instead of the default. @param password: Log in using this password instead of the default. @param gaia_id: Log in using this gaia_id instead of the default. """ self._autotest_ext_path = None if autotest_ext: self._autotest_ext_path = os.path.join(os.path.dirname(__file__), 'autotest_private_ext') extension_paths.append(self._autotest_ext_path) finder_options = browser_options.BrowserFinderOptions() self._browser_type = (self.BROWSER_TYPE_LOGIN if logged_in else self.BROWSER_TYPE_GUEST) finder_options.browser_type = self.browser_type if extra_browser_args: finder_options.browser_options.AppendExtraBrowserArgs( extra_browser_args) if logged_in: extensions_to_load = finder_options.extensions_to_load for path in extension_paths: extension = extension_to_load.ExtensionToLoad( path, self.browser_type, is_component=is_component) extensions_to_load.append(extension) self._extensions_to_load = extensions_to_load # finder options must be set before parse_args(), browser options must # be set before Create(). # TODO(crbug.com/360890) Below MUST be '2' so that it doesn't inhibit # autotest debug logs finder_options.verbosity = 2 finder_options.CreateParser().parse_args(args=[]) b_options = finder_options.browser_options b_options.disable_component_extensions_with_background_pages = False b_options.create_browser_with_oobe = True b_options.clear_enterprise_policy = clear_enterprise_policy b_options.dont_override_profile = dont_override_profile b_options.disable_gaia_services = disable_gaia_services b_options.disable_default_apps = disable_default_apps b_options.disable_component_extensions_with_background_pages = disable_default_apps b_options.auto_login = auto_login b_options.gaia_login = gaia_login self.username = b_options.username if username is None else username self.password = b_options.password if password is None else password b_options.username = self.username b_options.password = self.password # gaia_id will be added to telemetry code in chromium repository later try: self.gaia_id = b_options.gaia_id if gaia_id is None else gaia_id b_options.gaia_id = self.gaia_id except AttributeError: pass # Turn on collection of Chrome coredumps via creation of a magic file. # (Without this, Chrome coredumps are trashed.) open(constants.CHROME_CORE_MAGIC_FILE, 'w').close() for i in range(num_tries): try: browser_to_create = browser_finder.FindBrowser(finder_options) self._browser = browser_to_create.Create(finder_options) break except (exceptions.LoginException) as e: logging.error('Timed out logging in, tries=%d, error=%s', i, repr(e)) if i == num_tries-1: raise