예제 #1
0
 def setUp(self):
     if os.environ.get('INTEGRATION_TESTS', False):
         self.driver = selenium.webdriver.Firefox()
         self.conf = config.get_config()
     else:
         msg = "The INTEGRATION_TESTS env variable is not set."
         raise self.skipException(msg)
     super(BaseTestCase, self).setUp()
예제 #2
0
파일: helpers.py 프로젝트: CLisa/horizon
 def setUp(self):
     if os.environ.get('INTEGRATION_TESTS', False):
         self.driver = selenium.webdriver.Firefox()
         self.conf = config.get_config()
     else:
         msg = "The INTEGRATION_TESTS env variable is not set."
         raise self.skipException(msg)
     super(BaseTestCase, self).setUp()
예제 #3
0
class StacksPage(basepage.BaseNavigationPage):
    DEFAULT_TEMPLATE_SOURCE = 'raw'

    CONFIG = config.get_config()
    DEFAULT_PASSWORD = CONFIG.identity.admin_password
    STACKS_TABLE_NAME_COLUMN = 'name'
    STACKS_TABLE_STATUS_COLUMN = 'stack_status'

    def __init__(self, driver, conf):
        super(StacksPage, self).__init__(driver, conf)
        self._page_title = "Stacks"

    @property
    def stacks_table(self):
        return StacksTable(self.driver, self.conf)

    def _get_row_with_stack_name(self, name):
        return self.stacks_table.get_row(self.STACKS_TABLE_NAME_COLUMN, name)

    def create_stack(self,
                     stack_name,
                     template_data,
                     template_source=DEFAULT_TEMPLATE_SOURCE,
                     environment_source=None,
                     environment_upload=None,
                     timeout_mins=None,
                     enable_rollback=None,
                     password=DEFAULT_PASSWORD):
        select_template_form = self.stacks_table.select_template()
        select_template_form.template_source.value = template_source
        select_template_form.template_data.text = template_data
        select_template_form.submit()
        launch_stack_form = self.stacks_table.launch_stack()
        launch_stack_form.stack_name.text = stack_name
        launch_stack_form.password.text = password
        launch_stack_form.submit()

    def delete_stack(self, name):
        row = self._get_row_with_stack_name(name)
        row.mark()
        confirm_delete_stacks_form = self.stacks_table.delete_stack()
        confirm_delete_stacks_form.submit()

    def is_stack_present(self, name):
        return bool(self._get_row_with_stack_name(name))

    def is_stack_create_complete(self, name):
        def cell_getter():
            row = self._get_row_with_stack_name(name)
            return row and row.cells[self.STACKS_TABLE_STATUS_COLUMN]

        return bool(
            self.stacks_table.wait_cell_status(cell_getter, 'Create Complete'))

    def is_stack_deleted(self, name):
        return self.stacks_table.is_row_deleted(
            lambda: self._get_row_with_stack_name(name))
예제 #4
0
class BaseTestCase(testtools.TestCase):

    CONFIG = config.get_config()

    def setUp(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            # Start a virtual display server for running the tests headless.
            if os.environ.get('SELENIUM_HEADLESS', False):
                self.vdisplay = xvfbwrapper.Xvfb(width=1280, height=720)
                # workaround for memory leak in Xvfb taken from: http://blog.
                # jeffterrace.com/2012/07/xvfb-memory-leak-workaround.html
                self.vdisplay.xvfb_cmd.append("-noreset")
                # disables X access control
                self.vdisplay.xvfb_cmd.append("-ac")
                self.vdisplay.start()
            # Start the Selenium webdriver and setup configuration.
            self.driver = webdriver.WebDriverWrapper()
            self.driver.maximize_window()
            self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait)
            self.driver.set_page_load_timeout(
                self.CONFIG.selenium.page_timeout)
            self.addOnException(self._dump_page_html_source)
        else:
            msg = "The INTEGRATION_TESTS env variable is not set."
            raise self.skipException(msg)
        super(BaseTestCase, self).setUp()

    def _dump_page_html_source(self, exc_info):
        content = None
        try:
            pg_source = self._get_page_html_source()
            content = testtools.content.Content(
                testtools.content_type.ContentType('text', 'html'),
                lambda: pg_source)
        except Exception:
            exc_traceback = traceback.format_exc()
            content = testtools.content.text_content(exc_traceback)
        finally:
            self.addDetail("PageHTMLSource.html", content)

    def _get_page_html_source(self):
        """Gets html page source.

        self.driver.page_source is not used on purpose because it does not
        display html code generated/changed by javascript.
        """

        html_elem = self.driver.find_element_by_tag_name("html")
        return html_elem.get_attribute("innerHTML").encode("UTF-8")

    def tearDown(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            self.driver.quit()
        if hasattr(self, 'vdisplay'):
            self.vdisplay.stop()
        super(BaseTestCase, self).tearDown()
 def actual_decoration(obj):
     skip_method = _get_skip_method(obj)
     # get available services from configuration
     avail_services = config.get_config().service_available
     for req_service in req_services:
         if not getattr(avail_services, req_service, False):
             obj = skip_method(obj, "%s service is required for this test"
                                    " to work properly." % req_service)
             break
     return obj
def _parse_compound_config_option_value(option_name):
    """Parses the value of a given config option where option's section name is
    separated from option name by '.'.
    """
    name_parts = option_name.split('.')
    name_parts.reverse()
    option = config.get_config()
    while name_parts:
        option = getattr(option, name_parts.pop())
    return option
예제 #7
0
파일: helpers.py 프로젝트: PFZheng/horizon
 def setUp(self):
     if os.environ.get('INTEGRATION_TESTS', False):
         # Start a virtual display server for running the tests headless.
         if os.environ.get('SELENIUM_HEADLESS', False):
             self.vdisplay = xvfbwrapper.Xvfb(width=1280, height=720)
             self.vdisplay.start()
         # Start the Selenium webdriver and setup configuration.
         self.driver = selenium.webdriver.Firefox()
         self.conf = config.get_config()
     else:
         msg = "The INTEGRATION_TESTS env variable is not set."
         raise self.skipException(msg)
     super(BaseTestCase, self).setUp()
예제 #8
0
 def setUp(self):
     if os.environ.get('INTEGRATION_TESTS', False):
         # Start a virtual display server for running the tests headless.
         if os.environ.get('SELENIUM_HEADLESS', False):
             self.vdisplay = xvfbwrapper.Xvfb(width=1280, height=720)
             self.vdisplay.start()
         # Start the Selenium webdriver and setup configuration.
         self.driver = selenium.webdriver.Firefox()
         self.conf = config.get_config()
     else:
         msg = "The INTEGRATION_TESTS env variable is not set."
         raise self.skipException(msg)
     super(BaseTestCase, self).setUp()
예제 #9
0
 def setUp(self):
     if os.environ.get('INTEGRATION_TESTS', False):
         # Start a virtual display server for running the tests headless.
         if os.environ.get('SELENIUM_HEADLESS', False):
             self.vdisplay = xvfbwrapper.Xvfb(width=1280, height=720)
             self.vdisplay.start()
         # Start the Selenium webdriver and setup configuration.
         self.driver = webdriver.WebDriverWrapper()
         self.driver.maximize_window()
         self.conf = config.get_config()
         self.driver.implicitly_wait(self.conf.dashboard.page_timeout)
     else:
         msg = "The INTEGRATION_TESTS env variable is not set."
         raise self.skipException(msg)
     super(BaseTestCase, self).setUp()
예제 #10
0
 def actual_decoration(obj):
     # make sure that we can decorate method and classes as well
     if inspect.isclass(obj):
         if not _is_test_cls(obj):
             raise ValueError(NOT_TEST_OBJECT_ERROR_MSG)
         skip_method = _mark_class_skipped
     else:
         if not _is_test_method_name(obj.__name__):
             raise ValueError(NOT_TEST_OBJECT_ERROR_MSG)
         skip_method = _mark_method_skipped
     # get available services from configuration
     avail_services = config.get_config().service_available
     for req_service in req_services:
         if not getattr(avail_services, req_service, False):
             obj = skip_method(obj, "%s service is required for this test"
                                    " to work properly." % req_service)
             break
     return obj
예제 #11
0
 def actual_decoration(obj):
     # make sure that we can decorate method and classes as well
     if inspect.isclass(obj):
         if not _is_test_cls(obj):
             raise ValueError(NOT_TEST_OBJECT_ERROR_MSG)
         skip_method = _mark_class_skipped
     else:
         if not _is_test_method_name(obj.__name__):
             raise ValueError(NOT_TEST_OBJECT_ERROR_MSG)
         skip_method = _mark_method_skipped
     # get available services from configuration
     avail_services = config.get_config().service_available
     for req_service in req_services:
         if not getattr(avail_services, req_service, False):
             obj = skip_method(obj, "%s service is required for this test"
                                    " to work properly." % req_service)
             break
     return obj
예제 #12
0
 def setUp(self):
     if os.environ.get('INTEGRATION_TESTS', False):
         # Start a virtual display server for running the tests headless.
         if os.environ.get('SELENIUM_HEADLESS', False):
             self.vdisplay = xvfbwrapper.Xvfb(width=1280, height=720)
             # workaround for memory leak in Xvfb taken from: http://blog.
             # jeffterrace.com/2012/07/xvfb-memory-leak-workaround.html
             self.vdisplay.xvfb_cmd.append("-noreset")
             # disables X access control
             self.vdisplay.xvfb_cmd.append("-ac")
             self.vdisplay.start()
         # Start the Selenium webdriver and setup configuration.
         self.driver = webdriver.WebDriverWrapper()
         self.driver.maximize_window()
         self.conf = config.get_config()
         self.driver.implicitly_wait(self.conf.selenium.implicit_wait)
         self.driver.set_page_load_timeout(self.conf.selenium.page_timeout)
     else:
         msg = "The INTEGRATION_TESTS env variable is not set."
         raise self.skipException(msg)
     super(BaseTestCase, self).setUp()
예제 #13
0
class BaseTestCase(testtools.TestCase):

    CONFIG = config.get_config()

    def setUp(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            # Start a virtual display server for running the tests headless.
            if os.environ.get('SELENIUM_HEADLESS', False):
                self.vdisplay = xvfbwrapper.Xvfb(width=1920, height=1080)
                args = []

                # workaround for memory leak in Xvfb taken from:
                # http://blog.jeffterrace.com/2012/07/xvfb-memory-leak-workaround.html
                args.append("-noreset")

                # disables X access control
                args.append("-ac")

                if hasattr(self.vdisplay, 'extra_xvfb_args'):
                    # xvfbwrapper 0.2.8 or newer
                    self.vdisplay.extra_xvfb_args.extend(args)
                else:
                    self.vdisplay.xvfb_cmd.extend(args)
                self.vdisplay.start()
            # Increase the default Python socket timeout from nothing
            # to something that will cope with slow webdriver startup times.
            # This *just* affects the communication between this test process
            # and the webdriver.
            socket.setdefaulttimeout(60)
            # Start the Selenium webdriver and setup configuration.
            desired_capabilities = dict(webdriver.desired_capabilities)
            desired_capabilities['loggingPrefs'] = {'browser': 'ALL'}
            self.driver = webdriver.WebDriverWrapper(
                desired_capabilities=desired_capabilities)
            if self.CONFIG.selenium.maximize_browser:
                self.driver.maximize_window()
            self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait)
            self.driver.set_page_load_timeout(
                self.CONFIG.selenium.page_timeout)
            self.addOnException(self._dump_page_html_source)
            self.addOnException(self._dump_browser_log)
            self.addOnException(self._save_screenshot)
        else:
            msg = "The INTEGRATION_TESTS env variable is not set."
            raise self.skipException(msg)
        super(BaseTestCase, self).setUp()

    @contextlib.contextmanager
    def exceptions_captured(self, label):
        contents = []
        try:
            yield contents
        except Exception:
            exc_traceback = traceback.format_exc()
            contents.append(testtools.content.text_content(exc_traceback))
        finally:
            self.addDetail(label, contents[0])

    @staticmethod
    def _unwrap_browser_log(_log):
        def rec(log):
            if isinstance(log, dict):
                return log['message'].encode('utf-8')
            elif isinstance(log, list):
                return '\n'.join([rec(item) for item in log])
            else:
                return log.encode('utf-8')

        return rec(_log)

    def _dump_browser_log(self, exc_info):
        with self.exceptions_captured("BrowserLog.text") as contents:
            log = self.driver.get_log('browser')
            contents.append(
                testtools.content.Content(
                    testtools.content_type.UTF8_TEXT,
                    lambda: self._unwrap_browser_log(log)))

    def _dump_page_html_source(self, exc_info):
        with self.exceptions_captured("PageHTMLSource.html") as contents:
            pg_source = self._get_page_html_source()
            contents.append(
                testtools.content.Content(
                    testtools.content_type.ContentType('text', 'html'),
                    lambda: pg_source))

    def zoom_out(self, times=3):
        """Zooming out prevents different elements being driven out of xvfb
        viewport (which in Selenium>=2.50.1 prevents interaction with them.
        """
        html = self.driver.find_element(by.By.TAG_NAME, 'html')
        html.send_keys(keys.Keys.NULL)
        zoom_out_keys = (keys.Keys.SUBTRACT, ) * times
        action_chains.ActionChains(self.driver).key_down(
            keys.Keys.CONTROL).send_keys(*zoom_out_keys).key_up(
                keys.Keys.CONTROL).perform()

    def _save_screenshot(self, exc_info):
        with self.exceptions_captured("Screenshot") as contents:
            filename = self._get_screenshot_filename()
            self.driver.get_screenshot_as_file(filename)
            contents.append(testtools.content.text_content(filename))

    def _get_screenshot_filename(self):
        screenshot_dir = os.path.join(
            ROOT_PATH, self.CONFIG.selenium.screenshots_directory)
        if not os.path.exists(screenshot_dir):
            os.makedirs(screenshot_dir)
        date_string = datetime.datetime.now().strftime('%Y.%m.%d-%H%M%S')
        test_name = self._testMethodName
        name = '%s_%s.png' % (test_name, date_string)
        return os.path.join(screenshot_dir, name)

    def _get_page_html_source(self):
        """Gets html page source.

        self.driver.page_source is not used on purpose because it does not
        display html code generated/changed by javascript.
        """
        html_elem = self.driver.find_element_by_tag_name("html")
        return html_elem.get_attribute("innerHTML").encode("UTF-8")

    def tearDown(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            self.driver.quit()
        if hasattr(self, 'vdisplay'):
            self.vdisplay.stop()
        super(BaseTestCase, self).tearDown()
예제 #14
0
파일: helpers.py 프로젝트: toha10/horizon
class BaseTestCase(testtools.TestCase):

    CONFIG = config.get_config()

    def setUp(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            # Start a virtual display server for running the tests headless.
            if os.environ.get('SELENIUM_HEADLESS', False):
                self.vdisplay = xvfbwrapper.Xvfb(width=1280, height=720)
                # workaround for memory leak in Xvfb taken from: http://blog.
                # jeffterrace.com/2012/07/xvfb-memory-leak-workaround.html
                self.vdisplay.xvfb_cmd.append("-noreset")
                # disables X access control
                self.vdisplay.xvfb_cmd.append("-ac")
                self.vdisplay.start()
            # Start the Selenium webdriver and setup configuration.
            self.driver = webdriver.WebDriverWrapper(
                logging_prefs={'browser': 'ALL'})
            self.driver.maximize_window()
            self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait)
            self.driver.set_page_load_timeout(
                self.CONFIG.selenium.page_timeout)
            self.addOnException(self._dump_page_html_source)
            self.addOnException(self._dump_browser_log)
            self.addOnException(self._save_screenshot)
        else:
            msg = "The INTEGRATION_TESTS env variable is not set."
            raise self.skipException(msg)
        super(BaseTestCase, self).setUp()

    @staticmethod
    def _unwrap_browser_log(_log):
        def rec(log):
            if isinstance(log, dict):
                return log['message'].encode('utf-8')
            elif isinstance(log, list):
                return '\n'.join([rec(item) for item in log])
            else:
                return log.encode('utf-8')

        return rec(_log)

    def _dump_browser_log(self, exc_info):
        content = None
        try:
            log = self.driver.get_log('browser')
            content = testtools.content.Content(
                testtools.content_type.UTF8_TEXT,
                lambda: self._unwrap_browser_log(log))
        except Exception:
            exc_traceback = traceback.format_exc()
            content = testtools.content.text_content(exc_traceback)
        finally:
            self.addDetail("BrowserLog.text", content)

    def _dump_page_html_source(self, exc_info):
        content = None
        try:
            pg_source = self._get_page_html_source()
            content = testtools.content.Content(
                testtools.content_type.ContentType('text', 'html'),
                lambda: pg_source)
        except Exception:
            exc_traceback = traceback.format_exc()
            content = testtools.content.text_content(exc_traceback)
        finally:
            self.addDetail("PageHTMLSource.html", content)

    def _save_screenshot(self, exc_info):
        screenshot_dir = os.path.join(
            ROOT_PATH, self.CONFIG.selenium.screenshots_directory)
        if not os.path.exists(screenshot_dir):
            os.makedirs(screenshot_dir)
        date_string = datetime.datetime.now().strftime('%Y.%m.%d-%H%M%S')
        test_name = self._testMethodName
        name = '%s_%s.png' % (test_name, date_string)
        filename = os.path.join(screenshot_dir, name)
        self.driver.get_screenshot_as_file(filename)
        content = testtools.content.text_content(filename)
        self.addDetail("Screenshot", content)

    def _get_page_html_source(self):
        """Gets html page source.

        self.driver.page_source is not used on purpose because it does not
        display html code generated/changed by javascript.
        """

        html_elem = self.driver.find_element_by_tag_name("html")
        return html_elem.get_attribute("innerHTML").encode("UTF-8")

    def tearDown(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            self.driver.quit()
        if hasattr(self, 'vdisplay'):
            self.vdisplay.stop()
        super(BaseTestCase, self).tearDown()
예제 #15
0
class BaseTestCase(testtools.TestCase):

    CONFIG = config.get_config()

    def setUp(self):
        self._configure_log()

        if not os.environ.get('INTEGRATION_TESTS', False):
            msg = "The INTEGRATION_TESTS env variable is not set."
            raise self.skipException(msg)

        # Start a virtual display server for running the tests headless.
        if os.environ.get('SELENIUM_HEADLESS', False):
            self.vdisplay = xvfbwrapper.Xvfb(width=1920, height=1080)
            args = []

            # workaround for memory leak in Xvfb taken from:
            # http://blog.jeffterrace.com/2012/07/xvfb-memory-leak-workaround.html
            args.append("-noreset")

            # disables X access control
            args.append("-ac")

            if hasattr(self.vdisplay, 'extra_xvfb_args'):
                # xvfbwrapper 0.2.8 or newer
                self.vdisplay.extra_xvfb_args.extend(args)
            else:
                self.vdisplay.xvfb_cmd.extend(args)
            self.vdisplay.start()
        # Increase the default Python socket timeout from nothing
        # to something that will cope with slow webdriver startup times.
        # This *just* affects the communication between this test process
        # and the webdriver.
        socket.setdefaulttimeout(60)
        # Start the Selenium webdriver and setup configuration.
        desired_capabilities = dict(webdriver.desired_capabilities)
        desired_capabilities['loggingPrefs'] = {'browser': 'ALL'}
        self.driver = webdriver.WebDriverWrapper(
            desired_capabilities=desired_capabilities
        )
        if self.CONFIG.selenium.maximize_browser:
            self.driver.maximize_window()
        self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait)
        self.driver.set_page_load_timeout(
            self.CONFIG.selenium.page_timeout)
        self.addOnException(self._attach_page_source)
        self.addOnException(self._attach_screenshot)
        self.addOnException(self._attach_browser_log)
        self.addOnException(self._attach_test_log)

        super(BaseTestCase, self).setUp()

    def _configure_log(self):
        """Configure log to capture test logs include selenium logs in order
        to attach them if test will be broken.
        """
        LOGGER.handlers[:] = []  # clear other handlers to set target handler
        self._log_buffer = StringIO()
        stream_handler = logging.StreamHandler(stream=self._log_buffer)
        stream_handler.setLevel(logging.DEBUG)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        stream_handler.setFormatter(formatter)
        LOGGER.addHandler(stream_handler)

    @property
    def _test_report_dir(self):
        report_dir = os.path.join(ROOT_PATH, 'test_reports',
                                  self._testMethodName)
        if not os.path.isdir(report_dir):
            os.makedirs(report_dir)
        return report_dir

    def _attach_page_source(self, exc_info):
        source_path = os.path.join(self._test_report_dir, 'page.html')
        with self.log_exception("Attach page source"):
            with open(source_path, 'w') as f:
                f.write(self._get_page_html_source())

    def _attach_screenshot(self, exc_info):
        screen_path = os.path.join(self._test_report_dir, 'screenshot.png')
        with self.log_exception("Attach screenshot"):
            self.driver.get_screenshot_as_file(screen_path)

    def _attach_browser_log(self, exc_info):
        browser_log_path = os.path.join(self._test_report_dir, 'browser.log')
        with self.log_exception("Attach browser log"):
            with open(browser_log_path, 'w') as f:
                f.write(
                    self._unwrap_browser_log(self.driver.get_log('browser')))

    def _attach_test_log(self, exc_info):
        test_log_path = os.path.join(self._test_report_dir, 'test.log')
        with self.log_exception("Attach test log"):
            with open(test_log_path, 'w') as f:
                f.write(self._log_buffer.getvalue().encode('utf-8'))

    @contextlib.contextmanager
    def log_exception(self, label):
        try:
            yield
        except Exception:
            self.addDetail(
                label, testtools.content.text_content(traceback.format_exc()))

    @staticmethod
    def _unwrap_browser_log(_log):
        def rec(log):
            if isinstance(log, dict):
                return log['message'].encode('utf-8')
            elif isinstance(log, list):
                return '\n'.join([rec(item) for item in log])
            else:
                return log.encode('utf-8')
        return rec(_log)

    def zoom_out(self, times=3):
        """Zooming out prevents different elements being driven out of xvfb
        viewport (which in Selenium>=2.50.1 prevents interaction with them.
        """
        html = self.driver.find_element(by.By.TAG_NAME, 'html')
        html.send_keys(keys.Keys.NULL)
        zoom_out_keys = (keys.Keys.SUBTRACT,) * times
        action_chains.ActionChains(self.driver).key_down(
            keys.Keys.CONTROL).send_keys(*zoom_out_keys).key_up(
            keys.Keys.CONTROL).perform()

    def _get_page_html_source(self):
        """Gets html page source.

        self.driver.page_source is not used on purpose because it does not
        display html code generated/changed by javascript.
        """
        html_elem = self.driver.find_element_by_tag_name("html")
        return html_elem.get_attribute("innerHTML").encode("utf-8")

    def tearDown(self):
        if os.environ.get('INTEGRATION_TESTS', False):
            self.driver.quit()
        if hasattr(self, 'vdisplay'):
            self.vdisplay.stop()
        super(BaseTestCase, self).tearDown()
예제 #16
0
파일: helpers.py 프로젝트: jcp-read/horizon
class BaseTestCase(testtools.TestCase):

    CONFIG = config.get_config()

    def setUp(self):
        self._configure_log()

        self.addOnException(
            lambda exc_info: setattr(self, '_need_attach_test_log', True))

        def cleanup():
            if getattr(self, '_need_attach_test_log', None):
                self._attach_test_log()

        self.addCleanup(cleanup)

        width, height = SCREEN_SIZE
        display = '0.0'
        # Start a virtual display server for running the tests headless.
        if IS_SELENIUM_HEADLESS:
            width, height = 1920, 1080
            self.vdisplay = xvfbwrapper.Xvfb(width=width, height=height)
            args = []

            # workaround for memory leak in Xvfb taken from:
            # http://blog.jeffterrace.com/2012/07/xvfb-memory-leak-workaround.html
            args.append("-noreset")

            # disables X access control
            args.append("-ac")

            if hasattr(self.vdisplay, 'extra_xvfb_args'):
                # xvfbwrapper 0.2.8 or newer
                self.vdisplay.extra_xvfb_args.extend(args)
            else:
                self.vdisplay.xvfb_cmd.extend(args)
            self.vdisplay.start()
            display = self.vdisplay.new_display

            self.addCleanup(self.vdisplay.stop)

        self.video_recorder = VideoRecorder(width, height, display=display)
        self.video_recorder.start()

        self.addOnException(
            lambda exc_info: setattr(self, '_need_attach_video', True))

        def cleanup():
            self.video_recorder.stop()
            if getattr(self, '_need_attach_video', None):
                self._attach_video()
            else:
                self.video_recorder.clear()

        self.addCleanup(cleanup)

        # Increase the default Python socket timeout from nothing
        # to something that will cope with slow webdriver startup times.
        # This *just* affects the communication between this test process
        # and the webdriver.
        socket.setdefaulttimeout(60)
        # Start the Selenium webdriver and setup configuration.
        desired_capabilities = dict(webdriver.desired_capabilities)
        desired_capabilities['loggingPrefs'] = {'browser': 'ALL'}
        self.driver = webdriver.WebDriverWrapper(
            desired_capabilities=desired_capabilities)
        if self.CONFIG.selenium.maximize_browser:
            self.driver.maximize_window()
            if IS_SELENIUM_HEADLESS:  # force full screen in xvfb
                self.driver.set_window_size(width, height)

        self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait)
        self.driver.set_page_load_timeout(self.CONFIG.selenium.page_timeout)

        self.addOnException(self._attach_page_source)
        self.addOnException(self._attach_screenshot)
        self.addOnException(
            lambda exc_info: setattr(self, '_need_attach_browser_log', True))

        def cleanup():
            if getattr(self, '_need_attach_browser_log', None):
                self._attach_browser_log()
            self.driver.quit()

        self.addCleanup(cleanup)

        super(BaseTestCase, self).setUp()

    def addOnException(self, exception_handler):
        def wrapped_handler(exc_info):
            if issubclass(exc_info[0], testtools.testcase.TestSkipped):
                return
            return exception_handler(exc_info)

        super(BaseTestCase, self).addOnException(wrapped_handler)

    def __hash__(self):
        return hash((type(self), self._testMethodName))

    def _configure_log(self):
        """Configure log to capture test logs include selenium logs.

        This allows us to attach them if test will be broken.
        """
        # clear other handlers to set target handler
        ROOT_LOGGER.handlers[:] = []
        self._log_buffer = io.StringIO()
        stream_handler = logging.StreamHandler(stream=self._log_buffer)
        stream_handler.setLevel(logging.DEBUG)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        stream_handler.setFormatter(formatter)
        ROOT_LOGGER.addHandler(stream_handler)

    @property
    def _test_report_dir(self):
        report_dir = os.path.join(
            ROOT_PATH, 'test_reports', '{}.{}'.format(self.__class__.__name__,
                                                      self._testMethodName))
        if not os.path.isdir(report_dir):
            os.makedirs(report_dir)
        return report_dir

    def _attach_page_source(self, exc_info):
        source_path = os.path.join(self._test_report_dir, 'page.html')
        with self.log_exception("Attach page source"):
            with open(source_path, 'w') as f:
                f.write(self._get_page_html_source())

    def _attach_screenshot(self, exc_info):
        screen_path = os.path.join(self._test_report_dir, 'screenshot.png')
        with self.log_exception("Attach screenshot"):
            self.driver.get_screenshot_as_file(screen_path)

    def _attach_video(self, exc_info=None):
        with self.log_exception("Attach video"):
            if not os.path.isfile(self.video_recorder.file_path):
                LOG.warning("Can't find video %s",
                            self.video_recorder.file_path)
                return

            shutil.move(self.video_recorder.file_path,
                        os.path.join(self._test_report_dir, 'video.mp4'))

    def _attach_browser_log(self, exc_info=None):
        browser_log_path = os.path.join(self._test_report_dir, 'browser.log')
        with self.log_exception("Attach browser log"):
            with open(browser_log_path, 'w') as f:
                f.write(
                    self._unwrap_browser_log(self.driver.get_log('browser')))

    def _attach_test_log(self, exc_info=None):
        test_log_path = os.path.join(self._test_report_dir, 'test.log')
        with self.log_exception("Attach test log"):
            with open(test_log_path, 'w') as f:
                f.write(self._log_buffer.getvalue().encode('utf-8'))

    @contextlib.contextmanager
    def log_exception(self, label):
        try:
            yield
        except Exception:
            self.addDetail(
                label, testtools.content.text_content(traceback.format_exc()))

    @staticmethod
    def _unwrap_browser_log(_log):
        def rec(log):
            if isinstance(log, dict):
                return log['message'].encode('utf-8')
            elif isinstance(log, list):
                return '\n'.join([rec(item) for item in log])
            else:
                return log.encode('utf-8')

        return rec(_log)

    def zoom_out(self, times=3):
        """Zooming out a specified element.

        It prevents different elements being driven out of xvfb viewport
        (which in Selenium>=2.50.1 prevents interaction with them).
        """
        html = self.driver.find_element(by.By.TAG_NAME, 'html')
        html.send_keys(keys.Keys.NULL)
        zoom_out_keys = (keys.Keys.SUBTRACT, ) * times
        action_chains.ActionChains(self.driver).key_down(
            keys.Keys.CONTROL).send_keys(*zoom_out_keys).key_up(
                keys.Keys.CONTROL).perform()

    def _get_page_html_source(self):
        """Gets html page source.

        self.driver.page_source is not used on purpose because it does not
        display html code generated/changed by javascript.
        """
        html_elem = self.driver.find_element_by_tag_name("html")
        return html_elem.get_attribute("innerHTML").encode("utf-8")
예제 #17
0
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
import pytest

from openstack_dashboard.test.integration_tests import config
from openstack_dashboard.test.integration_tests import helpers
from openstack_dashboard.test.integration_tests.regions import messages

CONFIG = config.get_config()


class TestVolumeSnapshotsBasic(helpers.TestCase):
    """Login as demo user"""
    VOLUME_NAME = helpers.gen_random_resource_name("volume")
    VOLUME_SNAPSHOT_NAME = helpers.gen_random_resource_name("volume_snapshot")

    @property
    def volumes_snapshot_page(self):
        return self.home_pg.go_to_project_volumes_snapshotspage()

    def setUp(self):
        """Setup: create volume"""
        super().setUp()
        volumes_page = self.home_pg.go_to_project_volumes_volumespage()
예제 #18
0
class Navigation(object):
    """Provide basic navigation among pages.

    * allows navigation among pages without need to import pageobjects
    * shortest path possible should be always used for navigation to
      specific page as user would navigate in the same manner
    * go_to_*some_page* method respects following pattern:
      * go_to_{sub_menu}_{pagename}page
    * go_to_*some_page* methods are generated at runtime at module import
    * go_to_*some_page* method returns pageobject
    * pages must be located in the correct directories for the navigation
      to work correctly
    * pages modules and class names must respect following pattern
      to work correctly with navigation module:
      * module name consist of menu item in lower case without spaces and '&'
      * page class begins with capital letter and ends with 'Page'

    Examples:
        In order to go to Project/Compute/Overview page, one would have to call
        method go_to_compute_overviewpage()

        In order to go to Admin/System/Overview page, one would have to call
        method go_to_system_overviewpage()

    """
    # constants
    MAX_SUB_LEVEL = 4
    MIN_SUB_LEVEL = 2
    SIDE_MENU_MAX_LEVEL = 3

    CONFIG = config.get_config()
    PAGES_IMPORT_PATH = ["openstack_dashboard.test.integration_tests.pages.%s"]
    if CONFIG.plugin.is_plugin and CONFIG.plugin.plugin_page_path:
        for path in CONFIG.plugin.plugin_page_path:
            PAGES_IMPORT_PATH.append(path + ".%s")

    ITEMS = "_"

    CORE_PAGE_STRUCTURE = \
        {
            "Project":
                {
                    "Compute":
                        {

                            ITEMS:
                                (
                                    "Overview",
                                    "Instances",
                                    "Images",
                                    "Key Pairs",
                                    "Server Groups",
                                )
                        },
                    "Volumes":
                        {
                            ITEMS:
                                (
                                    "Volumes",
                                    "Backups",
                                    "Snapshots",
                                    "Consistency Groups",
                                    "Consistency Group Snapshots",

                                )
                        },
                    "Network":
                        {
                            ITEMS:
                                (
                                    "Network Topology",
                                    "Networks",
                                    "Routers",
                                    "Security Groups",
                                    "Floating IPs",
                                )
                        },
                    ITEMS:
                        (
                            "API Access",
                        )
                },
            "Admin":
                {
                    "Compute":
                        {

                            ITEMS:
                                (
                                    "Hypervisors",
                                    "Host Aggregates",
                                    "Instances",
                                    "Flavors",
                                    "Images",
                                )
                        },
                    "Volume":
                        {
                            ITEMS:
                                (
                                    "Volumes",
                                    "Snapshots",
                                    "Volume Types",

                                )
                        },
                    "Network":
                        {
                            ITEMS:
                                (
                                    "Networks",
                                    "Routers",
                                    "Floating IPs",
                                )
                        },
                    "System":
                        {
                            ITEMS:
                                (
                                    "Defaults",
                                    "Metadata Definitions",
                                    "System Information"
                                )
                        },
                    ITEMS:
                        (
                            "Overview",
                        )
                },

            "Identity":
                {
                    ITEMS:
                        (
                            "Projects",
                            "Users",
                            "Groups",
                            "Roles",
                            "Application Credentials",
                        )
                },
            "Settings":
                {
                    ITEMS:
                        (
                            "User Settings",
                            "Change Password",
                        )
                },
        }
    _main_content_locator = (by.By.ID, 'content_body')

    # protected methods
    def _go_to_page(self, path, page_class=None):
        """Go to page specified via path parameter.

         * page_class parameter overrides basic process for receiving
           pageobject
        """
        path_len = len(path)
        if path_len < self.MIN_SUB_LEVEL or path_len > self.MAX_SUB_LEVEL:
            raise ValueError(
                "Navigation path length should be in the interval"
                " between %s and %s, but its length is %s" %
                (self.MIN_SUB_LEVEL, self.MAX_SUB_LEVEL, path_len))

        if path_len == self.MIN_SUB_LEVEL:
            # menu items that do not contain second layer of menu
            if path[0] == "Settings":
                self._go_to_settings_page(path[1])
            else:
                self._go_to_side_menu_page([path[0], None, path[1]])
        else:
            # side menu contains only three sub-levels
            self._go_to_side_menu_page(path[:self.SIDE_MENU_MAX_LEVEL])

        if path_len == self.MAX_SUB_LEVEL:
            # apparently there is tabbed menu,
            #  because another extra sub level is present
            self._go_to_tab_menu_page(path[self.MAX_SUB_LEVEL - 1])

        # if there is some nonstandard pattern in page object naming
        return self._get_page_class(path, page_class)(self.driver, self.conf)

    def _go_to_tab_menu_page(self, item_text):
        content_body = self.driver.find_element(*self._main_content_locator)
        content_body.find_element_by_link_text(item_text).click()

    def _go_to_settings_page(self, item_text):
        """Go to page that is located under the settings tab."""
        self.topbar.user_dropdown_menu.click_on_settings()
        self.navaccordion.click_on_menu_items(third_level=item_text)

    def _go_to_side_menu_page(self, menu_items):
        """Go to page that is located in the side menu (navaccordion)."""
        self.navaccordion.click_on_menu_items(*menu_items)

    def _get_page_cls_name(self, filename):
        """Gather page class name from path.

         * take last item from path (should be python filename
           without extension)
         * make the first letter capital
         * append 'Page'
         """
        cls_name = "".join((filename.capitalize(), "Page"))
        return cls_name

    def _get_page_class(self, path, page_cls_name):

        # last module name does not contain '_'
        final_module = self.unify_page_path(path[-1], preserve_spaces=False)
        page_cls_path = ".".join(path[:-1] + (final_module, ))
        page_cls_path = self.unify_page_path(page_cls_path)
        # append 'page' as every page module ends with this keyword
        page_cls_path += "page"

        page_cls_name = page_cls_name or self._get_page_cls_name(final_module)

        module = None
        # return imported class
        for path in self.PAGES_IMPORT_PATH:
            try:
                module = importlib.import_module(path % page_cls_path)
                break
            except ImportError:
                pass
        if module is None:
            raise ImportError("Failed to import module: " +
                              (path % page_cls_path))
        return getattr(module, page_cls_name)

    class GoToMethodFactory(object):
        """Represent the go_to_some_page method."""

        METHOD_NAME_PREFIX = "go_to_"
        METHOD_NAME_SUFFIX = "page"
        METHOD_NAME_DELIMITER = "_"

        # private methods
        def __init__(self, path, page_class=None):
            self.path = path
            self.page_class = page_class
            self._name = self._create_name()

        def __call__(self, *args, **kwargs):
            return Navigation._go_to_page(args[0], self.path, self.page_class)

        # protected methods
        def _create_name(self):
            """Create method name.

            * consist of 'go_to_subsubmenu_menuitem_page'
            """
            if len(self.path) < 3:
                path_2_name = list(self.path[-2:])
            else:
                path_2_name = list(self.path[-3:])
            name = self.METHOD_NAME_DELIMITER.join(path_2_name)
            name = self.METHOD_NAME_PREFIX + name + self.METHOD_NAME_SUFFIX
            name = Navigation.unify_page_path(name, preserve_spaces=False)
            return name

        # properties
        @property
        def name(self):
            return self._name

    # classmethods
    @classmethod
    def _initialize_go_to_methods(cls):
        """Create all navigation methods based on the PAGE_STRUCTURE."""
        def rec(items, sub_menus):
            if isinstance(items, dict):
                for sub_menu, sub_item in items.items():
                    rec(sub_item, sub_menus + (sub_menu, ))
            elif isinstance(items, (list, tuple)):
                # exclude ITEMS element from sub_menus
                paths = (sub_menus[:-1] + (menu_item, ) for menu_item in items)
                for path in paths:
                    cls._create_go_to_method(path)

        rec(cls.CORE_PAGE_STRUCTURE, ())
        plugin_page_structure_strings = cls.CONFIG.plugin.plugin_page_structure
        for plugin_ps_string in plugin_page_structure_strings:
            plugin_page_structure = json.loads(plugin_ps_string)
            rec(plugin_page_structure, ())

    @classmethod
    def _create_go_to_method(cls, path, class_name=None):
        go_to_method = Navigation.GoToMethodFactory(path, class_name)
        inst_method = six.create_unbound_method(go_to_method, Navigation)

        # TODO(e0ne): remove python2 support once all integration jobs
        # will be switched to python3.
        if six.PY3:

            def _go_to_page(self, path):
                return Navigation._go_to_page(self, path)

            wrapped_go_to = functools.partialmethod(_go_to_page, path)
            setattr(Navigation, inst_method.name, wrapped_go_to)
        else:
            setattr(Navigation, inst_method.name, inst_method)

    @classmethod
    def unify_page_path(cls, path, preserve_spaces=True):
        """Unify path to page.

        Replace '&' in path with 'and', remove spaces (if not specified
        otherwise) and convert path to lower case.
        """
        path = path.replace("&", "and")
        path = path.lower()
        if preserve_spaces:
            path = path.replace(" ", "_")
        else:
            path = path.replace(" ", "")
        return path
예제 #19
0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from functools import wraps
import logging
import os
import subprocess
import types

from openstack_dashboard.test.integration_tests import config

CONF = config.get_config()
LOGGER = logging.getLogger(__name__)
IS_SELENIUM_HEADLESS = os.environ.get('SELENIUM_HEADLESS', False)


def once_only(func):
    called_funcs = {}

    @wraps(func)
    def wrapper(*args, **kwgs):
        if func.__name__ not in called_funcs:
            result = obj = func(*args, **kwgs)
            if isinstance(obj, types.GeneratorType):

                def gi_wrapper():
                    while True: