diff --git a/src/utils/ddb/tests/SConscript b/src/utils/ddb/tests/SConscript index 87514b1273c..fe26b85ec11 100644 --- a/src/utils/ddb/tests/SConscript +++ b/src/utils/ddb/tests/SConscript @@ -51,12 +51,14 @@ def scons(): # Required for dtx_act_discard_invalid tests. # This function is validated by its respective unit tests. tenv.AppendUnique(LINKFLAGS=['-Wl,--wrap=vos_dtx_discard_invalid']) + # Required for DDB_CAN_PROCEED tests (vmd_wa_can_proceed failure path). + tenv.AppendUnique(LINKFLAGS=['-Wl,--wrap=vmd_wa_can_proceed']) libs = [ 'uuid', 'daos_common_pmem', 'gurt', 'vea', 'abt', 'bio', 'cmocka', 'pthread', 'pmemobj', 'json-c', ] - src = ['ddb_ut.c', 'ddb_vos_ut.c'] + src = ['ddb_ut.c', 'ddb_vos_ut.c', 'ddb_commands_ut.c'] # vos and mock object files to wrap vos symbols vos_obj = tenv.Object(Glob('../../../vos/*.c')) mock_obj = tenv.Object(Glob('../../../dtx/tests/*_mock.c')) diff --git a/src/utils/ddb/tests/ddb_commands_tests.c b/src/utils/ddb/tests/ddb_commands_tests.c index 382d228be0a..47dc4b7fd98 100644 --- a/src/utils/ddb/tests/ddb_commands_tests.c +++ b/src/utils/ddb/tests/ddb_commands_tests.c @@ -475,6 +475,41 @@ dtx_get_cmt_time(char *buf) return cmt_time; } +static void +open_cmd_tests(void **state) +{ + struct dt_vos_pool_ctx *tctx = *state; + struct ddb_ctx ctx = {0}; + struct open_options opt = {0}; + + ctx.dc_io_ft.ddb_print_message = dvt_fake_print; + ctx.dc_io_ft.ddb_print_error = dvt_fake_print; + + /* Non-existent path: must return DER_INVAL */ + opt.path = "/non/existent/vos-0"; + assert_invalid(ddb_run_open(&ctx, &opt)); + + /* Read-only open: pool handle must be valid, dc_write_mode must be false */ + opt.path = tctx->dvt_pmem_file; + opt.write_mode = false; + assert_success(ddb_run_open(&ctx, &opt)); + assert_true(daos_handle_is_valid(ctx.dc_poh)); + assert_false(ctx.dc_write_mode); + assert_success(ddb_run_close(&ctx)); + + /* Write-mode open: dc_write_mode must be propagated to the context */ + opt.write_mode = true; + assert_success(ddb_run_open(&ctx, &opt)); + assert_true(daos_handle_is_valid(ctx.dc_poh)); + assert_true(ctx.dc_write_mode); + + /* Pool already open: must return DER_BUSY with an error message */ + dvt_fake_print_reset(); + assert_rc_equal(-DER_BUSY, ddb_run_open(&ctx, &opt)); + assert_printed_contains("Cannot operate on an opened pool. Close it first."); + assert_success(ddb_run_close(&ctx)); +} + static void dtx_aggr_tests(void **state) { @@ -621,6 +656,7 @@ ddb_commands_tests_run() TEST(dtx_act_discard_invalid_tests), TEST(dtx_abort_entry_tests), TEST(feature_cmd_tests), + TEST(open_cmd_tests), TEST(dtx_aggr_tests), }; diff --git a/src/utils/ddb/tests/ddb_commands_ut.c b/src/utils/ddb/tests/ddb_commands_ut.c new file mode 100644 index 00000000000..71967d275c7 --- /dev/null +++ b/src/utils/ddb/tests/ddb_commands_ut.c @@ -0,0 +1,133 @@ +/** + * (C) Copyright 2026 Hewlett Packard Enterprise Development LP. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ + +#include +#include +#include +#include +#include + +#include +#include "ddb.h" +#include "ddb_common.h" + +/* ---------------------------------------------------------------- + * Wrapped vmd_wa_can_proceed + * ---------------------------------------------------------------- + * The real function lives in ddb_vmd_wa.c but is intercepted by the linker's + * --wrap mechanism. __real_vmd_wa_can_proceed is the original symbol. + */ +bool +__real_vmd_wa_can_proceed(struct ddb_ctx *ctx, const char *db_path); + +bool +__wrap_vmd_wa_can_proceed(struct ddb_ctx *ctx, const char *db_path) +{ + return mock_type(bool); +} + +/* ---------------------------------------------------------------- + * Fake print helpers (minimal, just for capturing output in these tests) + * ---------------------------------------------------------------- */ +#define PRINT_BUF_SIZE 4096 +static char g_print_buf[PRINT_BUF_SIZE]; + +static int +fake_print(const char *fmt, ...) +{ + va_list ap; + size_t offset = strlen(g_print_buf); + size_t left = PRINT_BUF_SIZE - offset; + + va_start(ap, fmt); + vsnprintf(g_print_buf + offset, left, fmt, ap); + va_end(ap); + + return 0; +} + +static void +fake_print_reset(void) +{ + memset(g_print_buf, 0, sizeof(g_print_buf)); +} + +/* ---------------------------------------------------------------- + * Tests + * ---------------------------------------------------------------- */ + +/** + * ddb_run_open must return -DER_NO_SERVICE when vmd_wa_can_proceed returns + * false (i.e. DDB_CAN_PROCEED macro fires). + */ +static void +open_can_proceed_failure_test(void **state) +{ + struct ddb_ctx ctx = {0}; + struct open_options opt = {0}; + int rc; + + ctx.dc_io_ft.ddb_print_message = fake_print; + ctx.dc_io_ft.ddb_print_error = fake_print; + + opt.path = "/some/path/vos-0"; + + /* Make vmd_wa_can_proceed return false */ + will_return(__wrap_vmd_wa_can_proceed, false); + + rc = ddb_run_open(&ctx, &opt); + assert_int_equal(rc, -DER_NO_SERVICE); +} + +/** + * ddb_run_version must print a version string and return 0. + */ +static void +version_test(void **state) +{ + struct ddb_ctx ctx = {0}; + int rc; + + ctx.dc_io_ft.ddb_print_message = fake_print; + fake_print_reset(); + + rc = ddb_run_version(&ctx); + assert_int_equal(rc, 0); + assert_non_null(strstr(g_print_buf, "ddb version")); +} + +/** + * ddb_run_close must return 0 when no pool is open (handle is invalid). + */ +static void +close_not_open_test(void **state) +{ + struct ddb_ctx ctx = {0}; + int rc; + + ctx.dc_poh = DAOS_HDL_INVAL; + + rc = ddb_run_close(&ctx); + assert_int_equal(rc, 0); +} + +/* ---------------------------------------------------------------- + * Suite registration + * ---------------------------------------------------------------- */ +#define TEST(x) {#x, x##_test, NULL, NULL} + +static const struct CMUnitTest ddb_commands_ut_cases[] = { + TEST(open_can_proceed_failure), + TEST(version), + TEST(close_not_open), +}; + +int +ddb_commands_ut_run(void) +{ + return cmocka_run_group_tests_name("DDB Commands Unit Tests", ddb_commands_ut_cases, NULL, + NULL); +} diff --git a/src/utils/ddb/tests/ddb_ut.c b/src/utils/ddb/tests/ddb_ut.c index 1f20ba46886..420ff139cdb 100644 --- a/src/utils/ddb/tests/ddb_ut.c +++ b/src/utils/ddb/tests/ddb_ut.c @@ -18,6 +18,9 @@ int ddb_vos_ut_run(void); +int +ddb_commands_ut_run(void); + static int ddb_test_driver_arguments_parse(uint32_t argc, char **argv) { @@ -88,6 +91,7 @@ main(int argc, char *argv[]) /* filtering suites and tests */ char test_suites[] = ""; RUN_TEST_SUIT('a', ddb_vos_ut_run); + RUN_TEST_SUIT('b', ddb_commands_ut_run); ddb_fini(); if (rc > 0)