tests/lib/conds: run pre-cond test by name
authorSimon Marchi <simon.marchi@efficios.com>
Tue, 30 Apr 2024 17:31:39 +0000 (17:31 +0000)
committerSimon Marchi <simon.marchi@efficios.com>
Wed, 9 Oct 2024 02:56:57 +0000 (22:56 -0400)
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
    <abort message>

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 <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/12503
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
Tested-by: jenkins <jenkins@lttng.org>
tests/lib/conds/test.py
tests/lib/conds/utils.cpp

index 2bbaa7183325af8a6d8868af82626fbeba397d2f..f229ae3a81c69680e9322ad3619909c8080f0aa5 100644 (file)
@@ -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 <index>
+    #     $ conds-triggers run <trigger-name>
     #
-    # where `<index>` is the descriptor's index.
+    # where `<trigger-name>` 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
index 4d4e3b1dd14454248f787722922605e45ded7279..364a7527a0c03b980217995adc4a5db53acb6876 100644 (file)
@@ -4,8 +4,9 @@
  * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
  */
 
+#include <unordered_set>
+
 #include <glib.h>
-#include <stdlib.h>
 #include <string.h>
 
 #include <babeltrace2/babeltrace.h>
@@ -48,28 +49,52 @@ void listCondTriggers(const CondTriggers& condTriggers) noexcept
     fmt::println("{}", condTriggerArray.dump());
 }
 
+void checkNamesUnique(const CondTriggers& condTriggers)
+{
+    std::unordered_set<std::string> 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<const char * const> 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)();
     }
 }
This page took 0.027201 seconds and 4 git commands to generate.