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 run for a given OVN program using ovn-appctl. For example, `ovn-appctl -t northd unit-test my-unit-test`. This commit does not define any unit tests. That is saved for a later commit in this series. Signed-off-by: Mark Michelson <[email protected]> --- acinclude.m4 | 12 +++++ configure.ac | 1 + lib/automake.mk | 4 +- lib/unit-test.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++ lib/unit-test.h | 41 ++++++++++++++++ tests/atlocal.in | 1 + 6 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 lib/unit-test.c create mode 100644 lib/unit-test.h diff --git a/acinclude.m4 b/acinclude.m4 index a797adc82..8b1888075 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -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])]) diff --git a/configure.ac b/configure.ac index 0b17f05b9..613e2ba3d 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/lib/automake.mk b/lib/automake.mk index f3e9c8818..3e9c2a697 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -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 \ diff --git a/lib/unit-test.c b/lib/unit-test.c new file mode 100644 index 000000000..a9eb79e73 --- /dev/null +++ b/lib/unit-test.c @@ -0,0 +1,125 @@ +/* + * 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 "lib/unit-test.h" + +#ifdef ENABLE_UNIT_TESTS +static struct shash unit_tests = SHASH_INITIALIZER(&unit_tests); + +struct unit_test_data { + unit_test_cb cb; + void *data; +}; + +void +register_unit_test(const char *name, unit_test_cb cb, void *data) +{ + struct unit_test_data *test_data = xmalloc(sizeof *test_data); + test_data->cb = cb; + test_data->data = data; + shash_add_once(&unit_tests, name, test_data); +} + +enum test_result +run_unit_test(const char *name) +{ + struct unit_test_data *test_data = shash_find_data(&unit_tests, name); + if (!test_data) { + return OVN_TEST_NOT_FOUND; + } + + return test_data->cb(test_data->data); +} + +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; + } + + enum test_result result; + bool error; + struct ds reply = DS_EMPTY_INITIALIZER; + + result = run_unit_test(argv[1]); + switch (result) { + case OVN_TEST_NOT_FOUND: + error = true; + ds_put_format(&reply, "Unit test %s not found", argv[1]); + break; + case OVN_TEST_FAIL: + error = true; + ds_put_format(&reply, "Unit test %s failed", argv[1]); + break; + case OVN_TEST_PASS: + error = false; + ds_put_format(&reply, "Unit test %s passed", argv[1]); + break; + case OVN_TEST_SKIP: + error = false; + ds_put_format(&reply, "Unit test %s skipped", argv[1]); + break; + default: + OVS_NOT_REACHED(); + } + + if (error) { + unixctl_command_reply_error(conn, ds_cstr(&reply)); + } else { + unixctl_command_reply(conn, ds_cstr(&reply)); + } + + ds_destroy(&reply); +} + +void +register_unixctl_unit_test(void) +{ + unixctl_command_register("unit-test", "", 1, 1, + unixctl_run_unit_test, NULL); +} + +#else /* ENABLE_UNIT_TESTS */ + +void +register_unit_test(const char *name OVS_UNUSED, unit_test_cb cb OVS_UNUSED, + void *data OVS_UNUSED) +{ + return; +} + +void +enum test_result run_unit_test(const char *name OVS_UNUSED) +{ + return OVN_TEST_NOT_FOUND; +} + +void register_unixctl_unit_test(void) +{ + return; +} + +#endif /* ENABLE_UNIT_TESTS */ diff --git a/lib/unit-test.h b/lib/unit-test.h new file mode 100644 index 000000000..e89a4d8f6 --- /dev/null +++ b/lib/unit-test.h @@ -0,0 +1,41 @@ +/* + * 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" + +enum test_result { + OVN_TEST_FAIL, + OVN_TEST_PASS, + OVN_TEST_SKIP, + OVN_TEST_NOT_FOUND, +}; + +typedef enum test_result (*unit_test_cb)(void *data); + +void register_unit_test(const char *name, unit_test_cb cb, void *data); + +enum test_result run_unit_test(const char *name); + +void register_unixctl_unit_test(void); + +#define UNIT_TEST_DEFINE(NAME, CB, DATA) \ + OVS_CONSTRUCTOR(unit_test_##NAME) { \ + register_unit_test(#NAME, CB, DATA); \ + } +#endif diff --git a/tests/atlocal.in b/tests/atlocal.in index 26681f02d..ca48ee93d 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -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@' -- 2.25.4 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
