Attach test logs individually for each test

Reports-Example: Ic35c95e720211bce8659baeb0cd4470308e25ea4

Change-Id: Ie5d972d2a560d4f59666c49dc3bf22fdb48071e8
Depends-On: I124973d9adbaaacf5d3429e6f6684f15de27dc7f
Closes-Bug: #1572999
This commit is contained in:
Sergei Chipiga 2016-04-19 18:31:08 +03:00
parent 4ec8b211f6
commit 4619696ec4
2 changed files with 62 additions and 46 deletions

View File

@ -11,8 +11,9 @@
# under the License. # under the License.
import contextlib import contextlib
import datetime import logging
import os import os
from six import StringIO
import socket import socket
import tempfile import tempfile
import time 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.pages import loginpage
from openstack_dashboard.test.integration_tests.regions import messages 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__)) ROOT_PATH = os.path.dirname(os.path.abspath(config.__file__))
@ -80,6 +83,8 @@ class BaseTestCase(testtools.TestCase):
CONFIG = config.get_config() CONFIG = config.get_config()
def setUp(self): def setUp(self):
self._configure_log()
if not os.environ.get('INTEGRATION_TESTS', False): if not os.environ.get('INTEGRATION_TESTS', False):
msg = "The INTEGRATION_TESTS env variable is not set." msg = "The INTEGRATION_TESTS env variable is not set."
raise self.skipException(msg) raise self.skipException(msg)
@ -118,22 +123,65 @@ class BaseTestCase(testtools.TestCase):
self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait) self.driver.implicitly_wait(self.CONFIG.selenium.implicit_wait)
self.driver.set_page_load_timeout( self.driver.set_page_load_timeout(
self.CONFIG.selenium.page_timeout) self.CONFIG.selenium.page_timeout)
self.addOnException(self._dump_page_html_source) self.addOnException(self._attach_page_source)
self.addOnException(self._dump_browser_log) self.addOnException(self._attach_screenshot)
self.addOnException(self._save_screenshot) self.addOnException(self._attach_browser_log)
self.addOnException(self._attach_test_log)
super(BaseTestCase, self).setUp() 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 @contextlib.contextmanager
def exceptions_captured(self, label): def log_exception(self, label):
contents = []
try: try:
yield contents yield
except Exception: except Exception:
exc_traceback = traceback.format_exc() self.addDetail(
contents.append(testtools.content.text_content(exc_traceback)) label, testtools.content.text_content(traceback.format_exc()))
finally:
self.addDetail(label, contents[0])
@staticmethod @staticmethod
def _unwrap_browser_log(_log): def _unwrap_browser_log(_log):
@ -146,20 +194,6 @@ class BaseTestCase(testtools.TestCase):
return log.encode('utf-8') return log.encode('utf-8')
return rec(_log) 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): def zoom_out(self, times=3):
"""Zooming out prevents different elements being driven out of xvfb """Zooming out prevents different elements being driven out of xvfb
viewport (which in Selenium>=2.50.1 prevents interaction with them. 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).send_keys(*zoom_out_keys).key_up(
keys.Keys.CONTROL).perform() 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): def _get_page_html_source(self):
"""Gets html page source. """Gets html page source.
@ -196,7 +212,7 @@ class BaseTestCase(testtools.TestCase):
display html code generated/changed by javascript. display html code generated/changed by javascript.
""" """
html_elem = self.driver.find_element_by_tag_name("html") 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): def tearDown(self):
if os.environ.get('INTEGRATION_TESTS', False): if os.environ.get('INTEGRATION_TESTS', False):

View File

@ -8,8 +8,8 @@ cd /opt/stack/new/horizon
sudo -H -u stack tox -e py27integration sudo -H -u stack tox -e py27integration
retval=$? retval=$?
if [ -d openstack_dashboard/test/integration_tests/integration_tests_screenshots/ ]; then if [ -d openstack_dashboard/test/integration_tests/test_reports/ ]; then
cp -r openstack_dashboard/test/integration_tests/integration_tests_screenshots/ /home/jenkins/workspace/gate-horizon-dsvm-integration/ cp -r openstack_dashboard/test/integration_tests/test_reports/ /home/jenkins/workspace/gate-horizon-dsvm-integration/
fi fi
exit $retval exit $retval