Tests: sink.text.pretty: Add unit tests for enum fields printing
authorGeneviève Bastien <gbastien@versatic.net>
Wed, 26 Feb 2020 20:49:57 +0000 (15:49 -0500)
committerFrancis Deslauriers <francis.deslauriers@efficios.com>
Thu, 6 Aug 2020 18:24:48 +0000 (14:24 -0400)
Adds a Python component class who creates an event class with an enum
field that contains the enumeration described by the test caller. The
script iterator has a single event with a value also sent in parameter.

The tests themselves are run from a bash script, for signed/unsigned
values.

This commit also renames the existing `test_pretty` test file to
`test_pretty_python` to control all future Python tests for the
`sink.text.pretty` component class.

Change-Id: I3f631224dd3bdf21dbb2ef2d233c9f2dc8da43fa
Signed-off-by: Geneviève Bastien <gbastien@versatic.net>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/3149
CI-Build: Francis Deslauriers <francis.deslauriers@efficios.com>
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
configure.ac
tests/Makefile.am
tests/data/plugins/sink.text.pretty/bt_plugin_pretty_test.py [new file with mode: 0644]
tests/plugins/Makefile.am
tests/plugins/sink.text.pretty/Makefile.am [new file with mode: 0644]
tests/plugins/sink.text.pretty/test_enum [new file with mode: 0755]
tests/plugins/sink.text.pretty/test_pretty [deleted file]
tests/plugins/sink.text.pretty/test_pretty_python [new file with mode: 0755]
tests/utils/python/split_sort_compare.py [new file with mode: 0644]

index 63eef1bcf611f16ff7103c8f0cb891f30882fdfc..34eb2f15102bdeb3b6fc17a49c68bdc320f7cb12 100644 (file)
@@ -817,6 +817,7 @@ AC_CONFIG_FILES([
        tests/plugins/flt.utils.muxer/Makefile
        tests/plugins/flt.utils.muxer/succeed/Makefile
        tests/plugins/flt.utils.trimmer/Makefile
+       tests/plugins/sink.text.pretty/Makefile
        tests/utils/Makefile
        tests/utils/tap/Makefile
 ])
index bd7ae03d7fff8a436e579eb65a59c7c84e78b647..f1bc2e7fc4dd616419347d36e49960473aebe991 100644 (file)
@@ -55,8 +55,9 @@ dist_check_SCRIPTS = \
        cli/test_trace_read \
        cli/test_trimmer \
        plugins/sink.text.details/succeed/test_succeed \
-       plugins/sink.text.pretty/test_pretty \
+       plugins/sink.text.pretty/test_enum \
        plugins/sink.text.pretty/test_pretty.py \
+       plugins/sink.text.pretty/test_pretty_python \
        plugins/src.ctf.lttng-live/test_live \
        python-plugin-provider/bt_plugin_test_python_plugin_provider.py \
        python-plugin-provider/test_python_plugin_provider \
@@ -135,7 +136,8 @@ TESTS_CLI += \
        cli/test_exit_status
 
 TESTS_PLUGINS += plugins/flt.utils.trimmer/test_trimming \
-       plugins/flt.utils.muxer/succeed/test_succeed
+       plugins/flt.utils.muxer/succeed/test_succeed \
+       plugins/sink.text.pretty/test_enum
 endif
 endif
 
@@ -151,7 +153,7 @@ TESTS_PYTHON_PLUGIN_PROVIDER =
 
 if ENABLE_PYTHON_PLUGINS
 TESTS_PYTHON_PLUGIN_PROVIDER += python-plugin-provider/test_python_plugin_provider
-TESTS_PLUGINS += plugins/sink.text.pretty/test_pretty
+TESTS_PLUGINS += plugins/sink.text.pretty/test_pretty_python
 if ENABLE_DEBUG_INFO
 TESTS_PLUGINS += \
        plugins/flt.lttng-utils.debug-info/test_succeed
diff --git a/tests/data/plugins/sink.text.pretty/bt_plugin_pretty_test.py b/tests/data/plugins/sink.text.pretty/bt_plugin_pretty_test.py
new file mode 100644 (file)
index 0000000..c3a66f7
--- /dev/null
@@ -0,0 +1,83 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2020 Geneviève Bastien <gbastien@versatic.net>
+
+import bt2
+
+
+class TheIteratorOfProblems(bt2._UserMessageIterator):
+    def __init__(self, config, port):
+        tc, sc, ec1, params = port.user_data
+        trace = tc()
+        stream = trace.create_stream(sc)
+        event_value = params['value']
+        self._msgs = []
+
+        self._msgs.append(self._create_stream_beginning_message(stream))
+
+        ev_msg1 = self._create_event_message(ec1, stream)
+        ev_msg1.event.payload_field["enum_field"] = event_value
+
+        self._msgs.append(ev_msg1)
+
+        self._msgs.append(self._create_stream_end_message(stream))
+
+        self._at = 0
+        config.can_seek_forward = True
+
+    def _user_seek_beginning(self):
+        self._at = 0
+
+    def __next__(self):
+        if self._at < len(self._msgs):
+            msg = self._msgs[self._at]
+            self._at += 1
+            return msg
+        else:
+            raise StopIteration
+
+
+@bt2.plugin_component_class
+class TheSourceOfProblems(
+    bt2._UserSourceComponent, message_iterator_class=TheIteratorOfProblems
+):
+    def __init__(self, config, params, obj):
+        tc = self._create_trace_class()
+
+        enum_values_str = params['enum-values']
+
+        sc = tc.create_stream_class()
+
+        # Create the enumeration field with the values in parameter
+        if params['enum-signed']:
+            enumfc = tc.create_signed_enumeration_field_class()
+        else:
+            enumfc = tc.create_unsigned_enumeration_field_class()
+
+        groups = str(enum_values_str).split(' ')
+        mappings = {}
+        range_set_type = (
+            bt2.SignedIntegerRangeSet
+            if params['enum-signed']
+            else bt2.UnsignedIntegerRangeSet
+        )
+        for group in groups:
+            label, low, high = group.split(',')
+
+            if label not in mappings.keys():
+                mappings[label] = range_set_type()
+
+            mappings[label].add((int(low), int(high)))
+
+        for x, y in mappings.items():
+            enumfc.add_mapping(x, y)
+
+        # Create the struct field to contain the enum field class
+        struct_fc = tc.create_structure_field_class()
+        struct_fc.append_member('enum_field', enumfc)
+
+        # Create an event class on this stream with the struct field
+        ec1 = sc.create_event_class(name='with_enum', payload_field_class=struct_fc)
+        self._add_output_port('out', (tc, sc, ec1, params))
+
+
+bt2.register_plugin(__name__, 'test-pretty')
index d0f711a88b918f6e84952b9beb422b598fd2c4ea..2cf409efbe2f4b7c1b67e9e75cd73fe4dfbcd5eb 100644 (file)
@@ -5,4 +5,5 @@ SUBDIRS = \
        src.ctf.fs \
        flt.lttng-utils.debug-info \
        flt.utils.muxer \
-       flt.utils.trimmer
+       flt.utils.trimmer \
+       sink.text.pretty
diff --git a/tests/plugins/sink.text.pretty/Makefile.am b/tests/plugins/sink.text.pretty/Makefile.am
new file mode 100644 (file)
index 0000000..2eb912f
--- /dev/null
@@ -0,0 +1,3 @@
+dist_check_SCRIPTS = \
+       test_pretty_python \
+       test_enum
diff --git a/tests/plugins/sink.text.pretty/test_enum b/tests/plugins/sink.text.pretty/test_enum
new file mode 100755 (executable)
index 0000000..c00e6ac
--- /dev/null
@@ -0,0 +1,160 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2020 Geneviève Bastien <gbastien@versatic.net>
+#
+# This file tests pretty printing in details some event classes that are
+# not all covered by the main babeltrace tests with traces.
+SH_TAP=1
+
+if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
+       UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
+else
+       UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+source "$UTILSSH"
+
+data_dir="$BT_TESTS_DATADIR/plugins/sink.text.pretty"
+temp_stdout_expected_file=$(mktemp -t test_pretty_expected_stdout.XXXXXX)
+temp_stderr_expected="/dev/null"
+
+plan_tests 14
+
+function compare_enum_sorted
+{
+       local expected_file="$1"
+       local actual_file="$2"
+
+       # The order in which enum labels are printed by a `sink.text.pretty`
+       # component directly depends on the order in which mappings were added
+       # to the enum field class in the source component. This order should
+       # not be relied on when testing. Relying on it caused problems with
+       # Python component classes because different versions of Python sort
+       # data structures differently (e.g. dictionaries are insertion sorted
+       # since Python 3.7).
+
+       run_python_bt2 python3 "${BT_TESTS_SRCDIR}/utils/python/split_sort_compare.py" \
+               "$(cat $expected_file)" "$(cat $actual_file)"
+}
+
+function run_test
+{
+       local test_name=$1
+       local expected_to_fail="$2"
+       local value="$3"
+       local expected_stdout_file="$4"
+       local test_text=
+       local actual_stdout_file
+       local actual_stderr_file
+       local ret=0
+       local local_args=(
+               "--plugin-path" "$data_dir"
+               "-c" "src.test-pretty.TheSourceOfProblems"
+               "-p" "enum-values=\"$enum_values\""
+               "-p" "value=$value"
+               "-p" "enum-signed=$enum_signed"
+               "-c" "sink.text.pretty"
+       )
+
+       actual_stdout_file="$(mktemp -t actual_pretty_stdout.XXXXXX)"
+       actual_stderr_file="$(mktemp -t actual_pretty_stderr.XXXXXX)"
+
+       bt_cli "$actual_stdout_file" "$actual_stderr_file" "${local_args[@]}"
+
+       compare_enum_sorted "$expected_stdout_file" "$actual_stdout_file"
+       ret_stdout=$?
+
+       bt_diff /dev/null "$actual_stderr_file"
+       ret_stderr=$?
+
+       if ((ret_stdout != 0 || ret_stderr != 0)); then
+               ret=1
+       fi
+
+       rm -f "$actual_stdout_file" "$actual_stderr_file"
+
+       if (($expected_to_fail)); then
+               isnt $ret 0 "$test_name signed=$enum_signed with value=$value doesn't match as expected"
+       else
+               ok $ret "$test_name signed=$enum_signed with value=$value matches"
+       fi
+
+}
+
+function test_normal_enum {
+       test_name="Normal enum"
+       enum_signed="$1"
+       enum_values="single,1,1 single2,2,2 single3,4,4 range,4,8 range2,15,20"
+
+       # Hit a single value
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( "single" : container = 1 ) }
+       END
+       run_test "$test_name" 0 1 "$temp_stdout_expected_file"
+
+       # Hit a single range
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( "range" : container = 7 ) }
+       END
+       run_test "$test_name" 0 7 "$temp_stdout_expected_file"
+
+       # Unknown
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( <unknown> : container = 21 ) }
+       END
+       run_test "$test_name" 0 21 "$temp_stdout_expected_file"
+
+       # Unknown but with bits with a value, but range larger than 1 element
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( <unknown> : container = 12 ) }
+       END
+       run_test "$test_name" 0 12 "$temp_stdout_expected_file"
+
+       # Unknown value of 0
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( <unknown> : container = 0 ) }
+       END
+       run_test "$test_name" 0 0 "$temp_stdout_expected_file"
+}
+
+function test_normal_enum_negative {
+       test_name="Normal enum with negative value"
+       enum_signed="true"
+       enum_values="zero,0,0 single,1,1 single2,2,2 single3,4,4 range,4,8 negative,-1,-1 rangeNegative,-6,-2"
+
+       # Hit a single negative value
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( "negative" : container = -1 ) }
+       END
+       run_test "$test_name" 0 -1 "$temp_stdout_expected_file"
+
+       # Hit a single negative range
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( "rangeNegative" : container = -6 ) }
+       END
+       run_test "$test_name" 0 -6 "$temp_stdout_expected_file"
+
+       # Unknown
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( <unknown> : container = -7 ) }
+       END
+       run_test "$test_name" 0 -7 "$temp_stdout_expected_file"
+
+       # value of 0
+       cat <<- 'END' > "$temp_stdout_expected_file"
+       with_enum: { enum_field = ( "zero" : container = 0 ) }
+       END
+       run_test "$test_name" 0 0 "$temp_stdout_expected_file"
+}
+
+# Enumerations tests
+test_normal_enum "false"
+test_normal_enum "true"
+test_normal_enum_negative
+
+# Do not `rm` $temp_stderr_expected because it's set to `/dev/null` right now
+# and that would print an error.
+rm -f "$temp_stdout_expected_file"
diff --git a/tests/plugins/sink.text.pretty/test_pretty b/tests/plugins/sink.text.pretty/test_pretty
deleted file mode 100755 (executable)
index 3fdac62..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-#
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
-#
-
-if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
-       UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
-else
-       UTILSSH="$(dirname "$0")/../../utils/utils.sh"
-fi
-
-# shellcheck source=../../utils/utils.sh
-source "$UTILSSH"
-
-run_python_bt2_test "${BT_TESTS_SRCDIR}/plugins/sink.text.pretty" "test_*"
diff --git a/tests/plugins/sink.text.pretty/test_pretty_python b/tests/plugins/sink.text.pretty/test_pretty_python
new file mode 100755 (executable)
index 0000000..3fdac62
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2017 Philippe Proulx <pproulx@efficios.com>
+#
+
+if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
+       UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
+else
+       UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+source "$UTILSSH"
+
+run_python_bt2_test "${BT_TESTS_SRCDIR}/plugins/sink.text.pretty" "test_*"
diff --git a/tests/utils/python/split_sort_compare.py b/tests/utils/python/split_sort_compare.py
new file mode 100644 (file)
index 0000000..3b4f83d
--- /dev/null
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
+
+import sys
+import re
+
+
+def main():
+    expected = sys.argv[1]
+    actual = sys.argv[2]
+    sorted_expected = ''.join(sorted(re.findall(r'\w+|\W+', expected.strip())))
+    sorted_actual = ''.join(sorted(re.findall(r'\w+|\W+', actual.strip())))
+
+    if sorted_expected == sorted_actual:
+        status = 0
+    else:
+        status = 1
+
+    sys.exit(status)
+
+
+if __name__ == '__main__':
+    main()
This page took 0.030518 seconds and 4 git commands to generate.