From: Simon Marchi Date: Fri, 10 Apr 2020 20:05:25 +0000 (-0400) Subject: tests: add tests for discarded events/packets creation X-Git-Url: http://git.efficios.com/?p=babeltrace.git;a=commitdiff_plain;h=f18c648282cb04162e1cdfb4ff3666b7c3788b7a tests: add tests for discarded events/packets creation Creation of these messages is a bit tested in AllMessagesTestCase, but not everything, especially not the error cases. To avoid code duplication as much as possible, I've added a `run_in_message_iterator_next` helper, similar to the existing `run_in_component_init`. This helper takes a callback to run in the context of a source component's message iterator's __next__method. Individual tests also need to customize the stream class creation, to decide if the stream class supports discarded event/packet messages, clock snapshots on those messages, etc. So it also receives a callback executed in the source component's __init__ method, which must return a stream class. This callback takes a trace class as a parameter, which it will need to create the stream class, and a clock class. It is free to use the clock class as the stream class' default_clock_class or not. Doing this, I noticed that reading the count and clock snapshot properties on a _DiscardedEventsMessage didn't work. This will be fixed in a subsequent patch, in the mean time the corresponding assertions are commented out. Change-Id: I5025d06e6cb5b9d1bbd4372818b391cbc7b5bfa2 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/3391 Tested-by: jenkins Reviewed-by: Philippe Proulx --- diff --git a/tests/bindings/python/bt2/test_message.py b/tests/bindings/python/bt2/test_message.py index 3cadfe1f..76cb1352 100644 --- a/tests/bindings/python/bt2/test_message.py +++ b/tests/bindings/python/bt2/test_message.py @@ -393,5 +393,220 @@ class AllMessagesTestCase(unittest.TestCase): self.assertIs(type(msg.event), bt2_event._Event) +class CreateDiscardedEventMessageTestCase(unittest.TestCase): + # Most basic case. + def test_create(self): + def create_stream_class(tc, cc): + return tc.create_stream_class(supports_discarded_events=True) + + def msg_iter_next(msg_iter, stream): + return msg_iter._create_discarded_events_message(stream) + + msg = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertIs(type(msg), bt2._DiscardedEventsMessage) + # Broken at the moment. + # self.assertIs(msg.count, None) + + # With event count. + def test_create_with_count(self): + def create_stream_class(tc, cc): + return tc.create_stream_class(supports_discarded_events=True) + + def msg_iter_next(msg_iter, stream): + return msg_iter._create_discarded_events_message(stream, count=242) + + msg = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertIs(type(msg), bt2._DiscardedEventsMessage) + # Broken at the moment. + # self.assertEqual(msg.count, 242) + + # With clock snapshots. + def test_create_with_clock_snapshots(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + default_clock_class=cc, + supports_discarded_events=True, + discarded_events_have_default_clock_snapshots=True, + ) + + def msg_iter_next(msg_iter, stream): + return msg_iter._create_discarded_events_message( + stream, beg_clock_snapshot=10, end_clock_snapshot=20 + ) + + msg = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertIs(type(msg), bt2._DiscardedEventsMessage) + # Broken at the moment. + # self.assertEqual(msg.beginning_default_clock_snapshot, 10); + # self.assertEqual(msg.end_default_clock_snapshot, 20); + + # Trying to create when the stream does not support discarded events. + def test_create_unsupported_raises(self): + def create_stream_class(tc, cc): + return tc.create_stream_class() + + def msg_iter_next(msg_iter, stream): + with self.assertRaisesRegex( + ValueError, 'stream class does not support discarded events' + ): + msg_iter._create_discarded_events_message(stream) + + return 123 + + res = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertEqual(res, 123) + + # Trying to create with clock snapshots when the stream does not support + # them. + def test_create_unsupported_clock_snapshots_raises(self): + def create_stream_class(tc, cc): + return tc.create_stream_class(supports_discarded_events=True) + + def msg_iter_next(msg_iter, stream): + with self.assertRaisesRegex( + ValueError, + 'discarded events have no default clock snapshots for this stream class', + ): + msg_iter._create_discarded_events_message( + stream, beg_clock_snapshot=10, end_clock_snapshot=20 + ) + + return 123 + + res = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertEqual(res, 123) + + # Trying to create without clock snapshots when the stream requires them. + def test_create_missing_clock_snapshots_raises(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + default_clock_class=cc, + supports_discarded_events=True, + discarded_events_have_default_clock_snapshots=True, + ) + + def msg_iter_next(msg_iter, stream): + with self.assertRaisesRegex( + ValueError, + 'discarded events have default clock snapshots for this stream class', + ): + msg_iter._create_discarded_events_message(stream) + + return 123 + + res = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertEqual(res, 123) + + +class CreateDiscardedPacketMessageTestCase(unittest.TestCase): + # Most basic case. + def test_create(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + supports_packets=True, supports_discarded_packets=True + ) + + def msg_iter_next(msg_iter, stream): + return msg_iter._create_discarded_packets_message(stream) + + msg = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertIs(type(msg), bt2._DiscardedPacketsMessage) + self.assertIs(msg.count, None) + + # With packet count. + def test_create_with_count(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + supports_packets=True, supports_discarded_packets=True + ) + + def msg_iter_next(msg_iter, stream): + return msg_iter._create_discarded_packets_message(stream, count=242) + + msg = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertIs(type(msg), bt2._DiscardedPacketsMessage) + self.assertEqual(msg.count, 242) + + # With clock snapshots. + def test_create_with_clock_snapshots(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + default_clock_class=cc, + supports_packets=True, + supports_discarded_packets=True, + discarded_packets_have_default_clock_snapshots=True, + ) + + def msg_iter_next(msg_iter, stream): + return msg_iter._create_discarded_packets_message( + stream, beg_clock_snapshot=10, end_clock_snapshot=20 + ) + + msg = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertIs(type(msg), bt2._DiscardedPacketsMessage) + self.assertEqual(msg.beginning_default_clock_snapshot, 10) + self.assertEqual(msg.end_default_clock_snapshot, 20) + + # Trying to create when the stream does not support discarded packets. + def test_create_unsupported_raises(self): + def create_stream_class(tc, cc): + return tc.create_stream_class(supports_packets=True,) + + def msg_iter_next(msg_iter, stream): + with self.assertRaisesRegex( + ValueError, 'stream class does not support discarded packets' + ): + msg_iter._create_discarded_packets_message(stream) + + return 123 + + res = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertEqual(res, 123) + + # Trying to create with clock snapshots when the stream does not support + # them. + def test_create_unsupported_clock_snapshots_raises(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + supports_packets=True, supports_discarded_packets=True + ) + + def msg_iter_next(msg_iter, stream): + with self.assertRaisesRegex( + ValueError, + 'discarded packets have no default clock snapshots for this stream class', + ): + msg_iter._create_discarded_packets_message( + stream, beg_clock_snapshot=10, end_clock_snapshot=20 + ) + + return 123 + + res = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertEqual(res, 123) + + # Trying to create without clock snapshots when the stream requires them. + def test_create_missing_clock_snapshots_raises(self): + def create_stream_class(tc, cc): + return tc.create_stream_class( + default_clock_class=cc, + supports_packets=True, + supports_discarded_packets=True, + discarded_packets_have_default_clock_snapshots=True, + ) + + def msg_iter_next(msg_iter, stream): + with self.assertRaisesRegex( + ValueError, + 'discarded packets have default clock snapshots for this stream class', + ): + msg_iter._create_discarded_packets_message(stream) + + return 123 + + res = utils.run_in_message_iterator_next(create_stream_class, msg_iter_next) + self.assertEqual(res, 123) + + if __name__ == '__main__': unittest.main() diff --git a/tests/bindings/python/bt2/utils.py b/tests/bindings/python/bt2/utils.py index 8d2d08fb..a15e777b 100644 --- a/tests/bindings/python/bt2/utils.py +++ b/tests/bindings/python/bt2/utils.py @@ -323,3 +323,60 @@ def create_const_field(tc, field_class, field_value_setter_fn): packet_beg_msg = next(msg_iter) return packet_beg_msg.packet.context_field[field_name] + + +# Run `msg_iter_next_func` in a bt2._UserMessageIterator.__next__ context. +# +# For convenience, a trace and a stream are created. To allow the caller to +# customize the created stream class, the `create_stream_class_func` callback +# is invoked during the component initialization. It gets passed a trace class +# and a clock class, and must return a stream class. +# +# The `msg_iter_next_func` callback receives two arguments, the message iterator +# and the created stream. +# +# The value returned by `msg_iter_next_func` is returned by this function. +def run_in_message_iterator_next(create_stream_class_func, msg_iter_next_func): + class MyIter(bt2._UserMessageIterator): + def __init__(self, config, port): + tc, sc = port.user_data + trace = tc() + self._stream = trace.create_stream(sc) + + def __next__(self): + nonlocal res_bound + res_bound = msg_iter_next_func(self, self._stream) + raise bt2.Stop + + class MySrc(bt2._UserSourceComponent, message_iterator_class=MyIter): + def __init__(self, config, params, obj): + tc = self._create_trace_class() + cc = self._create_clock_class() + sc = create_stream_class_func(tc, cc) + + self._add_output_port('out', (tc, sc)) + + class MySink(bt2._UserSinkComponent): + def __init__(self, config, params, obj): + self._input_port = self._add_input_port('in') + + def _user_graph_is_configured(self): + self._input_iter = self._create_message_iterator(self._input_port) + + def _user_consume(self): + next(self._input_iter) + + graph = bt2.Graph() + res_bound = None + src = graph.add_component(MySrc, 'ze source') + snk = graph.add_component(MySink, 'ze sink') + graph.connect_ports(src.output_ports['out'], snk.input_ports['in']) + graph.run() + + # We deliberately use a different variable for returning the result than + # the variable bound to the MyIter.__next__ context. See the big comment + # about that in `run_in_component_init`. + + res = res_bound + del res_bound + return res