tests: add libbabeltrace2 pre/postcondition testing infrastructure
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 14 Apr 2020 01:38:22 +0000 (21:38 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 23 Apr 2020 03:45:20 +0000 (23:45 -0400)
commit5d7e83594e8aa4f8b465165c05938116279f493d
tree818ec42d70a860a7729d36a51ae51b497bb4ade6
parent1778c2a4134647150b199b2b57130817144446b0
tests: add libbabeltrace2 pre/postcondition testing infrastructure

This patch adds a basic libbabeltrace2 pre/postcondition testing
infrastructure to the project.

When a libbabeltrace2 public function precondition or postcondition is
not satisfied, the function logs a FATAL-level message which indicates
what's wrong and then aborts. Slow path functions check such conditions
unconditionally, while fast path functions check them only in developer
mode.

Testing that a libbabeltrace2 function catches an unsatisfied
pre/postcondition and reports it is not straightforward: the library
aborts the program, so we can't use the usual approach because the test
program itself would abort.

The solution brought by this patch is the following process in
`tests/lib/conds`:

1. The `conds-triggers.c` program contains all the pre/postcondition
   failure triggering instructions to test, one condition per function.

   Each triggering function triggers a single pre/postcondition check.
   It is expected that the function actually aborts.

   main() calls ppc_main(), an internal utility, with its command-line
   arguments and an array of condition trigger descriptors.

   Each condition trigger descriptor has:

   * A condition type: precondition or postcondition.
   * The ID of the condition to trigger.
   * A name suffix.
   * A condition triggering function.

   Each condition trigger descriptor has a unique name: its condition ID
   and an optional name suffix.

   As of this patch, the PPC_TRIGGER_*_RUN_IN_COMP_CLS_INIT() macros
   create condition trigger descriptors of which the function runs
   within a component class initialization function (accepts a
   `bt_self_component *` parameter). This is often needed as many
   libbabeltrace2 functions are only accessible through a self component
   (all the trace IR API, for example).

   ppc_main() handles two command-line subcommands:

   `list`:
       Prints a JSON array of objects which represent the triggering
       descriptors, for example (output for this patch):

           [
             {
               "cond-id": "pre:field-class-integer-set-field-value-range:valid-n",
               "name": "pre:field-class-integer-set-field-value-range:valid-n-0"
             },
             {
               "cond-id": "pre:field-class-integer-set-field-value-range:valid-n",
               "name": "pre:field-class-integer-set-field-value-range:valid-n-gt-64"
             },
             {
               "cond-id": "pre:field-class-integer-set-field-value-range:not-null:field-class",
               "name": "pre:field-class-integer-set-field-value-range:not-null:field-class"
             }
           ]

   `run INDEX`:
       Runs the condition triggering function for the descriptor at
       index `INDEX` in the `list` array.

       It is expected that this command aborts.

2. `test_conds` is a Bash script which only does this:

       reldir=lib/conds
       export BT_TESTS_LIB_CONDS_TRIGGER_BIN="$BT_TESTS_BUILDDIR/$reldir/conds-triggers"

       if [ "$BT_OS_TYPE" = "mingw" ]; then
         BT_TESTS_LIB_CONDS_TRIGGER_BIN="$BT_TESTS_LIB_CONDS_TRIGGER_BIN.exe"
       fi

       run_python_bt2_test "$BT_TESTS_SRCDIR/$reldir" test.py

   In other words, it runs the Python TAP test runner to discover and
   run tests in `test.py`.

   This script is part of the `make check` test set.

3. In `test.py`, a function:

   a) Runs `conds-triggers list` and decodes the output to get the list
      of available condition trigger descriptors.

      This step also validates the regular expressions and checks that
      there are no duplicate descriptor names.

   b) For each condition trigger descriptor, creates and adds a test to
      its single test case class which:

        I. Executes `conds-triggers run INDEX` as a subprocess,
           where `INDEX` is the descriptor's index.

       II. Reads the complete process's standard error.

      III. Asserts that the process aborts (`SIGABRT` signal).

           This seems to be only possible on a POSIX system with the
           `subprocess.Popen` API.

       IV. Asserts that the standard error (II) contains the
           descriptor's condition ID.

All this is only enabled if, at configuration time:

* Python 3 is available.
* The Babeltrace 2 developer mode is enabled (`BABELTRACE_DEV_MODE=1`).

This patch's `conds-triggers.c` includes two precondition triggering
functions to confirm that everything works as expected:

trigger_fc_int_set_field_value_range_n_0():
    When calling bt_field_class_integer_set_field_value_range(), the
    parameter `N` cannot be greater than 64.

trigger_fc_int_set_field_value_range_n_gt_64():
    When calling bt_field_class_integer_set_field_value_range(), the
    parameter `N` cannot be 0.

trigger_fc_int_set_field_value_range_null():
    When calling bt_field_class_integer_set_field_value_range(), the
    field class cannot be `NULL`.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: I70713d690f7dbfeac5804e6cfcec989242823611
Reviewed-on: https://review.lttng.org/c/babeltrace/+/3401
.gitignore
configure.ac
tests/Makefile.am
tests/lib/Makefile.am
tests/lib/conds/Makefile.am [new file with mode: 0644]
tests/lib/conds/conds-triggers.c [new file with mode: 0644]
tests/lib/conds/test.py [new file with mode: 0644]
tests/lib/conds/test_conds [new file with mode: 0755]
tests/lib/conds/utils.c [new file with mode: 0644]
tests/lib/conds/utils.h [new file with mode: 0644]
This page took 0.030385 seconds and 4 git commands to generate.