Fix duplicated details gathering

Change-Id: I153709d642adfed8443b71f333d850d3a2a16050
This commit is contained in:
Federico Ressi 2019-08-21 16:26:14 +02:00
parent 13f92eaec8
commit 6f95a7f4c1
4 changed files with 83 additions and 16 deletions

View File

@ -45,6 +45,7 @@ cleanup_fixture = _fixture.cleanup_fixture
list_required_fixtures = _fixture.list_required_fixtures
SharedFixture = _fixture.SharedFixture
FixtureManager = _fixture.FixtureManager
details_content = _fixture.details_content
CaptureLogTest = _logging.CaptureLogTest
CaptureLogFixture = _logging.CaptureLogFixture

View File

@ -15,11 +15,13 @@ from __future__ import absolute_import
import os
import inspect
import itertools
import fixtures
from oslo_log import log
import six
import testtools
from testtools import content
import tobiko
@ -431,7 +433,67 @@ class RequiredSetupFixtureProperty(RequiredFixtureProperty):
fixture = setup_fixture(self.fixture)
if (hasattr(_instance, 'addCleanup') and
hasattr(_instance, 'getDetails')):
_instance.addCleanup(testtools.testcase.gather_details,
fixture.getDetails(),
_instance.addCleanup(gather_details, fixture.getDetails(),
_instance.getDetails())
return fixture
def gather_details(source_dict, target_dict):
"""Merge the details from ``source_dict`` into ``target_dict``.
``gather_details`` evaluates all details in ``source_dict``. Do not use it
if the details are not ready to be evaluated.
:param source_dict: A dictionary of details will be gathered.
:param target_dict: A dictionary into which details will be gathered.
"""
for name, content_object in source_dict.items():
disambiguator = itertools.count(1)
content_id = get_details_content_id(content_object)
new_name = name
while new_name in target_dict:
if content_id == get_details_content_id(target_dict[new_name]):
break
new_name = '{!s}-{!s}'.format(name, next(disambiguator))
if new_name not in target_dict:
target_dict[new_name] = copy_details_content(
content_object=content_object, content_id=content_id)
testtools.testcase.gather_details = gather_details
def copy_details_content(content_object, content_id):
content_bytes = list(content_object.iter_bytes())
return details_content(content_type=content_object.content_type,
get_bytes=lambda: content_bytes,
content_id=content_id)
def details_content(content_id, get_bytes=None, get_text=None,
content_type=None):
content_type = content_type or content.UTF8_TEXT
get_bytes = get_bytes or get_text_to_get_bytes(get_text)
content_object = content.Content(
content_type=content_type,
get_bytes=get_bytes)
content_object.content_id = content_id
return content_object
def get_text_to_get_bytes(get_text):
assert callable(get_text)
def get_bytes():
for t in get_text():
yield t.encode()
return get_bytes
def get_details_content_id(content_object):
try:
return content_object.content_id
except AttributeError:
return id(content_object)

View File

@ -45,8 +45,13 @@ class CaptureLogFixture(_fixture.SharedFixture):
self.addCleanup(self.logger.removeHandler, handler)
def getDetails(self):
if self.handler:
return {'log': self.handler.content}
handler = self.handler
if handler:
content_object = _fixture.details_content(
content_type=content.UTF8_TEXT,
content_id=self.fixture_name,
get_text=handler.format_all)
return {'log': content_object}
else:
return {}
@ -67,13 +72,9 @@ class CaptureLogHandler(logging.Handler):
def emit(self, record):
self.records.append(record)
@property
def content(self):
return content.Content(content.UTF8_TEXT, self.format_all)
def format_all(self):
for record in self.records:
yield (self.format(record) + '\n').encode()
yield self.format(record) + '\n'
class CaptureLogTest(testtools.TestCase):

View File

@ -18,7 +18,6 @@ from __future__ import absolute_import
import os
import six
from testtools import content
import tobiko
from tobiko import config
@ -179,12 +178,16 @@ class ServerStackFixture(heat.HeatStackFixture):
max_console_output_length = 64 * 1024
def getDetails(self):
server_id = content.Content(
content.UTF8_TEXT, lambda: [self.server_id.encode()])
console_output = content.Content(
content.UTF8_TEXT, lambda: [self.console_output.encode()])
return {self.stack_name + '.server_id': server_id,
self.stack_name + '.console_output': console_output}
return {
'server_console_output': tobiko.details_content(
content_id=self.fixture_name,
get_text=self._get_server_console_output_text)}
def _get_server_console_output_text(self):
yield 'Server Console Output [server_id=' + self.server_id + ']:\n'
yield '-' * 80 + '\n'
yield self.console_output
yield '-' * 80 + '\n'
@property
def console_output(self):