From: Simon Marchi Date: Tue, 24 Oct 2023 02:12:24 +0000 (-0400) Subject: tests: run some Python tests with CTF 1 and CTF 2 traces X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=c5d4db7a5b271f013e93540e16998beb01fd677d;p=babeltrace.git tests: run some Python tests with CTF 1 and CTF 2 traces The goal of this patch is to run as many Python-based tests that use CTF traces against both CTF 1 and CTF 2. I would like to minimize the amount of changes and boilerplate necessary in each individual test. I've taken the approach to add a decorator named `test_all_ctf_versions` to the test classes, inspired by the parameterized Python package [1]. Unlike the decorators, from parameterized, our decorator is hardcoded for what we need. When applied to a class, it makes two copies of all `test_*` methods of that class, suffixed with `_ctf_1` and `_ctf_2`, and removes the original method. The two new methods are in fact wrapped in a small wrapper that sets the `_ctf_version` attribute on the class (with the value 1 or 2) for the duration of the method call. The changes necessary in the test themselves are to make the test trace paths dependent on `self._ctf_version`, instead of hard-coded. [1] https://pypi.org/project/parameterized/ Change-Id: Idef27183db6287630e63260395d255e68da2a4c3 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/8737 Reviewed-by: Philippe Proulx Tested-by: jenkins Reviewed-on: https://review.lttng.org/c/babeltrace/+/12755 --- diff --git a/tests/data/ctf-traces/2/intersection/3eventsintersect/metadata b/tests/data/ctf-traces/2/intersection/3eventsintersect/metadata new file mode 100644 index 00000000..a223ab1b --- /dev/null +++ b/tests/data/ctf-traces/2/intersection/3eventsintersect/metadata @@ -0,0 +1,233 @@ +{ + "type": "preamble", + "uuid": [ + 122, + 254, + 143, + 190, + 121, + 184, + 79, + 106, + 187, + 199, + 208, + 199, + 130, + 231, + 221, + 175 + ], + "version": 2 +} +{ + "environment": { + "host": "sinkpad" + }, + "packet-header-field-class": { + "member-classes": [ + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 32, + "roles": [ + "packet-magic-number" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "magic" + }, + { + "field-class": { + "length": 16, + "roles": [ + "metadata-stream-uuid" + ], + "type": "static-length-blob" + }, + "name": "uuid" + }, + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 32, + "roles": [ + "data-stream-class-id" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "stream_id" + } + ], + "minimum-alignment": 8, + "type": "structure" + }, + "type": "trace-class", + "uid": "7afe8fbe-79b8-4f6a-bbc7-d0c782e7ddaf" +} +{ + "description": "This is a test clock", + "frequency": 1000000000, + "id": "test_clock", + "offset-from-origin": { + "cycles": 0, + "seconds": 13515309 + }, + "origin": "unix-epoch", + "precision": 10, + "type": "clock-class" +} +{ + "default-clock-class-id": "test_clock", + "event-record-header-field-class": { + "member-classes": [ + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 32, + "roles": [ + "event-record-class-id" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "id" + }, + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 64, + "roles": [ + "default-clock-timestamp" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "timestamp" + } + ], + "minimum-alignment": 8, + "type": "structure" + }, + "packet-context-field-class": { + "member-classes": [ + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 64, + "roles": [ + "default-clock-timestamp" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "timestamp_begin" + }, + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 64, + "roles": [ + "packet-end-default-clock-timestamp" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "timestamp_end" + }, + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 64, + "roles": [ + "packet-content-length" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "content_size" + }, + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 64, + "roles": [ + "packet-total-length" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "packet_size" + }, + { + "field-class": { + "alignment": 8, + "byte-order": "big-endian", + "length": 64, + "roles": [ + "discarded-event-record-counter-snapshot" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "events_discarded" + }, + { + "field-class": { + "byte-order": "big-endian", + "length": 64, + "roles": [ + "packet-sequence-number" + ], + "type": "fixed-length-unsigned-integer" + }, + "name": "packet_seq_num" + } + ], + "minimum-alignment": 8, + "type": "structure" + }, + "type": "data-stream-class" +} +{ + "name": "dummy_event", + "payload-field-class": { + "member-classes": [ + { + "field-class": { + "byte-order": "big-endian", + "length": 32, + "type": "fixed-length-unsigned-integer" + }, + "name": "dummy_value" + }, + { + "field-class": { + "byte-order": "big-endian", + "length": 32, + "type": "fixed-length-unsigned-integer" + }, + "name": "tracefile_id" + }, + { + "field-class": { + "byte-order": "big-endian", + "length": 32, + "type": "fixed-length-unsigned-integer" + }, + "name": "packet_begin" + }, + { + "field-class": { + "byte-order": "big-endian", + "length": 32, + "type": "fixed-length-unsigned-integer" + }, + "name": "packet_end" + } + ], + "type": "structure" + }, + "type": "event-record-class" +} diff --git a/tests/data/ctf-traces/2/intersection/3eventsintersect/test_stream_0 b/tests/data/ctf-traces/2/intersection/3eventsintersect/test_stream_0 new file mode 100644 index 00000000..6a69e445 Binary files /dev/null and b/tests/data/ctf-traces/2/intersection/3eventsintersect/test_stream_0 differ diff --git a/tests/data/ctf-traces/2/intersection/3eventsintersect/test_stream_1 b/tests/data/ctf-traces/2/intersection/3eventsintersect/test_stream_1 new file mode 100644 index 00000000..0cf1404d Binary files /dev/null and b/tests/data/ctf-traces/2/intersection/3eventsintersect/test_stream_1 differ diff --git a/tests/plugins/src.ctf.fs/query/test_query_support_info.py b/tests/plugins/src.ctf.fs/query/test_query_support_info.py index 0bc0a33a..1add0936 100644 --- a/tests/plugins/src.ctf.fs/query/test_query_support_info.py +++ b/tests/plugins/src.ctf.fs/query/test_query_support_info.py @@ -7,63 +7,69 @@ import os import unittest import bt2 - -session_rotation_trace_path = os.path.join( - os.environ["BT_CTF_TRACES_PATH"], "1", "succeed", "session-rotation" -) - - -trace_10352_1 = os.path.join( - session_rotation_trace_path, - "a", - "1", - "ust", - "pid", - "10352", -) -trace_10353_1 = os.path.join( - session_rotation_trace_path, - "a", - "1", - "ust", - "pid", - "10353", -) -trace_10352_2 = os.path.join( - session_rotation_trace_path, - "a", - "2", - "ust", - "pid", - "10352", -) -trace_10353_2 = os.path.join( - session_rotation_trace_path, - "a", - "2", - "ust", - "pid", - "10353", -) -trace_10352_3 = os.path.join( - session_rotation_trace_path, - "3", - "ust", - "pid", - "10352", -) -trace_10353_3 = os.path.join( - session_rotation_trace_path, - "3", - "ust", - "pid", - "10353", -) +from test_all_ctf_versions import test_all_ctf_versions +@test_all_ctf_versions class QuerySupportInfoTestCase(unittest.TestCase): def test_support_info_with_uuid(self): # Test that the right group is reported for each trace. + ctf = bt2.find_plugin("ctf") + fs = ctf.source_component_classes["fs"] + + session_rotation_trace_path = os.path.join( + os.environ["BT_CTF_TRACES_PATH"], + str(self._ctf_version), + "succeed", + "session-rotation", + ) + + trace_10352_1 = os.path.join( + session_rotation_trace_path, + "a", + "1", + "ust", + "pid", + "10352", + ) + trace_10353_1 = os.path.join( + session_rotation_trace_path, + "a", + "1", + "ust", + "pid", + "10353", + ) + trace_10352_2 = os.path.join( + session_rotation_trace_path, + "a", + "2", + "ust", + "pid", + "10352", + ) + trace_10353_2 = os.path.join( + session_rotation_trace_path, + "a", + "2", + "ust", + "pid", + "10353", + ) + trace_10352_3 = os.path.join( + session_rotation_trace_path, + "3", + "ust", + "pid", + "10352", + ) + trace_10353_3 = os.path.join( + session_rotation_trace_path, + "3", + "ust", + "pid", + "10353", + ) def do_one_query(input, expected_group): qe = bt2.QueryExecutor( @@ -73,9 +79,6 @@ class QuerySupportInfoTestCase(unittest.TestCase): result = qe.query() self.assertEqual(result["group"], expected_group) - ctf = bt2.find_plugin("ctf") - fs = ctf.source_component_classes["fs"] - do_one_query(trace_10352_1, "21cdfa5e-9a64-490a-832c-53aca6c101ba") do_one_query(trace_10352_2, "21cdfa5e-9a64-490a-832c-53aca6c101ba") do_one_query(trace_10352_3, "21cdfa5e-9a64-490a-832c-53aca6c101ba") diff --git a/tests/plugins/src.ctf.fs/query/test_query_trace_info.py b/tests/plugins/src.ctf.fs/query/test_query_trace_info.py index 1d688013..79e5d182 100644 --- a/tests/plugins/src.ctf.fs/query/test_query_trace_info.py +++ b/tests/plugins/src.ctf.fs/query/test_query_trace_info.py @@ -8,6 +8,7 @@ import re import unittest import bt2 +from test_all_ctf_versions import test_all_ctf_versions test_ctf_traces_path = os.environ["BT_CTF_TRACES_PATH"] @@ -17,13 +18,21 @@ def sort_predictably(stream): return stream["port-name"] +@test_all_ctf_versions class QueryTraceInfoClockOffsetTestCase(unittest.TestCase): def setUp(self): ctf = bt2.find_plugin("ctf") self._fs = ctf.source_component_classes["fs"] - self._inputs = [ - os.path.join(test_ctf_traces_path, "1", "intersection", "3eventsintersect") + @property + def _inputs(self): + return [ + os.path.join( + test_ctf_traces_path, + str(self._ctf_version), + "intersection", + "3eventsintersect", + ) ] def _check(self, trace, offset): @@ -115,6 +124,7 @@ class QueryTraceInfoClockOffsetTestCase(unittest.TestCase): ).query() +@test_all_ctf_versions class QueryTraceInfoPortNameTestCase(unittest.TestCase): def setUp(self): ctf = bt2.find_plugin("ctf") @@ -127,18 +137,20 @@ class QueryTraceInfoPortNameTestCase(unittest.TestCase): { "inputs": [ os.path.join( - test_ctf_traces_path, "1", "intersection", "3eventsintersect" + test_ctf_traces_path, + str(self._ctf_version), + "intersection", + "3eventsintersect", ) ] }, ).query() - if os.environ["BT_TESTS_OS_TYPE"] == "mingw": - os_stream_path = ( - "\\tests\\data\\ctf-traces\\1\\intersection\\3eventsintersect\\" - ) - else: - os_stream_path = "/tests/data/ctf-traces/1/intersection/3eventsintersect/" + os_stream_path = ( + "\\tests\\data\\ctf-traces\\{}\\intersection\\3eventsintersect\\" + if os.environ["BT_TESTS_OS_TYPE"] == "mingw" + else "/tests/data/ctf-traces/{}/intersection/3eventsintersect/" + ).format(self._ctf_version) self.assertEqual(len(res), 1) trace = res[0] @@ -187,6 +199,7 @@ class QueryTraceInfoPortNameTestCase(unittest.TestCase): ) +@test_all_ctf_versions class QueryTraceInfoRangeTestCase(unittest.TestCase): def setUp(self): ctf = bt2.find_plugin("ctf") @@ -203,7 +216,12 @@ class QueryTraceInfoRangeTestCase(unittest.TestCase): "babeltrace.trace-infos", { "inputs": [ - os.path.join(test_ctf_traces_path, "1", "succeed", "succeed1") + os.path.join( + test_ctf_traces_path, + str(self._ctf_version), + "succeed", + "succeed1", + ) ] }, ).query() @@ -224,7 +242,7 @@ class QueryTraceInfoRangeTestCase(unittest.TestCase): "inputs": [ os.path.join( test_ctf_traces_path, - "1", + str(self._ctf_version), "succeed", "lttng-tracefile-rotation", "kernel", @@ -255,17 +273,22 @@ class QueryTraceInfoRangeTestCase(unittest.TestCase): self.assertEqual(streams[3]["range-ns"]["end"], 1571261797582522088) +@test_all_ctf_versions class QueryTraceInfoPacketTimestampQuirksTestCase(unittest.TestCase): def setUp(self): ctf = bt2.find_plugin("ctf") self._fs = ctf.source_component_classes["fs"] - self._path = os.path.join(test_ctf_traces_path, "1", "succeed") + + def _trace_path(self, trace_name): + return os.path.join( + test_ctf_traces_path, str(self._ctf_version), "succeed", trace_name + ) def _test_lttng_quirks(self, trace_name): res = bt2.QueryExecutor( self._fs, "babeltrace.trace-infos", - {"inputs": [os.path.join(self._path, trace_name)]}, + {"inputs": [self._trace_path(trace_name)]}, ).query() self.assertEqual(len(res), 1) diff --git a/tests/utils/python/test_all_ctf_versions.py b/tests/utils/python/test_all_ctf_versions.py new file mode 100644 index 00000000..cc6fdd05 --- /dev/null +++ b/tests/utils/python/test_all_ctf_versions.py @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 EfficiOS, Inc. +# + + +# Decorator for unittest.TestCast sub-classes to run tests against CTF 1 and +# CTF 2 versions of the same traces. +# +# Replaces all test_* methods with a test_*_ctf_1 and a test_*_ctf_2 variant. +# +# For instance, it transforms this: +# +# @test_all_ctf_versions +# class MyTestCase(unittest.TestCase): +# test_something(self): +# pass +# +# into: +# +# class MyTestcase(unittest.TestCase): +# test_something_ctf_1(self): +# pass +# +# test_something_ctf_2(self): +# pass +# +# The test methods are wrapped such that the self._ctf_version attribute is +# set to either 1 or 2 during the call to each method. +def test_all_ctf_versions(cls): + for attr_name, attr_value in list(cls.__dict__.items()): + if not attr_name.startswith("test_") or not callable(attr_value): + continue + + for ctf_version in 1, 2: + # Callable that wraps and replaces test methods in order to + # temporarily set the _ctf_version attribute on the TestCase class. + def set_ctf_version_wrapper_method(self, ctf_version, test_method): + assert not hasattr(self, "_ctf_version") + self._ctf_version = ctf_version + + try: + return test_method(self) + finally: + assert hasattr(self, "_ctf_version") + del self._ctf_version + + def wrap_method(wrapper_method, ctf_version, original_method): + return lambda self: wrapper_method(self, ctf_version, original_method) + + setattr( + cls, + "{}_ctf_{}".format(attr_name, ctf_version), + wrap_method(set_ctf_version_wrapper_method, ctf_version, attr_value), + ) + + delattr(cls, attr_name) + + return cls