class Session(object): """A session context manager which is a key controller in airgun. It is responsible for initializing and starting :class:`airgun.browser.AirgunBrowser`, navigating to satellite, performing post-init browser tweaks, initializing navigator, all available UI entities, and logging in to satellite. When session is about to close, it saves a screenshot in case of any exception, attempts to log out from satellite and performs all necessary browser closure steps like quitting the browser, sending results to saucelabs, stopping docker container etc. For tests level it offers direct control over when UI session is started and stopped as well as provides all the entities available without the need to import and initialize them manually. Usage:: def test_foo(): # steps executed before starting UI session # [...] # start of UI session with Session('test_foo') as session: # steps executed during UI session. For example: session.architecture.create({'name': 'bar'}) [...] # steps executed after UI session was closed You can also pass credentials different from default ones specified in settings like that:: with Session(test_name, user='******', password='******'): # [...] Every test may use multiple sessions if needed:: def test_foo(): with Session('test_foo', 'admin', 'password') as admin_session: # UI steps, performed by 'admin' user admin_session.user.create({'login': '******', 'password: '******'}) # [...] with Session('test_foo', 'user1', 'pwd1') as user1_session: # UI steps, performed by 'user1' user user1_session.architecture.create({'name': 'bar'}) # [...] Nested sessions are supported as well, just don't forget to use different variables for sessions:: def test_foo(): with Session('test_foo', 'admin', 'password') as admin_session: # UI steps, performed by 'admin' user only admin_session.user.create({'login': '******', 'password: '******'}) # [...] with Session('test_foo', 'user1', 'pwd1') as user1_session: # UI steps, performed by 'user1' user OR 'admin' in # different browser instances user1_session.architecture.create({'name': 'bar'}) admin_session.architecture.search('bar') # [...] # UI steps, performed by 'admin' user only admin_session.user.delete({'login': '******'}) """ def __init__(self, session_name=None, user=None, password=None): """Stores provided values, doesn't perform any actions. :param str optional session_name: string representing session name. Used in screenshot names, saucelabs test results, docker container names etc. You should provide your test name here in most cases. Defaults to random alphanumeric value. :param str optional user: username (login) of user, who will perform UI actions. If None is passed - default one provided by settings will beused. :param str optional password: password for provided user. If None is passed - default one from settings will be used. """ self.name = session_name or gen_string('alphanumeric') self._user = user or settings.satellite.username self._password = password or settings.satellite.password self._factory = None self.browser = None def __enter__(self): """Starts the browser, navigates to satellite, performs post-init browser tweaks, initializes navigator and UI entities, and logs in to satellite. """ LOGGER.info(u'Starting UI session %r for user %r', self.name, self._user) self._factory = SeleniumBrowserFactory(test_name=self.name) selenium_browser = self._factory.get_browser() selenium_browser.maximize_window() self.browser = AirgunBrowser(selenium_browser, self) self.browser.url = 'https://' + settings.satellite.hostname self._factory.post_init() # Navigator self.navigator = copy.deepcopy(navigator) self.navigator.browser = self.browser # Entities self.activationkey = ActivationKeyEntity(self.browser) self.architecture = ArchitectureEntity(self.browser) self.location = LocationEntity(self.browser) self.login = LoginEntity(self.browser) self.operatingsystem = OperatingSystemEntity(self.browser) self.organization = OrganizationEntity(self.browser) self.subnet = SubnetEntity(self.browser) self.login.login({'username': self._user, 'password': self._password}) return self def __exit__(self, exc_type, exc_value, traceback): """Attempts to log out, saves the screenshot and performs all required session closure activities. NOTE: exceptions during logout or saving screenshot are just logged and not risen not to shadow real session result. """ LOGGER.info(u'Stopping UI session %r for user %r', self.name, self._user) passed = True if exc_type is None else False try: if passed: self.login.logout() else: self.take_screenshot() except Exception as err: LOGGER.exception(err) finally: self._factory.finalize(passed) def take_screenshot(self): """Take screen shot from the current browser window. The screenshot named ``screenshot-YYYY-mm-dd_HH_MM_SS.png`` will be placed on the path specified by ``settings.screenshots_path/YYYY-mm-dd/ClassName/method_name/``. All directories will be created if they don't exist. Make sure that the user running robottelo have the right permissions to create files and directories matching the complete. This method is called automatically in case any exception during UI session happens. """ now = datetime.now() path = os.path.join( settings.selenium.screenshots_path, now.strftime('%Y-%m-%d'), ) if not os.path.exists(path): os.makedirs(path) filename = '{0}-screenshot-{1}.png'.format( self.name.replace(' ', '_'), now.strftime('%Y-%m-%d_%H_%M_%S')) path = os.path.join(path, filename) LOGGER.debug('Saving screenshot %s', path) self.browser.selenium.save_screenshot(path)
class Session(object): """A session context manager that manages login and logout""" def __init__(self, test, user=None, password=None): self.test = test self._user = user or settings.satellite.username self._password = password or settings.satellite.password self.browser = None def __enter__(self): selenium_browser = browser() selenium_browser.maximize_window() self.browser = AirgunBrowser(selenium_browser, self) self.browser.url = 'https://' + settings.satellite.hostname # Navigator self.navigator = navigator self.navigator.browser = self.browser # Entities self.architecture = ArchitectureEntity(self.browser) self.login = LoginEntity(self.browser) self.login.login({'username': self._user, 'password': self._password}) return self def __exit__(self, exc_type, exc_value, traceback): try: if exc_type is None: self.login.logout() else: self.take_screenshot() except Exception as err: LOGGER.exception(err) finally: self.browser.selenium.quit() def take_screenshot(self): """Take screen shot from the current browser window. The screenshot named ``screenshot-YYYY-mm-dd_HH_MM_SS.png`` will be placed on the path specified by ``settings.screenshots_path/YYYY-mm-dd/ClassName/method_name/``. All directories will be created if they don't exist. Make sure that the user running robottelo have the right permissions to create files and directories matching the complete. """ # fixme: not tested # Take a screenshot if any exception is raised and the test method is # not in the skipped tests. now = datetime.now() path = os.path.join( settings.selenium.screenshots_path, now.strftime('%Y-%m-%d'), ) if not os.path.exists(path): os.makedirs(path) filename = '{0}-screenshot-{1}.png'.format( self.test.replace(' ', '_'), now.strftime('%Y-%m-%d_%H_%M_%S')) path = os.path.join(path, filename) LOGGER.debug('Saving screenshot %s', path) self.browser.selenium.save_screenshot(path)