diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/spdk/test/unit/lib/event | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/spdk/test/unit/lib/event')
-rw-r--r-- | src/spdk/test/unit/lib/event/Makefile | 44 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/app.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/app.c/Makefile | 39 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/app.c/app_ut.c | 193 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/reactor.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/reactor.c/Makefile | 39 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/reactor.c/reactor_ut.c | 455 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/subsystem.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/subsystem.c/Makefile | 38 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/event/subsystem.c/subsystem_ut.c | 255 |
10 files changed, 1066 insertions, 0 deletions
diff --git a/src/spdk/test/unit/lib/event/Makefile b/src/spdk/test/unit/lib/event/Makefile new file mode 100644 index 000000000..ea411460c --- /dev/null +++ b/src/spdk/test/unit/lib/event/Makefile @@ -0,0 +1,44 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +DIRS-y = subsystem.c app.c reactor.c + +.PHONY: all clean $(DIRS-y) + +all: $(DIRS-y) +clean: $(DIRS-y) + +include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk diff --git a/src/spdk/test/unit/lib/event/app.c/.gitignore b/src/spdk/test/unit/lib/event/app.c/.gitignore new file mode 100644 index 000000000..123e16734 --- /dev/null +++ b/src/spdk/test/unit/lib/event/app.c/.gitignore @@ -0,0 +1 @@ +app_ut diff --git a/src/spdk/test/unit/lib/event/app.c/Makefile b/src/spdk/test/unit/lib/event/app.c/Makefile new file mode 100644 index 000000000..9ec2b97db --- /dev/null +++ b/src/spdk/test/unit/lib/event/app.c/Makefile @@ -0,0 +1,39 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) + +SPDK_LIB_LIST = conf trace jsonrpc json +TEST_FILE = app_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/event/app.c/app_ut.c b/src/spdk/test/unit/lib/event/app.c/app_ut.c new file mode 100644 index 000000000..6077d6600 --- /dev/null +++ b/src/spdk/test/unit/lib/event/app.c/app_ut.c @@ -0,0 +1,193 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" +#include "common/lib/test_env.c" +#include "event/app.c" + +#define test_argc 6 + +DEFINE_STUB_V(spdk_event_call, (struct spdk_event *event)); +DEFINE_STUB(spdk_event_allocate, struct spdk_event *, (uint32_t core, spdk_event_fn fn, void *arg1, + void *arg2), NULL); +DEFINE_STUB_V(spdk_subsystem_init, (spdk_subsystem_init_fn cb_fn, void *cb_arg)); +DEFINE_STUB_V(spdk_rpc_register_method, (const char *method, spdk_rpc_method_handler func, + uint32_t state_mask)); +DEFINE_STUB_V(spdk_rpc_register_alias_deprecated, (const char *method, const char *alias)); +DEFINE_STUB_V(spdk_rpc_set_state, (uint32_t state)); +DEFINE_STUB(spdk_rpc_get_state, uint32_t, (void), SPDK_RPC_RUNTIME); +DEFINE_STUB_V(spdk_app_json_config_load, (const char *json_config_file, const char *rpc_addr, + spdk_subsystem_init_fn cb_fn, void *cb_arg, bool stop_on_error)); + +static void +unittest_usage(void) +{ +} + +static int +unittest_parse_args(int ch, char *arg) +{ + return 0; +} + +static void +clean_opts(struct spdk_app_opts *opts) +{ + free(opts->pci_whitelist); + opts->pci_whitelist = NULL; + free(opts->pci_blacklist); + opts->pci_blacklist = NULL; + memset(opts, 0, sizeof(struct spdk_app_opts)); +} + +static void +test_spdk_app_parse_args(void) +{ + spdk_app_parse_args_rvals_t rc; + struct spdk_app_opts opts = {}; + struct option my_options[2] = {}; + char *valid_argv[test_argc] = {"app_ut", + "--wait-for-rpc", + "-d", + "-p0", + "-B", + "0000:81:00.0" + }; + char *invalid_argv_BW[test_argc] = {"app_ut", + "-B", + "0000:81:00.0", + "-W", + "0000:82:00.0", + "-cspdk.conf" + }; + /* currently use -z as our new option */ + char *argv_added_short_opt[test_argc] = {"app_ut", + "-z", + "-d", + "--wait-for-rpc", + "-p0", + "-cspdk.conf" + }; + char *argv_added_long_opt[test_argc] = {"app_ut", + "-cspdk.conf", + "-d", + "-r/var/tmp/spdk.sock", + "--test-long-opt", + "--wait-for-rpc" + }; + char *invalid_argv_missing_option[test_argc] = {"app_ut", + "-d", + "-p", + "--wait-for-rpc", + "--silence-noticelog" + "-R" + }; + + /* Test valid arguments. Expected result: PASS */ + rc = spdk_app_parse_args(test_argc, valid_argv, &opts, "", NULL, unittest_parse_args, NULL); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_SUCCESS); + optind = 1; + clean_opts(&opts); + + /* Test invalid short option Expected result: FAIL */ + rc = spdk_app_parse_args(test_argc, argv_added_short_opt, &opts, "", NULL, unittest_parse_args, + NULL); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_FAIL); + optind = 1; + clean_opts(&opts); + + /* Test valid global and local options. Expected result: PASS */ + rc = spdk_app_parse_args(test_argc, argv_added_short_opt, &opts, "z", NULL, unittest_parse_args, + unittest_usage); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_SUCCESS); + optind = 1; + clean_opts(&opts); + + /* Test invalid long option Expected result: FAIL */ + rc = spdk_app_parse_args(test_argc, argv_added_long_opt, &opts, "", NULL, unittest_parse_args, + NULL); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_FAIL); + optind = 1; + clean_opts(&opts); + + /* Test valid global and local options. Expected result: PASS */ + my_options[0].name = "test-long-opt"; + rc = spdk_app_parse_args(test_argc, argv_added_long_opt, &opts, "", my_options, unittest_parse_args, + unittest_usage); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_SUCCESS); + optind = 1; + clean_opts(&opts); + + /* Test overlapping global and local options. Expected result: FAIL */ + rc = spdk_app_parse_args(test_argc, valid_argv, &opts, SPDK_APP_GETOPT_STRING, NULL, + unittest_parse_args, NULL); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_FAIL); + optind = 1; + clean_opts(&opts); + + /* Specify -B and -W options at the same time. Expected result: FAIL */ + rc = spdk_app_parse_args(test_argc, invalid_argv_BW, &opts, "", NULL, unittest_parse_args, NULL); + SPDK_CU_ASSERT_FATAL(rc == SPDK_APP_PARSE_ARGS_FAIL); + optind = 1; + clean_opts(&opts); + + /* Omit necessary argument to option */ + rc = spdk_app_parse_args(test_argc, invalid_argv_missing_option, &opts, "", NULL, + unittest_parse_args, NULL); + CU_ASSERT_EQUAL(rc, SPDK_APP_PARSE_ARGS_FAIL); + optind = 1; + clean_opts(&opts); +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + CU_set_error_action(CUEA_ABORT); + CU_initialize_registry(); + + suite = CU_add_suite("app_suite", NULL, NULL); + + CU_ADD_TEST(suite, test_spdk_app_parse_args); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/src/spdk/test/unit/lib/event/reactor.c/.gitignore b/src/spdk/test/unit/lib/event/reactor.c/.gitignore new file mode 100644 index 000000000..c86b7dfcd --- /dev/null +++ b/src/spdk/test/unit/lib/event/reactor.c/.gitignore @@ -0,0 +1 @@ +reactor_ut diff --git a/src/spdk/test/unit/lib/event/reactor.c/Makefile b/src/spdk/test/unit/lib/event/reactor.c/Makefile new file mode 100644 index 000000000..f7b3b5887 --- /dev/null +++ b/src/spdk/test/unit/lib/event/reactor.c/Makefile @@ -0,0 +1,39 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) + +SPDK_LIB_LIST = conf trace jsonrpc json +TEST_FILE = reactor_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/event/reactor.c/reactor_ut.c b/src/spdk/test/unit/lib/event/reactor.c/reactor_ut.c new file mode 100644 index 000000000..db50ea2f6 --- /dev/null +++ b/src/spdk/test/unit/lib/event/reactor.c/reactor_ut.c @@ -0,0 +1,455 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" +#include "common/lib/test_env.c" +#include "event/reactor.c" + +static void +test_create_reactor(void) +{ + struct spdk_reactor reactor = {}; + + g_reactors = &reactor; + + reactor_construct(&reactor, 0); + + CU_ASSERT(spdk_reactor_get(0) == &reactor); + + spdk_ring_free(reactor.events); + g_reactors = NULL; +} + +static void +test_init_reactors(void) +{ + uint32_t core; + + allocate_cores(3); + + CU_ASSERT(spdk_reactors_init() == 0); + + CU_ASSERT(g_reactor_state == SPDK_REACTOR_STATE_INITIALIZED); + for (core = 0; core < 3; core++) { + CU_ASSERT(spdk_reactor_get(core) != NULL); + } + + spdk_reactors_fini(); + + free_cores(); +} + +static void +ut_event_fn(void *arg1, void *arg2) +{ + uint8_t *test1 = arg1; + uint8_t *test2 = arg2; + + *test1 = 1; + *test2 = 0xFF; +} + +static void +test_event_call(void) +{ + uint8_t test1 = 0, test2 = 0; + struct spdk_event *evt; + struct spdk_reactor *reactor; + + allocate_cores(1); + + CU_ASSERT(spdk_reactors_init() == 0); + + evt = spdk_event_allocate(0, ut_event_fn, &test1, &test2); + CU_ASSERT(evt != NULL); + + spdk_event_call(evt); + + reactor = spdk_reactor_get(0); + CU_ASSERT(reactor != NULL); + + CU_ASSERT(event_queue_run_batch(reactor) == 1); + CU_ASSERT(test1 == 1); + CU_ASSERT(test2 == 0xFF); + + spdk_reactors_fini(); + + free_cores(); +} + +static void +test_schedule_thread(void) +{ + struct spdk_cpuset cpuset = {}; + struct spdk_thread *thread; + struct spdk_reactor *reactor; + struct spdk_lw_thread *lw_thread; + + allocate_cores(5); + + CU_ASSERT(spdk_reactors_init() == 0); + + spdk_cpuset_set_cpu(&cpuset, 3, true); + g_next_core = 4; + + /* _reactor_schedule_thread() will be called in spdk_thread_create() + * at its end because it is passed to SPDK thread library by + * spdk_thread_lib_init(). + */ + thread = spdk_thread_create(NULL, &cpuset); + CU_ASSERT(thread != NULL); + + reactor = spdk_reactor_get(3); + CU_ASSERT(reactor != NULL); + + MOCK_SET(spdk_env_get_current_core, 3); + + CU_ASSERT(event_queue_run_batch(reactor) == 1); + + MOCK_CLEAR(spdk_env_get_current_core); + + lw_thread = TAILQ_FIRST(&reactor->threads); + CU_ASSERT(lw_thread != NULL); + CU_ASSERT(spdk_thread_get_from_ctx(lw_thread) == thread); + + TAILQ_REMOVE(&reactor->threads, lw_thread, link); + reactor->thread_count--; + spdk_set_thread(thread); + spdk_thread_exit(thread); + while (!spdk_thread_is_exited(thread)) { + spdk_thread_poll(thread, 0, 0); + } + spdk_thread_destroy(thread); + spdk_set_thread(NULL); + + spdk_reactors_fini(); + + free_cores(); +} + +static void +test_reschedule_thread(void) +{ + struct spdk_cpuset cpuset = {}; + struct spdk_thread *thread; + struct spdk_reactor *reactor; + struct spdk_lw_thread *lw_thread; + + allocate_cores(3); + + CU_ASSERT(spdk_reactors_init() == 0); + + spdk_cpuset_set_cpu(&g_reactor_core_mask, 0, true); + spdk_cpuset_set_cpu(&g_reactor_core_mask, 1, true); + spdk_cpuset_set_cpu(&g_reactor_core_mask, 2, true); + g_next_core = 0; + + /* Create and schedule the thread to core 1. */ + spdk_cpuset_set_cpu(&cpuset, 1, true); + + thread = spdk_thread_create(NULL, &cpuset); + CU_ASSERT(thread != NULL); + lw_thread = spdk_thread_get_ctx(thread); + + reactor = spdk_reactor_get(1); + CU_ASSERT(reactor != NULL); + MOCK_SET(spdk_env_get_current_core, 1); + + CU_ASSERT(event_queue_run_batch(reactor) == 1); + CU_ASSERT(TAILQ_FIRST(&reactor->threads) == lw_thread); + + spdk_set_thread(thread); + + /* Call spdk_thread_set_cpumask() twice with different cpumask values. + * The cpumask of the 2nd call will be used in reschedule operation. + */ + + spdk_cpuset_zero(&cpuset); + spdk_cpuset_set_cpu(&cpuset, 0, true); + CU_ASSERT(spdk_thread_set_cpumask(&cpuset) == 0); + + spdk_cpuset_zero(&cpuset); + spdk_cpuset_set_cpu(&cpuset, 2, true); + CU_ASSERT(spdk_thread_set_cpumask(&cpuset) == 0); + + CU_ASSERT(lw_thread->resched == true); + + reactor_run(reactor); + + CU_ASSERT(lw_thread->resched == false); + CU_ASSERT(TAILQ_EMPTY(&reactor->threads)); + + reactor = spdk_reactor_get(0); + CU_ASSERT(reactor != NULL); + MOCK_SET(spdk_env_get_current_core, 0); + + CU_ASSERT(event_queue_run_batch(reactor) == 0); + + reactor = spdk_reactor_get(2); + CU_ASSERT(reactor != NULL); + MOCK_SET(spdk_env_get_current_core, 2); + + CU_ASSERT(event_queue_run_batch(reactor) == 1); + + CU_ASSERT(TAILQ_FIRST(&reactor->threads) == lw_thread); + + MOCK_CLEAR(spdk_env_get_current_core); + + TAILQ_REMOVE(&reactor->threads, lw_thread, link); + reactor->thread_count--; + spdk_set_thread(thread); + spdk_thread_exit(thread); + while (!spdk_thread_is_exited(thread)) { + spdk_thread_poll(thread, 0, 0); + } + spdk_thread_destroy(thread); + spdk_set_thread(NULL); + + spdk_reactors_fini(); + + free_cores(); +} + +static void +for_each_reactor_done(void *arg1, void *arg2) +{ + uint32_t *count = arg1; + bool *done = arg2; + + (*count)++; + *done = true; +} + +static void +for_each_reactor_cb(void *arg1, void *arg2) +{ + uint32_t *count = arg1; + + (*count)++; +} + +static void +test_for_each_reactor(void) +{ + uint32_t count = 0, i; + bool done = false; + struct spdk_reactor *reactor; + + allocate_cores(5); + + CU_ASSERT(spdk_reactors_init() == 0); + + MOCK_SET(spdk_env_get_current_core, 0); + + spdk_for_each_reactor(for_each_reactor_cb, &count, &done, for_each_reactor_done); + + MOCK_CLEAR(spdk_env_get_current_core); + + /* We have not processed any event yet, so count and done should be 0 and false, + * respectively. + */ + CU_ASSERT(count == 0); + + /* Poll each reactor to verify the event is passed to each */ + for (i = 0; i < 5; i++) { + reactor = spdk_reactor_get(i); + CU_ASSERT(reactor != NULL); + + event_queue_run_batch(reactor); + CU_ASSERT(count == (i + 1)); + CU_ASSERT(done == false); + } + + /* After each reactor is called, the completion calls it one more time. */ + reactor = spdk_reactor_get(0); + CU_ASSERT(reactor != NULL); + + event_queue_run_batch(reactor); + CU_ASSERT(count == 6); + CU_ASSERT(done == true); + + spdk_reactors_fini(); + + free_cores(); +} + +static int +poller_run_idle(void *ctx) +{ + uint64_t delay_us = (uint64_t)ctx; + + spdk_delay_us(delay_us); + + return 0; +} + +static int +poller_run_busy(void *ctx) +{ + uint64_t delay_us = (uint64_t)ctx; + + spdk_delay_us(delay_us); + + return 1; +} + +static void +test_reactor_stats(void) +{ + struct spdk_cpuset cpuset = {}; + struct spdk_thread *thread1, *thread2; + struct spdk_reactor *reactor; + struct spdk_poller *busy1, *idle1, *busy2, *idle2; + int rc __attribute__((unused)); + + /* Test case is the following: + * Create a reactor on CPU core0. + * Create thread1 and thread2 simultaneously on reactor0 at TSC = 100. + * Reactor runs + * - thread1 for 100 with busy + * - thread2 for 200 with idle + * - thread1 for 300 with idle + * - thread2 for 400 with busy. + * Then, + * - both elapsed TSC of thread1 and thread2 should be 1000 (= 100 + 900). + * - busy TSC of reactor should be 500 (= 100 + 400). + * - idle TSC of reactor should be 500 (= 200 + 300). + */ + + allocate_cores(1); + + CU_ASSERT(spdk_reactors_init() == 0); + + spdk_cpuset_set_cpu(&cpuset, 0, true); + + MOCK_SET(spdk_env_get_current_core, 0); + MOCK_SET(spdk_get_ticks, 100); + + thread1 = spdk_thread_create(NULL, &cpuset); + SPDK_CU_ASSERT_FATAL(thread1 != NULL); + + thread2 = spdk_thread_create(NULL, &cpuset); + SPDK_CU_ASSERT_FATAL(thread2 != NULL); + + reactor = spdk_reactor_get(0); + SPDK_CU_ASSERT_FATAL(reactor != NULL); + + reactor->tsc_last = 100; + + spdk_set_thread(thread1); + busy1 = spdk_poller_register(poller_run_busy, (void *)100, 0); + CU_ASSERT(busy1 != NULL); + + spdk_set_thread(thread2); + idle2 = spdk_poller_register(poller_run_idle, (void *)300, 0); + CU_ASSERT(idle2 != NULL); + + _reactor_run(reactor); + + CU_ASSERT(thread1->tsc_last == 200); + CU_ASSERT(thread1->stats.busy_tsc == 100); + CU_ASSERT(thread1->stats.idle_tsc == 0); + CU_ASSERT(thread2->tsc_last == 500); + CU_ASSERT(thread2->stats.busy_tsc == 0); + CU_ASSERT(thread2->stats.idle_tsc == 300); + + CU_ASSERT(reactor->busy_tsc == 100); + CU_ASSERT(reactor->idle_tsc == 300); + + spdk_set_thread(thread1); + spdk_poller_unregister(&busy1); + idle1 = spdk_poller_register(poller_run_idle, (void *)200, 0); + CU_ASSERT(idle1 != NULL); + + spdk_set_thread(thread2); + spdk_poller_unregister(&idle2); + busy2 = spdk_poller_register(poller_run_busy, (void *)400, 0); + CU_ASSERT(busy2 != NULL); + + _reactor_run(reactor); + + CU_ASSERT(thread1->tsc_last == 700); + CU_ASSERT(thread1->stats.busy_tsc == 100); + CU_ASSERT(thread1->stats.idle_tsc == 200); + CU_ASSERT(thread2->tsc_last == 1100); + CU_ASSERT(thread2->stats.busy_tsc == 400); + CU_ASSERT(thread2->stats.idle_tsc == 300); + + CU_ASSERT(reactor->busy_tsc == 500); + CU_ASSERT(reactor->idle_tsc == 500); + + spdk_set_thread(thread1); + spdk_poller_unregister(&idle1); + spdk_thread_exit(thread1); + + spdk_set_thread(thread2); + spdk_poller_unregister(&busy2); + spdk_thread_exit(thread2); + + _reactor_run(reactor); + + CU_ASSERT(TAILQ_EMPTY(&reactor->threads)); + + spdk_reactors_fini(); + + free_cores(); +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + CU_set_error_action(CUEA_ABORT); + CU_initialize_registry(); + + suite = CU_add_suite("app_suite", NULL, NULL); + + CU_ADD_TEST(suite, test_create_reactor); + CU_ADD_TEST(suite, test_init_reactors); + CU_ADD_TEST(suite, test_event_call); + CU_ADD_TEST(suite, test_schedule_thread); + CU_ADD_TEST(suite, test_reschedule_thread); + CU_ADD_TEST(suite, test_for_each_reactor); + CU_ADD_TEST(suite, test_reactor_stats); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} diff --git a/src/spdk/test/unit/lib/event/subsystem.c/.gitignore b/src/spdk/test/unit/lib/event/subsystem.c/.gitignore new file mode 100644 index 000000000..76ca0d330 --- /dev/null +++ b/src/spdk/test/unit/lib/event/subsystem.c/.gitignore @@ -0,0 +1 @@ +subsystem_ut diff --git a/src/spdk/test/unit/lib/event/subsystem.c/Makefile b/src/spdk/test/unit/lib/event/subsystem.c/Makefile new file mode 100644 index 000000000..b62f1ee1a --- /dev/null +++ b/src/spdk/test/unit/lib/event/subsystem.c/Makefile @@ -0,0 +1,38 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) + +TEST_FILE = subsystem_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/event/subsystem.c/subsystem_ut.c b/src/spdk/test/unit/lib/event/subsystem.c/subsystem_ut.c new file mode 100644 index 000000000..deeb2f3aa --- /dev/null +++ b/src/spdk/test/unit/lib/event/subsystem.c/subsystem_ut.c @@ -0,0 +1,255 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk/stdinc.h" + +#include "spdk_cunit.h" + +#include "unit/lib/json_mock.c" +#include "event/subsystem.c" +#include "common/lib/test_env.c" + +static struct spdk_subsystem g_ut_subsystems[8]; +static struct spdk_subsystem_depend g_ut_subsystem_deps[8]; +static int global_rc; + +static void +ut_event_fn(int rc, void *arg1) +{ + global_rc = rc; +} + +static void +set_up_subsystem(struct spdk_subsystem *subsystem, const char *name) +{ + subsystem->init = NULL; + subsystem->fini = NULL; + subsystem->config = NULL; + subsystem->name = name; +} + +static void +set_up_depends(struct spdk_subsystem_depend *depend, const char *subsystem_name, + const char *dpends_on_name) +{ + depend->name = subsystem_name; + depend->depends_on = dpends_on_name; +} + +static void +subsystem_clear(void) +{ + struct spdk_subsystem *subsystem, *subsystem_tmp; + struct spdk_subsystem_depend *subsystem_dep, *subsystem_dep_tmp; + + TAILQ_FOREACH_SAFE(subsystem, &g_subsystems, tailq, subsystem_tmp) { + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + } + + TAILQ_FOREACH_SAFE(subsystem_dep, &g_subsystems_deps, tailq, subsystem_dep_tmp) { + TAILQ_REMOVE(&g_subsystems_deps, subsystem_dep, tailq); + } +} + +static void +subsystem_sort_test_depends_on_single(void) +{ + struct spdk_subsystem *subsystem; + int i; + char subsystem_name[16]; + + global_rc = -1; + spdk_subsystem_init(ut_event_fn, NULL); + CU_ASSERT(global_rc == 0); + + i = 4; + TAILQ_FOREACH(subsystem, &g_subsystems, tailq) { + snprintf(subsystem_name, sizeof(subsystem_name), "subsystem%d", i); + SPDK_CU_ASSERT_FATAL(i > 0); + i--; + CU_ASSERT(strcmp(subsystem_name, subsystem->name) == 0); + } +} + +static void +subsystem_sort_test_depends_on_multiple(void) +{ + int i; + struct spdk_subsystem *subsystem; + + subsystem_clear(); + set_up_subsystem(&g_ut_subsystems[0], "iscsi"); + set_up_subsystem(&g_ut_subsystems[1], "nvmf"); + set_up_subsystem(&g_ut_subsystems[2], "sock"); + set_up_subsystem(&g_ut_subsystems[3], "bdev"); + set_up_subsystem(&g_ut_subsystems[4], "rpc"); + set_up_subsystem(&g_ut_subsystems[5], "scsi"); + set_up_subsystem(&g_ut_subsystems[6], "interface"); + set_up_subsystem(&g_ut_subsystems[7], "accel"); + + for (i = 0; i < 8; i++) { + spdk_add_subsystem(&g_ut_subsystems[i]); + } + + set_up_depends(&g_ut_subsystem_deps[0], "bdev", "accel"); + set_up_depends(&g_ut_subsystem_deps[1], "scsi", "bdev"); + set_up_depends(&g_ut_subsystem_deps[2], "rpc", "interface"); + set_up_depends(&g_ut_subsystem_deps[3], "sock", "interface"); + set_up_depends(&g_ut_subsystem_deps[4], "nvmf", "interface"); + set_up_depends(&g_ut_subsystem_deps[5], "iscsi", "scsi"); + set_up_depends(&g_ut_subsystem_deps[6], "iscsi", "sock"); + set_up_depends(&g_ut_subsystem_deps[7], "iscsi", "rpc"); + + for (i = 0; i < 8; i++) { + spdk_add_subsystem_depend(&g_ut_subsystem_deps[i]); + } + + global_rc = -1; + spdk_subsystem_init(ut_event_fn, NULL); + CU_ASSERT(global_rc == 0); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "interface") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "accel") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "nvmf") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "sock") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "bdev") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "rpc") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "scsi") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); + + subsystem = TAILQ_FIRST(&g_subsystems); + CU_ASSERT(strcmp(subsystem->name, "iscsi") == 0); + TAILQ_REMOVE(&g_subsystems, subsystem, tailq); +} + +struct spdk_subsystem subsystem1 = { + .name = "subsystem1", +}; + +struct spdk_subsystem subsystem2 = { + .name = "subsystem2", +}; +struct spdk_subsystem subsystem3 = { + .name = "subsystem3", +}; + +struct spdk_subsystem subsystem4 = { + .name = "subsystem4", +}; + +SPDK_SUBSYSTEM_REGISTER(subsystem1); +SPDK_SUBSYSTEM_REGISTER(subsystem2); +SPDK_SUBSYSTEM_REGISTER(subsystem3); +SPDK_SUBSYSTEM_REGISTER(subsystem4); + +SPDK_SUBSYSTEM_DEPEND(subsystem1, subsystem2) +SPDK_SUBSYSTEM_DEPEND(subsystem2, subsystem3) +SPDK_SUBSYSTEM_DEPEND(subsystem3, subsystem4) + + +static void +subsystem_sort_test_missing_dependency(void) +{ + /* + * A depends on B, but B is missing + */ + + subsystem_clear(); + set_up_subsystem(&g_ut_subsystems[0], "A"); + spdk_add_subsystem(&g_ut_subsystems[0]); + + set_up_depends(&g_ut_subsystem_deps[0], "A", "B"); + spdk_add_subsystem_depend(&g_ut_subsystem_deps[0]); + + global_rc = -1; + spdk_subsystem_init(ut_event_fn, NULL); + CU_ASSERT(global_rc != 0); + + /* + * Dependency from C to A is defined, but C is missing + */ + + subsystem_clear(); + set_up_subsystem(&g_ut_subsystems[0], "A"); + spdk_add_subsystem(&g_ut_subsystems[0]); + + set_up_depends(&g_ut_subsystem_deps[0], "C", "A"); + spdk_add_subsystem_depend(&g_ut_subsystem_deps[0]); + + global_rc = -1; + spdk_subsystem_init(ut_event_fn, NULL); + CU_ASSERT(global_rc != 0); + +} + +int +main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + CU_set_error_action(CUEA_ABORT); + CU_initialize_registry(); + + suite = CU_add_suite("subsystem_suite", NULL, NULL); + + CU_ADD_TEST(suite, subsystem_sort_test_depends_on_single); + CU_ADD_TEST(suite, subsystem_sort_test_depends_on_multiple); + CU_ADD_TEST(suite, subsystem_sort_test_missing_dependency); + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} |