@@ -366,3 +366,15 @@ AC_DEFUN([OVN_CHECK_OVS], [
AC_SUBST(OVSVERSION)
AC_MSG_RESULT([OVS version is $OVSVERSION])
])
+
+AC_DEFUN([OVN_ENABLE_UNIT_TESTS],
+ [AC_ARG_ENABLE(
+ [unit_tests],
+ [AC_HELP_STRING([--enable-unit-tests], [Enable unit test framework])],
+ [], [enable_unit_tests=no])
+ AC_CONFIG_COMMANDS_PRE(
+ [if test "X$enable_unit_tests" = Xyes; then
+ OVS_CFLAGS="$OVS_CFLAGS -DENABLE_UNIT_TESTS"
+ fi])
+
+ AC_SUBST([enable_unit_tests])])
@@ -166,6 +166,7 @@ OVS_CONDITIONAL_CC_OPTION([-Wno-unused], [HAVE_WNO_UNUSED])
OVS_CONDITIONAL_CC_OPTION([-Wno-unused-parameter], [HAVE_WNO_UNUSED_PARAMETER])
OVS_ENABLE_WERROR
OVS_ENABLE_SPARSE
+OVN_ENABLE_UNIT_TESTS
OVS_CHECK_PRAGMA_MESSAGE
OVN_CHECK_OVS
@@ -23,7 +23,9 @@ lib_libovn_la_SOURCES = \
lib/ovn-util.h \
lib/logical-fields.c \
lib/inc-proc-eng.c \
- lib/inc-proc-eng.h
+ lib/inc-proc-eng.h \
+ lib/unit-test.c \
+ lib/unit-test.h
nodist_lib_libovn_la_SOURCES = \
lib/ovn-dirs.c \
lib/ovn-nb-idl.c \
new file mode 100644
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2020 Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "openvswitch/shash.h"
+#include "openvswitch/dynamic-string.h"
+#include "util.h"
+#include "unixctl.h"
+#include "command-line.h"
+
+#include "lib/unit-test.h"
+
+#ifdef ENABLE_UNIT_TESTS
+static struct shash unit_tests = SHASH_INITIALIZER(&unit_tests);
+
+struct unit_test_data {
+ size_t min_args;
+ size_t max_args;
+ ovs_cmdl_handler cb;
+};
+
+void
+register_unit_test(const char *name, size_t min_args, size_t max_args,
+ ovs_cmdl_handler cb)
+{
+ struct unit_test_data *test_data = xmalloc(sizeof *test_data);
+ test_data->min_args = min_args;
+ test_data->max_args = max_args;
+ test_data->cb = cb;
+ shash_add_once(&unit_tests, name, test_data);
+}
+
+void
+run_unit_test(struct ovs_cmdl_context *ctx)
+{
+ struct unit_test_data *test_data = shash_find_data(&unit_tests,
+ ctx->argv[0]);
+ if (!test_data) {
+ struct ds *output = ctx->pvt;
+ ds_put_format(output, "Unable to find unit test %s\n", ctx->argv[0]);
+ return;
+ }
+
+ int test_args = ctx->argc - 1; /* Ignore test name */
+ if (test_args < test_data->min_args ||
+ test_args > test_data->max_args) {
+ struct ds *output = ctx->pvt;
+ ds_put_format(output, "Invalid number of arguments. "
+ "Minimum: %"PRIuSIZE". Maxium: %"PRIuSIZE". "
+ "Got: %d\n",
+ test_data->min_args, test_data->max_args,
+ test_args);
+ }
+ test_data->cb(ctx);
+}
+
+static void
+unixctl_run_unit_test(struct unixctl_conn *conn, int argc,
+ const char *argv[], void *ignore OVS_UNUSED)
+{
+ if (argc < 2) {
+ unixctl_command_reply_error(conn, "No unit test specified");
+ return;
+ }
+
+ struct ds reply = DS_EMPTY_INITIALIZER;
+ struct ovs_cmdl_context ctx = {
+ .argc = argc - 1,
+ .argv = (char **) argv + 1,
+ .pvt = &reply,
+ };
+ run_unit_test(&ctx);
+ unixctl_command_reply(conn, ds_cstr(&reply));
+
+ ds_destroy(&reply);
+}
+
+void
+register_unixctl_unit_test(void)
+{
+ unixctl_command_register("unit-test", "", 1, UINT_MAX,
+ unixctl_run_unit_test, NULL);
+}
+
+#else /* ENABLE_UNIT_TESTS */
+
+void
+register_unit_test(const char *name OVS_UNUSED, size_t min_args OVS_UNUSED,
+ size_t max_args OVS_UNUSED, ovs_cmdl_handler cb OVS_UNUSED)
+{
+ return;
+}
+
+void
+run_unit_test(struct ovs_cmdl_context *ctx OVS_UNUSED)
+{
+ return;
+}
+
+void
+register_unixctl_unit_test(void)
+{
+ return;
+}
+
+#endif /* ENABLE_UNIT_TESTS */
new file mode 100644
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_UNIT_TEST_H
+#define OVN_UNIT_TEST_H 1
+
+#include "openvswitch/compiler.h"
+#include "command-line.h"
+
+void register_unit_test(const char *name, size_t min_args, size_t max_args,
+ ovs_cmdl_handler cb);
+
+void run_unit_test(struct ovs_cmdl_context *ctx);
+
+void register_unixctl_unit_test(void);
+
+#define UNIT_TEST_DEFINE(NAME, MIN_ARGS, MAX_ARGS, CB) \
+ OVS_CONSTRUCTOR(unit_test_##NAME) { \
+ register_unit_test(#NAME, MIN_ARGS, MAX_ARGS, CB); \
+ }
+#endif
@@ -3,6 +3,7 @@ HAVE_OPENSSL='@HAVE_OPENSSL@'
OPENSSL_SUPPORTS_SNI='@OPENSSL_SUPPORTS_SNI@'
HAVE_UNBOUND='@HAVE_UNBOUND@'
EGREP='@EGREP@'
+ENABLE_UNIT_TESTS='@enable_unit_tests@'
if test x"$PYTHON3" = x; then
PYTHON3='@PYTHON3@'
This creates an API that allows for unit tests to be registered in code by OVN. This change enables the following: * At configure time, "--enable-unit-tests" can be specified to allow for unit tests to be compiled. * This configure-time variable also enables a testsuite variable to be defined, allowing for unit tests to be run from the testsuite. * Testsuite tests are defined using OVS_CONSTRUCTOR, meaning they are automatically registered prior to main() being run in whichever program the unit test is defined in. * Unit tests can be written as standalone programs using the ovstest framework. This works so long as the symbols referenced in the unit test can be found in a header file. Unit tests written in this way don't rely on anything introduced in this commit and have existed in the testsuite via the test-ovn.c file for a while. * Unit tests can also be written within the source of a file and accessed using ovn-appctl. This can be useful for testing private functions within source code. Example: `ovn-appctl -t northd unit-test my-unit-test [args]`. Unit tests written this way require the use of the library introduced in this commit. This commit does not define any unit tests. That is saved for a later commit in this series. Signed-off-by: Mark Michelson <mmichels@redhat.com> --- acinclude.m4 | 12 +++++ configure.ac | 1 + lib/automake.mk | 4 +- lib/unit-test.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++ lib/unit-test.h | 34 ++++++++++++++ tests/atlocal.in | 1 + 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 lib/unit-test.c create mode 100644 lib/unit-test.h