diff --git a/openstack_dashboard/test/integration_tests/helpers.py b/openstack_dashboard/test/integration_tests/helpers.py index abd62623a0..323629aa2d 100644 --- a/openstack_dashboard/test/integration_tests/helpers.py +++ b/openstack_dashboard/test/integration_tests/helpers.py @@ -11,8 +11,9 @@ # under the License. import contextlib -import datetime +import logging import os +from six import StringIO import socket import tempfile import time @@ -30,6 +31,8 @@ from openstack_dashboard.test.integration_tests import config from openstack_dashboard.test.integration_tests.pages import loginpage from openstack_dashboard.test.integration_tests.regions import messages +LOGGER = logging.getLogger() +LOGGER.setLevel(logging.DEBUG) ROOT_PATH = os.path.dirname(os.path.abspath(config.__file__)) @@ -80,6 +83,8 @@ 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) @@ -118,22 +123,65 @@ class BaseTestCase(testtools.TestCase): 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) + 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 exceptions_captured(self, label): - contents = [] + def log_exception(self, label): try: - yield contents + yield except Exception: - exc_traceback = traceback.format_exc() - contents.append(testtools.content.text_content(exc_traceback)) - finally: - self.addDetail(label, contents[0]) + self.addDetail( + label, testtools.content.text_content(traceback.format_exc())) @staticmethod def _unwrap_browser_log(_log): @@ -146,20 +194,6 @@ class BaseTestCase(testtools.TestCase): 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. @@ -171,24 +205,6 @@ class BaseTestCase(testtools.TestCase): 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. @@ -196,7 +212,7 @@ class BaseTestCase(testtools.TestCase): 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") + return html_elem.get_attribute("innerHTML").encode("utf-8") def tearDown(self): if os.environ.get('INTEGRATION_TESTS', False): diff --git a/tools/gate/integration/post_test_hook.sh b/tools/gate/integration/post_test_hook.sh index f8dd33ab96..afe1535519 100755 --- a/tools/gate/integration/post_test_hook.sh +++ b/tools/gate/integration/post_test_hook.sh @@ -8,8 +8,8 @@ cd /opt/stack/new/horizon sudo -H -u stack tox -e py27integration retval=$? -if [ -d openstack_dashboard/test/integration_tests/integration_tests_screenshots/ ]; then - cp -r openstack_dashboard/test/integration_tests/integration_tests_screenshots/ /home/jenkins/workspace/gate-horizon-dsvm-integration/ +if [ -d openstack_dashboard/test/integration_tests/test_reports/ ]; then + cp -r openstack_dashboard/test/integration_tests/test_reports/ /home/jenkins/workspace/gate-horizon-dsvm-integration/ fi exit $retval