Add subunit2sql CLI option to use non_subunit_name
This commit adds a new CLI option for allowing mixed subunit content. This is desired for subunit.stream files with non-subunit content mixed in but still want the subunit content converted to sql. However, this commit only adds support for passing the argument to ByteStreamToStreamResult. Nothing is added beyond that for managing the non-subunit content. Co-Authored-By: Matthew Treinish <mtreinish@kortar.org> Change-Id: I68cbeb47e9093b98630f096fc5818a77932c8da4
This commit is contained in:
parent
37fc3f5f38
commit
fed81d0901
@ -49,6 +49,10 @@ path that points to any logs or other external test artifacts related to the
|
|||||||
run being added. The run_meta option takes in a dictionary which will be added
|
run being added. The run_meta option takes in a dictionary which will be added
|
||||||
to the database as key value pairs associated with the run being added.
|
to the database as key value pairs associated with the run being added.
|
||||||
|
|
||||||
|
If you want to use a subunit stream with non-subunit data mixed in you can do
|
||||||
|
this with the optional argument --non_subunit_name. This will treat all the
|
||||||
|
non-subunit data as a file attachment with the specified name.
|
||||||
|
|
||||||
.. _sql2subunit:
|
.. _sql2subunit:
|
||||||
|
|
||||||
sql2subunit
|
sql2subunit
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- A new option is added to the subunit2sql CLI command,
|
||||||
|
--non_subunit_name, that is used to allow subunit files with
|
||||||
|
mixed content. The default is to raise an error containing the
|
||||||
|
non-subunit byte after it has been read from the stream. By
|
||||||
|
using this new option, the error will not be raised.
|
@ -34,14 +34,17 @@ def get_duration(start, end):
|
|||||||
class ReadSubunit(object):
|
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, use_wall_time=False):
|
targets=None, use_wall_time=False, non_subunit_name=None):
|
||||||
if targets is None:
|
if targets is None:
|
||||||
targets = []
|
targets = []
|
||||||
else:
|
else:
|
||||||
targets = targets[:]
|
targets = targets[:]
|
||||||
self.use_wall_time = use_wall_time
|
self.use_wall_time = use_wall_time
|
||||||
self.stream_file = stream_file
|
self.stream_file = stream_file
|
||||||
self.stream = subunit.ByteStreamToStreamResult(self.stream_file)
|
self.stream = subunit.ByteStreamToStreamResult(
|
||||||
|
self.stream_file,
|
||||||
|
non_subunit_name=non_subunit_name
|
||||||
|
)
|
||||||
starts = testtools.StreamResult()
|
starts = testtools.StreamResult()
|
||||||
summary = testtools.StreamSummary()
|
summary = testtools.StreamSummary()
|
||||||
outcomes = testtools.StreamToDict(functools.partial(
|
outcomes = testtools.StreamToDict(functools.partial(
|
||||||
|
@ -60,6 +60,9 @@ SHELL_OPTS = [
|
|||||||
help="When True the wall time of a run will be used for the "
|
help="When True the wall time of a run will be used for the "
|
||||||
"run_time column in the runs table. By default the sum of"
|
"run_time column in the runs table. By default the sum of"
|
||||||
" the test executions are used instead."),
|
" the test executions are used instead."),
|
||||||
|
cfg.StrOpt('non_subunit_name', default=None,
|
||||||
|
help='Allows non-subunit content and stores it under this'
|
||||||
|
' name'),
|
||||||
]
|
]
|
||||||
|
|
||||||
_version_ = version.VersionInfo('subunit2sql').version_string_with_vcs()
|
_version_ = version.VersionInfo('subunit2sql').version_string_with_vcs()
|
||||||
@ -232,14 +235,16 @@ def main():
|
|||||||
attachments=CONF.store_attachments,
|
attachments=CONF.store_attachments,
|
||||||
attr_regex=CONF.attr_regex,
|
attr_regex=CONF.attr_regex,
|
||||||
targets=targets,
|
targets=targets,
|
||||||
use_wall_time=CONF.use_run_wall_time)
|
use_wall_time=CONF.use_run_wall_time,
|
||||||
|
non_subunit_name=CONF.non_subunit_name)
|
||||||
for s in CONF.subunit_files]
|
for s in CONF.subunit_files]
|
||||||
else:
|
else:
|
||||||
streams = [subunit.ReadSubunit(sys.stdin,
|
streams = [subunit.ReadSubunit(sys.stdin,
|
||||||
attachments=CONF.store_attachments,
|
attachments=CONF.store_attachments,
|
||||||
attr_regex=CONF.attr_regex,
|
attr_regex=CONF.attr_regex,
|
||||||
targets=targets,
|
targets=targets,
|
||||||
use_wall_time=CONF.use_run_wall_time)]
|
use_wall_time=CONF.use_run_wall_time,
|
||||||
|
non_subunit_name=CONF.non_subunit_name)]
|
||||||
for stream in streams:
|
for stream in streams:
|
||||||
process_results(stream.get_results())
|
process_results(stream.get_results())
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import datetime
|
|||||||
import io
|
import io
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
import subunit as subunit_lib
|
||||||
|
|
||||||
from subunit2sql import read_subunit as subunit
|
from subunit2sql import read_subunit as subunit
|
||||||
from subunit2sql.tests import base
|
from subunit2sql.tests import base
|
||||||
@ -215,3 +216,31 @@ class TestReadSubunit(base.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(ntargets1, ntargets2)
|
self.assertEqual(ntargets1, ntargets2)
|
||||||
self.assertEqual(targets, ['foo'])
|
self.assertEqual(targets, ['foo'])
|
||||||
|
|
||||||
|
def test_non_subunit_name(self):
|
||||||
|
non_subunit_name = 'fake_non_subunit'
|
||||||
|
fake_subunit = subunit.ReadSubunit(mock.MagicMock(),
|
||||||
|
non_subunit_name=non_subunit_name)
|
||||||
|
self.assertEqual(fake_subunit.stream.non_subunit_name,
|
||||||
|
non_subunit_name)
|
||||||
|
|
||||||
|
def test_not_subunit_no_subunit_name_set(self):
|
||||||
|
stream_buf = io.BytesIO()
|
||||||
|
stream = subunit_lib.StreamResultToBytes(stream_buf)
|
||||||
|
stream.status(test_id='test_a', test_status='inprogress')
|
||||||
|
stream.status(test_id='test_a', test_status='success')
|
||||||
|
stream_buf.write(b'I AM NOT SUBUNIT')
|
||||||
|
stream_buf.seek(0)
|
||||||
|
result = subunit.ReadSubunit(stream_buf)
|
||||||
|
exc_found = False
|
||||||
|
try:
|
||||||
|
result.get_results()
|
||||||
|
# NOTE(mtreinish): Subunit raises the generic Exception class
|
||||||
|
# so manually inspect the Exception object to check the error
|
||||||
|
# message
|
||||||
|
except Exception as e:
|
||||||
|
self.assertIsInstance(e, Exception)
|
||||||
|
self.assertEqual(e.args, ('Non subunit content', b'I'))
|
||||||
|
exc_found = True
|
||||||
|
self.assertTrue(exc_found,
|
||||||
|
'subunit exception not raised on invalid content')
|
||||||
|
@ -159,6 +159,7 @@ class TestMain(base.TestCase):
|
|||||||
read_subunit_mock.assert_called_once_with(sys.stdin,
|
read_subunit_mock.assert_called_once_with(sys.stdin,
|
||||||
attachments=False,
|
attachments=False,
|
||||||
attr_regex='\[(.*)\]',
|
attr_regex='\[(.*)\]',
|
||||||
|
non_subunit_name=None,
|
||||||
targets=[],
|
targets=[],
|
||||||
use_wall_time=False)
|
use_wall_time=False)
|
||||||
process_results_mock.assert_called_once_with(fake_get_results)
|
process_results_mock.assert_called_once_with(fake_get_results)
|
||||||
@ -185,6 +186,7 @@ class TestMain(base.TestCase):
|
|||||||
read_subunit_mock.assert_called_with(mock.ANY,
|
read_subunit_mock.assert_called_with(mock.ANY,
|
||||||
attachments=False,
|
attachments=False,
|
||||||
attr_regex='\[(.*)\]',
|
attr_regex='\[(.*)\]',
|
||||||
|
non_subunit_name=None,
|
||||||
targets=[],
|
targets=[],
|
||||||
use_wall_time=False)
|
use_wall_time=False)
|
||||||
self.assertEqual(2, len(read_subunit_mock.call_args_list))
|
self.assertEqual(2, len(read_subunit_mock.call_args_list))
|
||||||
@ -216,6 +218,7 @@ class TestMain(base.TestCase):
|
|||||||
shell.main()
|
shell.main()
|
||||||
read_subunit_mock.assert_called_once_with(
|
read_subunit_mock.assert_called_once_with(
|
||||||
sys.stdin, attachments=False, attr_regex='\[(.*)\]',
|
sys.stdin, attachments=False, attr_regex='\[(.*)\]',
|
||||||
|
non_subunit_name=None,
|
||||||
targets=[mock.sentinel.extension],
|
targets=[mock.sentinel.extension],
|
||||||
use_wall_time=False)
|
use_wall_time=False)
|
||||||
process_results_mock.assert_called_once_with(fake_get_results)
|
process_results_mock.assert_called_once_with(fake_get_results)
|
||||||
|
Loading…
Reference in New Issue
Block a user