def video_recorder(test_case):
    recorder = VideoRecorder()
    recorder.start()

    yield recorder

    LOGGER.info("Stop video recording")
    recorder.stop()

    if test_case.is_failed:
        if os.path.isfile(recorder.file_path):
            with test_case.log_exception("Attach video"):
                shutil.move(recorder.file_path,
                            os.path.join(test_case._test_report_dir,
                                         'video.mp4'))
        else:
            LOGGER.warn(
                "Can't move video from {!r}".format(recorder.file_path))
    else:
        recorder.clear()
예제 #2
0
파일: helpers.py 프로젝트: amotoki/horizon
class BaseTestCase(testtools.TestCase):

    CONFIG = config.get_config()

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

        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 _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 = 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")
예제 #3
0
파일: helpers.py 프로젝트: amotoki/horizon
    def setUp(self):
        if not os.environ.get('INTEGRATION_TESTS', False):
            raise self.skipException(
                "The INTEGRATION_TESTS env variable is not set.")

        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()
예제 #4
0
    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()
예제 #5
0
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 = 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")