Add an extension capability for adding targets
This is meant to facilitate anything else that wants to look at the subunit stream and do something with it. The unit test for main is simply intended to ensure that found targets are passed in to the reader. The unit test for ReadSubunit verifies that any targets passed in are in fact copied into the final result processor. Change-Id: I5200521a3c33d61ea4e4af8cfa900eff2c698355 Implements: counter-inspection
This commit is contained in:
parent
8af81fea4a
commit
35b10a9de7
18
doc/source/target-extensions.rst
Normal file
18
doc/source/target-extensions.rst
Normal file
@ -0,0 +1,18 @@
|
||||
=================
|
||||
Target Extensions
|
||||
=================
|
||||
|
||||
Subunit2SQL is meant to be generic. But while processing subunit streams,
|
||||
you may have some site-specific behavior you'd like to enable, such as
|
||||
loading attachments into a storage location that can be extracted later.
|
||||
|
||||
To do this, you must create a plugin in the `subunit2sql.target` entry
|
||||
point namespace, and it will be invoked along with the other targets
|
||||
that subunit2sql invokes normally to store tests in a SQL database.
|
||||
|
||||
The plugin's entry point should be a class that extends
|
||||
`testtools.StreamResult`. It should also add a class method, `enabled`,
|
||||
which returns False if the plugin has no chance of functioning. The
|
||||
`enabled` method can also do any configuration file preparation if you
|
||||
are using oslo.config. The constructor will not be executed until after
|
||||
all config options are loaded.
|
@ -33,14 +33,18 @@ def get_duration(start, end):
|
||||
|
||||
class ReadSubunit(object):
|
||||
|
||||
def __init__(self, stream_file, attachments=False, attr_regex=None):
|
||||
def __init__(self, stream_file, attachments=False, attr_regex=None,
|
||||
targets=None):
|
||||
if targets is None:
|
||||
targets = []
|
||||
self.stream_file = stream_file
|
||||
self.stream = subunit.ByteStreamToStreamResult(stream_file)
|
||||
starts = testtools.StreamResult()
|
||||
summary = testtools.StreamSummary()
|
||||
outcomes = testtools.StreamToDict(functools.partial(
|
||||
self.parse_outcome))
|
||||
self.result = testtools.CopyStreamResult([starts, outcomes, summary])
|
||||
targets.extend([starts, outcomes, summary])
|
||||
self.result = testtools.CopyStreamResult(targets)
|
||||
self.results = {}
|
||||
self.attachments = attachments
|
||||
if attr_regex:
|
||||
|
@ -19,6 +19,7 @@ import sys
|
||||
from oslo_config import cfg
|
||||
from oslo_db import options
|
||||
from pbr import version
|
||||
from stevedore import enabled
|
||||
|
||||
from subunit2sql.db import api
|
||||
from subunit2sql import exceptions
|
||||
@ -182,19 +183,30 @@ def process_results(results):
|
||||
|
||||
def main():
|
||||
cli_opts()
|
||||
|
||||
def check_enabled(ext):
|
||||
return ext.plugin.enabled()
|
||||
extensions = enabled.EnabledExtensionManager('subunit2sql.target',
|
||||
check_func=check_enabled)
|
||||
parse_args(sys.argv)
|
||||
try:
|
||||
targets = list(extensions.map(lambda ext: ext.plugin()))
|
||||
except RuntimeError:
|
||||
targets = []
|
||||
if CONF.subunit_files:
|
||||
if len(CONF.subunit_files) > 1 and CONF.run_id:
|
||||
print("You can not specify a run id for adding more than 1 stream")
|
||||
return 3
|
||||
streams = [subunit.ReadSubunit(open(s, 'r'),
|
||||
attachments=CONF.store_attachments,
|
||||
attr_regex=CONF.attr_regex)
|
||||
attr_regex=CONF.attr_regex,
|
||||
targets=targets)
|
||||
for s in CONF.subunit_files]
|
||||
else:
|
||||
streams = [subunit.ReadSubunit(sys.stdin,
|
||||
attachments=CONF.store_attachments,
|
||||
attr_regex=CONF.attr_regex)]
|
||||
attr_regex=CONF.attr_regex,
|
||||
targets=targets)]
|
||||
for stream in streams:
|
||||
process_results(stream.get_results())
|
||||
|
||||
|
@ -170,3 +170,8 @@ class TestReadSubunit(base.TestCase):
|
||||
test_name = read.cleanup_test_name(fake_id, strip_tags=True,
|
||||
strip_scenarios=False)
|
||||
self.assertEqual(fake_id, test_name)
|
||||
|
||||
@mock.patch('testtools.CopyStreamResult')
|
||||
def test_targets_added_to_result(self, ttc_mock):
|
||||
subunit.ReadSubunit(mock.MagicMock(), targets=['foo'])
|
||||
self.assertIn('foo', ttc_mock.call_args[0][0])
|
||||
|
@ -156,7 +156,8 @@ class TestMain(base.TestCase):
|
||||
shell.main()
|
||||
read_subunit_mock.assert_called_once_with(sys.stdin,
|
||||
attachments=False,
|
||||
attr_regex='\[(.*)\]')
|
||||
attr_regex='\[(.*)\]',
|
||||
targets=[])
|
||||
process_results_mock.assert_called_once_with(fake_get_results)
|
||||
|
||||
@mock.patch('subunit2sql.read_subunit.ReadSubunit')
|
||||
@ -165,8 +166,8 @@ class TestMain(base.TestCase):
|
||||
read_subunit_mock):
|
||||
tfile1 = tempfile.NamedTemporaryFile()
|
||||
tfile2 = tempfile.NamedTemporaryFile()
|
||||
tfile1.write('test me later 1')
|
||||
tfile2.write('test me later 2')
|
||||
tfile1.write(b'test me later 1')
|
||||
tfile2.write(b'test me later 2')
|
||||
tfile1.flush()
|
||||
tfile2.flush()
|
||||
self.fake_args.extend([tfile1.name, tfile2.name])
|
||||
@ -180,17 +181,36 @@ class TestMain(base.TestCase):
|
||||
shell.main()
|
||||
read_subunit_mock.assert_called_with(mock.ANY,
|
||||
attachments=False,
|
||||
attr_regex='\[(.*)\]')
|
||||
attr_regex='\[(.*)\]',
|
||||
targets=[])
|
||||
self.assertEqual(2, len(read_subunit_mock.call_args_list))
|
||||
file_1 = read_subunit_mock.call_args_list[0][0][0]
|
||||
self.assertIsInstance(file_1, file)
|
||||
file_1.seek(0)
|
||||
self.assertEqual('test me later 1', file_1.read())
|
||||
file_2 = read_subunit_mock.call_args_list[1][0][0]
|
||||
self.assertIsInstance(file_2, file)
|
||||
file_2.seek(0)
|
||||
self.assertEqual('test me later 2', file_2.read())
|
||||
self.assertEqual(fake_get_results_1,
|
||||
process_results_mock.call_args_list[0][0][0])
|
||||
self.assertEqual(fake_get_results_2,
|
||||
process_results_mock.call_args_list[1][0][0])
|
||||
|
||||
@mock.patch('stevedore.enabled.EnabledExtensionManager')
|
||||
@mock.patch('subunit2sql.read_subunit.ReadSubunit')
|
||||
@mock.patch('subunit2sql.shell.process_results')
|
||||
def test_main_with_targets(self, process_results_mock, read_subunit_mock,
|
||||
ext_mock):
|
||||
exts = mock.MagicMock('EnabledExtensionManager()')
|
||||
ext_mock.return_value = exts
|
||||
exts.map = mock.MagicMock('extensions.map')
|
||||
exts.map.return_value = [mock.sentinel.extension]
|
||||
fake_read_subunit = mock.MagicMock('ReadSubunit')
|
||||
fake_get_results = 'fake results'
|
||||
fake_read_subunit.get_results = mock.MagicMock('get_results')
|
||||
fake_read_subunit.get_results.return_value = fake_get_results
|
||||
read_subunit_mock.return_value = fake_read_subunit
|
||||
shell.main()
|
||||
read_subunit_mock.assert_called_once_with(
|
||||
sys.stdin, attachments=False, attr_regex='\[(.*)\]',
|
||||
targets=[mock.sentinel.extension])
|
||||
process_results_mock.assert_called_once_with(fake_get_results)
|
||||
|
Loading…
Reference in New Issue
Block a user