From 2bddca6f62d10c07ca6078d52a3f65f95f944c2f Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Tue, 30 Apr 2024 17:31:39 +0000 Subject: [PATCH] tests/lib/conds: run pre-cond test by name Change `conds-trigger` to run triggers by name, instead of by index. This makes it easier to run an arbitrary trigger by hand, when developing. Example: $ tests/lib/conds/conds-triggers list | python3 -m json.tool ... { "cond-id": "pre:field-class-integer-set-field-value-range:valid-n", "name": "field-class-integer-set-field-value-range:valid-n-gt-64" }, ... $ tests/lib/conds/conds-triggers run field-class-integer-set-field-value-range:valid-n-gt-64 Update the `test.py` driver to match. Update it also to output the trigger name in a TAP comment before each test, to make it easier for a developer to run a failing test by hand. Example: $ tests/lib/conds/test-conds.sh # Running trigger `field-class-integer-set-field-value-range:not-null:field-class` # TAP results for LibPrePostCondsTestCase ok 1 - test_field_class_integer_set_field_value_range_not_null_field_class (test.LibPrePostCondsTestCase.test_field_class_integer_set_field_value_range_not_null_field_class) # Running trigger `field-class-integer-set-field-value-range:valid-n-0` ok 2 - test_field_class_integer_set_field_value_range_valid_n_0 (test.LibPrePostCondsTestCase.test_field_class_integer_set_field_value_range_valid_n_0) # Running trigger `field-class-integer-set-field-value-range:valid-n-gt-64` ok 3 - test_field_class_integer_set_field_value_range_valid_n_gt_64 (test.LibPrePostCondsTestCase.test_field_class_integer_set_field_value_range_valid_n_gt_64) Note the little quirk that the `Running trigger` comment is displayed before the `TAP results for ...` comment. The latter is displayed when the first result is recorded, so I'm not sure how to fix this, but I don't think it's really a problem as it is. Since the test name is now a used as a key, modify `condMain()` to check that the test names passed in the `condTriggers` vectors are unique. If there is a duplicate name, we get: $ tests/lib/conds/conds-triggers list Duplicate test name `field-class-integer-set-field-value-range:valid-n-0` Ensuring unique names would have probably been useful anyway, since we generate Python methods based on that name, so we don't want any clashes. Change-Id: Ie05ad4070d9ea859e0678ee1cf5ed1c4010f9829 Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/12503 Reviewed-by: Philippe Proulx Tested-by: jenkins --- tests/lib/conds/test.py | 18 +++++++--------- tests/lib/conds/utils.cpp | 43 +++++++++++++++++++++++++++++++-------- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/tests/lib/conds/test.py b/tests/lib/conds/test.py index 2bbaa718..f229ae3a 100644 --- a/tests/lib/conds/test.py +++ b/tests/lib/conds/test.py @@ -25,15 +25,10 @@ class LibPrePostCondsTestCase(unittest.TestCase): # a condition trigger descriptor (base) class _CondTriggerDescriptor: - def __init__(self, index: int, trigger_name: str, cond_id: str): - self._index = index + def __init__(self, trigger_name: str, cond_id: str): self._trigger_name = trigger_name self._cond_id = cond_id - @property - def index(self): - return self._index - @property def trigger_name(self): return self._trigger_name @@ -61,11 +56,12 @@ class _PostCondTriggerDescriptor(_CondTriggerDescriptor): def _test(self: unittest.TestCase, descriptor: _CondTriggerDescriptor): # Execute: # - # $ conds-triggers run + # $ conds-triggers run # - # where `` is the descriptor's index. + # where `` is the descriptor trigger name. + print("# Running trigger `{}`".format(descriptor.trigger_name)) with subprocess.Popen( - [_CONDS_TRIGGERS_PATH, "run", str(descriptor.index)], + [_CONDS_TRIGGERS_PATH, "run", descriptor.trigger_name], stderr=subprocess.PIPE, universal_newlines=True, ) as proc: @@ -95,7 +91,7 @@ def _cond_trigger_descriptors_from_json(json_descr_array: tjson.ArrayVal): descriptors = [] # type: list[_CondTriggerDescriptor] descriptor_names = set() # type: set[str] - for index, json_descr in enumerate(json_descr_array.iter(tjson.ObjVal)): + for json_descr in json_descr_array.iter(tjson.ObjVal): # sanity check: check for duplicate trigger_name = json_descr.at("name", tjson.StrVal).val @@ -114,7 +110,7 @@ def _cond_trigger_descriptors_from_json(json_descr_array: tjson.ArrayVal): else: raise ValueError("Invalid condition ID `{}`".format(cond_id)) - descriptors.append(cond_type(index, trigger_name, cond_id)) + descriptors.append(cond_type(trigger_name, cond_id)) descriptor_names.add(trigger_name) return descriptors diff --git a/tests/lib/conds/utils.cpp b/tests/lib/conds/utils.cpp index 4d4e3b1d..364a7527 100644 --- a/tests/lib/conds/utils.cpp +++ b/tests/lib/conds/utils.cpp @@ -4,8 +4,9 @@ * Copyright (C) 2020 Philippe Proulx */ +#include + #include -#include #include #include @@ -48,28 +49,52 @@ void listCondTriggers(const CondTriggers& condTriggers) noexcept fmt::println("{}", condTriggerArray.dump()); } +void checkNamesUnique(const CondTriggers& condTriggers) +{ + std::unordered_set names; + + for (const auto& trigger : condTriggers) { + const auto res = names.insert(trigger->name()); + + if (!res.second) { + fmt::println(stderr, "Duplicate test name `{}`", trigger->name()); + std::exit(1); + } + } +} + } /* namespace */ void condMain(const bt2s::span argv, const CondTriggers& condTriggers) noexcept { BT_ASSERT(argv.size() >= 2); + checkNamesUnique(condTriggers); if (strcmp(argv[1], "list") == 0) { listCondTriggers(condTriggers); } else if (strcmp(argv[1], "run") == 0) { /* - * It's expected that calling `*condTriggers[index]` below - * aborts (calls bt_common_abort()). In this testing context, we - * don't want any custom abortion command to run. + * It's expected that calling the trigger below aborts (calls + * bt_common_abort()). In this testing context, we don't want + * any custom abortion command to run. */ g_unsetenv("BABELTRACE_EXEC_ON_ABORT"); - /* Call the trigger */ - BT_ASSERT(argv.size() >= 3); + /* Find the trigger */ + BT_ASSERT(argv.size() == 3); - const auto index = atoi(argv[2]); + const auto name = argv[2]; + const auto it = std::find_if(condTriggers.begin(), condTriggers.end(), + [&](const CondTrigger::UP& trigger) { + return trigger->name() == name; + }); - BT_ASSERT(index >= 0 && index < condTriggers.size()); - (*condTriggers[index])(); + if (it == condTriggers.end()) { + fmt::println(stderr, "No trigger named `{}` found.", name); + std::exit(1); + } + + /* Call the trigger */ + (**it)(); } } -- 2.34.1