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()
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")
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 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()
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")