]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
devguide: repurpose unittests page to unittests-c
authorJuliana Fajardini <jufajardini@gmail.com>
Wed, 3 Nov 2021 10:59:20 +0000 (10:59 +0000)
committerVictor Julien <victor@inliniac.net>
Sat, 6 Nov 2021 15:24:41 +0000 (16:24 +0100)
Part of ongoing task to add more guidance on how to create unittests
and suricata-verify tests for suri. There will also be a unittests-rust
page.

Doc: #4590

doc/devguide/Makefile.am
doc/devguide/codebase/index.rst
doc/devguide/codebase/unittests-c.rst [new file with mode: 0644]
doc/devguide/codebase/unittests.rst [deleted file]

index b9a64246269df0e806a03ddfca0b4fbc3c44a7b8..57c9704f61085b6f7682fc0dec7d38b8cd6d7673 100644 (file)
@@ -15,13 +15,13 @@ EXTRA_DIST = \
        internals/index.rst \
        internals/pipeline/index.rst \
        internals/datastructs/index.rst \
-       codebase/unittests.rst \
        codebase/index.rst \
        codebase/code-style.rst \
        codebase/contributing/code-submission-process.rst \
        codebase/contributing/index.rst \
        codebase/fuzz-testing.rst \
-       codebase/testing.rst
+       codebase/testing.rst \
+       codebase/unittests-c.rst
 
 if HAVE_SPHINXBUILD
 if HAVE_MSCGEN
index 180080fbb7b754159552f047ae29f8adb8b1e9f1..b868bc09a4706d93e275f73ae707651bd9459876 100644 (file)
@@ -6,6 +6,6 @@ Working with the Codebase
 
    contributing/index.rst
    code-style
-   unittests
    fuzz-testing
    testing
+   unittests-c
diff --git a/doc/devguide/codebase/unittests-c.rst b/doc/devguide/codebase/unittests-c.rst
new file mode 100644 (file)
index 0000000..2465366
--- /dev/null
@@ -0,0 +1,148 @@
+**************
+Unit Tests - C
+**************
+
+Unit tests are a great way to create tests that can check the internal state
+of parsers, structures and other objects.
+
+Tests should:
+
+- use ``FAIL``/``PASS`` macros
+- be deterministic
+- not leak memory on ``PASS``
+- not use conditions
+
+Unit tests are used by developers of Suricata and advanced users who would like to contribute by debugging and testing the engine.
+Unit tests are small pieces (units) of code which check certain code functionalities in Suricata. If Suricata's code is modified, developers can run unit tests to see if there are any unforeseen effects on other parts of the engine's code.
+Unit tests will not be compiled with Suricata by default.
+If you would like to compile Suricata with unit tests, enter the following during the configure-stage::
+
+   ./configure --enable-unittests
+
+The unit tests specific command line options can be found at `Command Line Options <https://suricata.readthedocs.io/en/suricata-6.0.3/command-line-options.html#unit-tests>`_.
+
+Example:
+You can run tests specifically on flowbits. This is how you should do that::
+
+   suricata -u -U flowbit
+
+It is highly appreciated if you would run unit tests and report failing tests in our `issue tracker
+<https://redmine.openinfosecfoundation.org/projects/suricata/issues>`_.
+
+If you want more info about the unittests, regular debug mode can help. This is enabled by adding the configure option::
+
+    --enable-debug
+
+Then, set the debug level from the commandline::
+
+    SC_LOG_LEVEL=Debug suricata -u
+
+This will be very verbose. You can also add the ``SC_LOG_OP_FILTER`` to limit the output, it is grep-like::
+
+    SC_LOG_LEVEL=Debug SC_LOG_OP_FILTER="(something|somethingelse)" suricata -u
+
+This example will show all lines (debug, info, and all other levels) that contain either something or something else.
+Keep in mind the `log level <https://suricata.readthedocs.io/en/latest/manpages/suricata.html#id1>`_  precedence: if you choose *Info* level, for instance, Suricata won't show messages from the other levels.
+
+Writing Unit Tests - C codebase
+===============================
+
+Suricata unit tests are somewhat different in C and in Rust. In C, they are comprised of a function with no arguments and returning 0 for failure or 1 for success. Instead of explicitly returning a value, FAIL_* and PASS macros should be used. For example:
+
+.. code-block:: c
+
+    void MyUnitTest(void)
+    {
+        int n = 1;
+        void *p = NULL;
+
+        FAIL_IF(n != 1);
+        FAIL_IF_NOT(n == 1);
+        FAIL_IF_NOT_NULL(p);
+        FAIL_IF_NULL(p);
+
+        PASS;
+    }
+
+Each unit test needs to be registered with ``UtRegisterTest()``. Example::
+
+    UtRegisterTest("MyUnitTest", MyUnitTest);
+
+where the first argument is the name of the test, and the second argument is the function. Existing modules should already have a function that registers its unit tests. Otherwise the unit tests will need to be registered. Look for a module similar to your new module to see how best to register the unit tests or ask the development team for help.
+
+Examples
+--------
+
+From ``conf-yaml-loader.c``:
+
+.. code-block:: c
+
+    /**
+     * Test that a configuration section is overridden but subsequent
+     * occurrences.
+     */
+    static int
+    ConfYamlOverrideTest(void)
+    {
+        char config[] =
+            "%YAML 1.1\n"
+            "---\n"
+            "some-log-dir: /var/log\n"
+            "some-log-dir: /tmp\n"
+            "\n"
+            "parent:\n"
+            "  child0:\n"
+            "    key: value\n"
+            "parent:\n"
+            "  child1:\n"
+            "    key: value\n"
+            ;
+        const char *value;
+
+        ConfCreateContextBackup();
+        ConfInit();
+
+        FAIL_IF(ConfYamlLoadString(config, strlen(config)) != 0);
+        FAIL_IF_NOT(ConfGet("some-log-dir", &value));
+        FAIL_IF(strcmp(value, "/tmp") != 0);
+
+        /* Test that parent.child0 does not exist, but child1 does. */
+        FAIL_IF_NOT_NULL(ConfGetNode("parent.child0"));
+        FAIL_IF_NOT(ConfGet("parent.child1.key", &value));
+        FAIL_IF(strcmp(value, "value") != 0);
+
+        ConfDeInit();
+        ConfRestoreContextBackup();
+
+        PASS;
+    }
+
+In ``detect-ike-chosen-sa.c``, it is possible to see the freeing of resources (``DetectIkeChosenSaFree``) and the
+function that should group all the ``UtRegisterTest`` calls:
+
+.. code-block:: c
+
+    #ifdef UNITTESTS
+    .
+    .
+    .
+    static int IKEChosenSaParserTest(void)
+    {
+        DetectIkeChosenSaData *de = NULL;
+        de = DetectIkeChosenSaParse("alg_hash=2");
+
+        FAIL_IF_NULL(de);
+        FAIL_IF(de->sa_value != 2);
+        FAIL_IF(strcmp(de->sa_type, "alg_hash") != 0);
+
+        DetectIkeChosenSaFree(NULL, de);
+        PASS;
+    }
+
+    #endif /* UNITTESTS */
+
+    void IKEChosenSaRegisterTests(void)
+    {
+    #ifdef UNITTESTS
+        UtRegisterTest("IKEChosenSaParserTest", IKEChosenSaParserTest);
+    #endif /* UNITTESTS */
diff --git a/doc/devguide/codebase/unittests.rst b/doc/devguide/codebase/unittests.rst
deleted file mode 100644 (file)
index a8be84a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-Unittests
-=========
-
-Unittests are a great way to create tests that can check the internal state
-of parsers, structures and other objects.
-
-Tests should:
-
-- use FAIL/PASS macros
-- be deterministic
-- not leak memory on PASS
-- not use conditions