From 3b8884283f8c90195bd231cad3f3e115d006c6fd Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Wed, 11 May 2016 15:45:46 -0400 Subject: [PATCH] Tests: Multi-trace stream intersection test MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérémie Galarneau --- .gitignore | 3 +- configure.ac | 5 +- tests/Makefile.am | 6 +- tests/bin/Makefile.am | 3 +- tests/bin/intersection/Makefile.am | 6 + tests/bin/intersection/bt_python_helper.py.in | 37 ++++ .../{ => intersection}/test_intersection.in | 5 +- .../test_multi_trace_intersection.py | 159 ++++++++++++++++++ 8 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 tests/bin/intersection/Makefile.am create mode 100644 tests/bin/intersection/bt_python_helper.py.in rename tests/bin/{ => intersection}/test_intersection.in (95%) create mode 100755 tests/bin/intersection/test_multi_trace_intersection.py diff --git a/.gitignore b/.gitignore index a1f883e2..a7c9e3ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *~ /tests/bin/test_trace_read -/tests/bin/test_intersection +/tests/bin/intersection/test_intersection +/tests/bin/intersection/bt_python_helper.py /tests/bin/test_packet_seq_num /tests/lib/test_bitfield /tests/lib/test_seek diff --git a/configure.ac b/configure.ac index 0157ec83..38b8a75f 100644 --- a/configure.ac +++ b/configure.ac @@ -313,6 +313,7 @@ AC_CONFIG_FILES([ bindings/python/babeltrace/Makefile tests/Makefile tests/bin/Makefile + tests/bin/intersection/Makefile tests/lib/Makefile tests/utils/Makefile tests/utils/tap/Makefile @@ -329,8 +330,10 @@ AC_CONFIG_FILES([tests/lib/test_dwarf_complete], [chmod +x tests/lib/test_dwarf_ AC_CONFIG_FILES([tests/lib/test_bin_info_complete], [chmod +x tests/lib/test_bin_info_complete]) AC_CONFIG_FILES([tests/bin/test_trace_read], [chmod +x tests/bin/test_trace_read]) -AC_CONFIG_FILES([tests/bin/test_intersection], [chmod +x tests/bin/test_intersection]) +AC_CONFIG_FILES([tests/bin/intersection/test_intersection], [chmod +x tests/bin/intersection/test_intersection]) +AC_CONFIG_FILES([tests/bin/intersection/bt_python_helper.py]) AC_CONFIG_FILES([tests/bin/test_packet_seq_num], [chmod +x tests/bin/test_packet_seq_num]) +AC_CONFIG_FILES([tests/bin/intersection/test_multi_trace_intersection.py:tests/bin/intersection/test_multi_trace_intersection.py], [chmod +x tests/bin/intersection/test_multi_trace_intersection.py]) AC_OUTPUT diff --git a/tests/Makefile.am b/tests/Makefile.am index 7045aef9..98e0b85f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,7 +6,7 @@ LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ TESTS = bin/test_trace_read \ bin/test_trace_read \ bin/test_packet_seq_num \ - bin/test_intersection \ + bin/intersection/test_intersection \ lib/test_bitfield \ lib/test_seek_empty_packet \ lib/test_seek_big_trace \ @@ -20,3 +20,7 @@ if ENABLE_DEBUGINFO TESTS += lib/test_dwarf_complete \ lib/test_bin_info_complete endif + +if USE_PYTHON +TESTS += bin/intersection/test_multi_trace_intersection.py +endif diff --git a/tests/bin/Makefile.am b/tests/bin/Makefile.am index 0d56c6d7..2d008ed4 100644 --- a/tests/bin/Makefile.am +++ b/tests/bin/Makefile.am @@ -1 +1,2 @@ -check_SCRIPTS = test_trace_read test_intersection test_packet_seq_num +SUBDIRS = intersection +check_SCRIPTS = test_trace_read test_packet_seq_num diff --git a/tests/bin/intersection/Makefile.am b/tests/bin/intersection/Makefile.am new file mode 100644 index 00000000..664bc3a0 --- /dev/null +++ b/tests/bin/intersection/Makefile.am @@ -0,0 +1,6 @@ +check_SCRIPTS = test_intersection \ + bt_python_helper.py \ + test_multi_trace_intersection.py + +SCRIPT_LIST = test_multi_trace_intersection.py +dist_noinst_SCRIPTS = test_multi_trace_intersection.py diff --git a/tests/bin/intersection/bt_python_helper.py.in b/tests/bin/intersection/bt_python_helper.py.in new file mode 100644 index 00000000..11b4ab16 --- /dev/null +++ b/tests/bin/intersection/bt_python_helper.py.in @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# +# The MIT License (MIT) +# +# Copyright (C) 2016 - Jérémie Galarneau +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys + +# Point the Python interpreter to the builddir's library and Babeltrace +# bindings +bt_module_path = '@abs_top_builddir@/bindings/python/babeltrace' +bt_lib_py_path = '@abs_top_builddir@/bindings/python/babeltrace/.libs' +bt_lib_bt_path = '@abs_top_builddir@/lib/.libs' +bt_lib_ctf_path = '@abs_top_builddir@/format/ctf/.libs' + +sys.path.insert(0, bt_module_path) +sys.path.insert(1, bt_lib_py_path) +sys.path.insert(2, bt_lib_bt_path) +sys.path.insert(3, bt_lib_ctf_path) diff --git a/tests/bin/test_intersection.in b/tests/bin/intersection/test_intersection.in similarity index 95% rename from tests/bin/test_intersection.in rename to tests/bin/intersection/test_intersection.in index 82eac235..689fbc1e 100644 --- a/tests/bin/test_intersection.in +++ b/tests/bin/intersection/test_intersection.in @@ -15,10 +15,9 @@ # this program; if not, write to the Free Software Foundation, Inc., 51 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -CURDIR=$(dirname $0) -TESTDIR=$CURDIR/.. +TESTDIR=@abs_top_srcdir@/tests -BABELTRACE_BIN=$CURDIR/../../converter/babeltrace +BABELTRACE_BIN=@abs_top_builddir@/converter/babeltrace CTF_TRACES=@abs_top_srcdir@/tests/ctf-traces source $TESTDIR/utils/tap/tap.sh diff --git a/tests/bin/intersection/test_multi_trace_intersection.py b/tests/bin/intersection/test_multi_trace_intersection.py new file mode 100755 index 00000000..907b5010 --- /dev/null +++ b/tests/bin/intersection/test_multi_trace_intersection.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# +# The MIT License (MIT) +# +# Copyright (C) 2016 - Jérémie Galarneau +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import bt_python_helper +import tempfile +import babeltrace +import uuid +import shutil + + +class Entry(object): + def __init__(self, stream_id, timestamp=None, end_of_packet=False): + self.stream_id = stream_id + self.timestamp = timestamp + self.end_of_packet = end_of_packet + + +class Packet(object): + def __init__(self, timestamps): + self.timestamps = timestamps + +clock_uuid = uuid.uuid4() + +# stream_descriptions is a list of lists of Packets. +# Each stream description list is mapped to a single stream instance. +def create_trace(path, clock_uuid, stream_descriptions): + trace = babeltrace.CTFWriter.Writer(path) + clock = babeltrace.CTFWriter.Clock('test_clock') + clock.uuid = clock_uuid + trace.add_clock(clock) + + integer_field_type = babeltrace.CTFWriter.IntegerFieldDeclaration(32) + + event_class = babeltrace.CTFWriter.EventClass('simple_event') + event_class.add_field(integer_field_type, 'int_field') + + stream_class = babeltrace.CTFWriter.StreamClass('test_stream') + stream_class.add_event_class(event_class) + stream_class.clock = clock + + streams = [] + stream_entries = [] + for stream_id, stream_packets in enumerate(stream_descriptions): + stream = trace.create_stream(stream_class) + streams.append(stream) + + for packet in stream_packets: + for timestamp in packet.timestamps: + stream_entries.append(Entry(stream_id, timestamp)) + # Mark the last inserted entry as the end of packet + stream_entries[len(stream_entries) - 1].end_of_packet = True + + # Sort stream entries which will provide us with a time-ordered list of + # events to insert in the streams. + for entry in sorted(stream_entries, key=lambda entry: entry.timestamp): + clock.time = entry.timestamp + event = babeltrace.CTFWriter.Event(event_class) + event.payload('int_field').value = entry.stream_id + streams[entry.stream_id].append_event(event) + if entry.end_of_packet is True: + streams[entry.stream_id].flush() + + +def check_trace_expected_timestamps(trace_paths, expected_timestamps): + traces = babeltrace.TraceCollection(intersect_mode=True) + for trace_path in trace_paths: + trace_handle = traces.add_trace(trace_path, 'ctf') + if trace_handle is None: + print('Failed to open trace at {}'.format(trace_path)) + return False + for event in traces.events: + expected_timestamp = expected_timestamps.pop(0) + if event.timestamp != expected_timestamp: + print('# Unexpected timestamp ({}), expected {}'.format( + event.timestamp, expected_timestamp)) + return False + return True + + +def print_test_result(test_number, result, description): + result_string = 'ok' if result else 'not ok' + result_string += ' {} - {}'.format(test_number, description) + print(result_string) + +TEST_COUNT = 3 +# TAP plan +print('1..{}'.format(TEST_COUNT)) + +trace_path_early = tempfile.mkdtemp() + +# The stream intersection of this trace is event timestamps 11, 12 and 13, +# accounting for 9 events in stream-intersection mode +print('# Creating early trace at {}'.format(trace_path_early)) +create_trace(trace_path_early, clock_uuid, [ + [Packet(range(1, 7)), Packet(range(11, 18))], + [Packet(range(8, 15)), Packet(range(22, 24)), Packet(range(30, 60))], + [Packet(range(11, 14))] + ]) + +trace_path_late = tempfile.mkdtemp() +print('# Creating late trace at {}'.format(trace_path_late)) +# The stream intersection of this trace is event timestamps 100, 101, 102, 103 +# and 104 accounting for 15 events in stream-intersection mode +create_trace(trace_path_late, clock_uuid, [ + [Packet(range(100, 105)), Packet(range(109, 120))], + [Packet(range(88, 95)), Packet(range(96, 110)), Packet(range(112, 140))], + [Packet(range(99, 105))] + ]) + +expected_timestamps_early = [] +for ts in range(11, 14): + for stream in range(3): + expected_timestamps_early.append(ts) + +expected_timestamps_late = [] +for ts in range(100, 105): + for stream in range(3): + expected_timestamps_late.append(ts) + +expected_timestamps_union = (expected_timestamps_early + + expected_timestamps_late) + +# Validate that the stream-intersection mode on a single trace returns only +# the events that are in overlapping packets across all of the trace's streams. +result = check_trace_expected_timestamps([trace_path_early], + expected_timestamps_early) +print_test_result(1, result, 'Validating expected event timestamps of "early" trace') + +result = check_trace_expected_timestamps([trace_path_late], + expected_timestamps_late) +print_test_result(2, result, 'Validating expected event timestamps of "late" trace') + +result = check_trace_expected_timestamps([trace_path_early, trace_path_late], + expected_timestamps_union) +print_test_result(3, result, 'Validating expected event timestamps of the union of "early" and "late" traces') + +shutil.rmtree(trace_path_early) +shutil.rmtree(trace_path_late) -- 2.34.1