diff --git a/.github/workflows/daos.yml b/.github/workflows/daos.yml new file mode 100644 index 00000000000..35a7f9977ca --- /dev/null +++ b/.github/workflows/daos.yml @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation +# + +name: DAOS + +on: + push: + +permissions: {} + +jobs: + clear_caches: + name: Clear caches + runs-on: ubuntu-latest + strategy: + matrix: + ref: [master, release/2.6] + permissions: + actions: write + steps: + - run: | + curl -L \ + -X DELETE \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/pmem/pmdk/actions/caches?key=opt_daos-${{ matrix.ref }}" + daos_tests: + name: DAOS + needs: clear_caches + strategy: + matrix: + ref: [master, release/2.6] + uses: pmem/pmdk/.github/workflows/daos_tests.yml@DAOS-tests + with: + DAOS_REF: ${{ matrix.ref }} diff --git a/.github/workflows/daos_tests.yml b/.github/workflows/daos_tests.yml new file mode 100644 index 00000000000..7bb0967ba02 --- /dev/null +++ b/.github/workflows/daos_tests.yml @@ -0,0 +1,159 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation +# + +name: DAOS tests + +on: + workflow_call: + inputs: + DAOS_REF: + required: true + type: string + workflow_dispatch: + inputs: + DAOS_REF: + description: DAOS ref + required: true + type: string + +permissions: {} + +env: + DAOS_PATH: /opt/daos + +jobs: + daos_test: + name: DAOS tests + runs-on: ubuntu-latest + steps: + - name: Generate a safe ref + id: safe_ref + run: | + ref=${{ inputs.DAOS_REF }} + safe_ref=${ref//\//_} + echo "value=$safe_ref" >> $GITHUB_OUTPUT + + - name: Clone the DAOS repo + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + repository: daos-stack/daos + ref: ${{ inputs.DAOS_REF }} + path: daos + + - name: Clone the PMDK repo + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + with: + repository: pmem/pmdk + path: pmdk + + - name: Restore ${{ env.DAOS_PATH }} from cache + id: cache + uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + path: ${{ env.DAOS_PATH }} + key: opt_daos-${{ inputs.DAOS_REF }} + fail-on-cache-miss: false + + - name: Apply DAOS patches + if: steps.cache.outputs.cache-hit != 'true' + working-directory: daos + run: git apply ../pmdk/src/test/daos_dtx/*.patch + + # It seems necessary for both building and running. + - name: Install DAOS' dependencies + working-directory: daos + run: | + sudo pip install -r requirements-build.txt + sudo utils/scripts/install-ubuntu.sh + + # https://go.dev/doc/install + - name: Update the golang package + if: steps.cache.outputs.cache-hit != 'true' + env: + GOLANG_VER: go1.23.1 # >= 1.21 because of https://go.dev/doc/toolchain + run: | + sudo apt-get remove golang-go + wget https://go.dev/dl/${{ env.GOLANG_VER }}.linux-amd64.tar.gz + sudo tar -C /usr/local -xzf ${{ env.GOLANG_VER }}.linux-amd64.tar.gz + + - name: Install Valgrind + working-directory: pmdk/utils/docker/images/ + run: sudo ./install-valgrind.sh + + - name: Generate ${{ env.OPTS_FILE }} + if: steps.cache.outputs.cache-hit != 'true' + working-directory: daos + env: + OPTS_FILE: daos.conf + run: | + cat <<-EOF >> ${{ env.OPTS_FILE }} + BUILD_TYPE = 'debug' + TARGET_TYPE = 'debug' + PREFIX = '${{ env.DAOS_PATH }}' + GO_BIN = '/usr/local/go/bin/go' + EOF + cat ${{ env.OPTS_FILE }} + + - name: Build DAOS + if: steps.cache.outputs.cache-hit != 'true' + working-directory: daos + run: | + git submodule init + git submodule update + scons install -j16 --build-deps=yes + + - name: Save ${{ env.DAOS_PATH }} as cache + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + path: ${{ env.DAOS_PATH }} + key: opt_daos-${{ inputs.DAOS_REF }} + + - name: Install PMDK's dependencies + run: sudo apt-get install libndctl-dev libdaxctl-dev pandoc + + - name: Build PMDK + working-directory: pmdk + env: + PMDK_BUILD_DAOS_TESTS: y + DAOS_INSTALL_PATH: ${{ env.DAOS_PATH }} + run: | + export DAOS_SRC_PATH=$(realpath ../daos) + utils/gha-runners/build-pmdk.sh + + - name: Create testconfig files + working-directory: pmdk + env: + PMEM_FS_DIR: /dev/shm + PMEM_FS_DIR_FORCE_PMEM: 1 + run: | + utils/create-testconfig.sh + for testconfig in src/test/testconfig.{sh,py}; do + echo "$testconfig" + cat $testconfig + echo + done + + - name: Run daos_dtx tests (1/2) + working-directory: pmdk/src/test + env: + LD_LIBRARY_PATH: ${{ env.DAOS_PATH }}/prereq/debug/ofi/lib + run: | + export PATH=${{ env.DAOS_PATH }}/bin:$PATH + ./RUNTESTS.py daos_dtx + + - name: Run daos_dtx tests (2/2) + working-directory: pmdk/src/test + env: + PMEMOBJ_CONF: sds.at_create=0 + run: | + export PATH=${{ env.DAOS_PATH }}/bin:$PATH + ./RUNTESTS.sh daos_dtx 2> daos_dtx/err.log + + - name: Upload test results as artifact + if: success() || failure() + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + with: + name: daos_dtx-${{ steps.safe_ref.outputs.value }} + path: pmdk/src/test/daos_dtx diff --git a/src/test/Makefile b/src/test/Makefile index 5d39101d811..8bd876df0be 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -122,6 +122,7 @@ OTHER_TESTS = \ compat_incompat_features\ ctl_prefault\ ctl_cow\ + daos_dtx\ magic\ out_err\ out_err_mt\ diff --git a/src/test/daos_dtx/.gitignore b/src/test/daos_dtx/.gitignore new file mode 100644 index 00000000000..d74b8e3176f --- /dev/null +++ b/src/test/daos_dtx/.gitignore @@ -0,0 +1 @@ +daos_dtx diff --git a/src/test/daos_dtx/00_harmonize_VOS_pool_path.patch b/src/test/daos_dtx/00_harmonize_VOS_pool_path.patch new file mode 100644 index 00000000000..508edc3341a --- /dev/null +++ b/src/test/daos_dtx/00_harmonize_VOS_pool_path.patch @@ -0,0 +1,172 @@ +diff --git a/src/vos/tests/vts_common.c b/src/vos/tests/vts_common.c +index 618f9feddd..7452ba2a34 100644 +--- a/src/vos/tests/vts_common.c ++++ b/src/vos/tests/vts_common.c +@@ -52,11 +52,22 @@ vts_file_exists(const char *filename) + } + + int +-vts_alloc_gen_fname(char **fname) ++vts_alloc_gen_fname(char *po_uuid_str, char **fname) + { + int rc; + +- rc = asprintf(fname, "%s/vpool.%d", vos_path, gc++); ++ assert(*fname == NULL); ++ rc = asprintf(fname, "%s/%s/", vos_path, po_uuid_str); ++ if (rc < 0) { ++ *fname = NULL; ++ print_error("Failed to allocate memory for fname: rc = %d\n", rc); ++ return rc; ++ } ++ rc = mkdir(*fname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); ++ assert(rc == 0 || errno == EEXIST); ++ free(*fname); ++ ++ rc = asprintf(fname, "%s/%s/vpool.%d", vos_path, po_uuid_str, gc++); + if (rc < 0) { + *fname = NULL; + print_error("Failed to allocate memory for fname: rc = %d\n", rc); +@@ -71,9 +82,9 @@ vts_pool_fallocate(char **fname) + { + int ret = 0, fd; + +- ret = vts_alloc_gen_fname(fname); +- if (ret) +- return ret; ++ // ret = vts_alloc_gen_fname(fname); ++ // if (ret) ++ // return ret; + + fd = open(*fname, O_CREAT | O_TRUNC | O_RDWR, 0666); + if (fd < 0) { +@@ -92,10 +103,17 @@ int + vts_ctx_init(struct vos_test_ctx *tcx, size_t psize) + { + int rc; ++ char uuid_str[] = "dd6728be-696a-11ef-a059-a4bf0165c389"; ++ char uuid_str2[] = "591d19e4-69fe-11ef-b13d-a4bf0165c389"; + + memset(tcx, 0, sizeof(*tcx)); ++ ++ uuid_parse(uuid_str, tcx->tc_po_uuid); ++ // uuid_generate_time_safe(tcx->tc_po_uuid); ++ // uuid_unparse(tcx->tc_po_uuid, uuid_str); ++ + oid_cnt = 0; +- rc = vts_alloc_gen_fname(&tcx->tc_po_name); ++ rc = vts_alloc_gen_fname(uuid_str, &tcx->tc_po_name); + assert_int_equal(rc, 0); + + if (vts_file_exists(tcx->tc_po_name)) { +@@ -103,8 +121,8 @@ vts_ctx_init(struct vos_test_ctx *tcx, size_t psize) + assert_int_equal(rc, 0); + } + +- uuid_generate_time_safe(tcx->tc_po_uuid); +- uuid_generate_time_safe(tcx->tc_co_uuid); ++ // uuid_generate_time_safe(tcx->tc_co_uuid); ++ uuid_parse(uuid_str2, tcx->tc_co_uuid); + + /* specify @psize as both NVMe size and SCM size */ + rc = vos_pool_create(tcx->tc_po_name, tcx->tc_po_uuid, psize, psize, 0, 0 /* version */, +@@ -155,14 +173,14 @@ vts_ctx_fini(struct vos_test_ctx *tcx) + assert_rc_equal(rc, 0); + /* fallthrough */ + case TCX_CO_CREATE: +- rc = vos_cont_destroy(tcx->tc_po_hdl, tcx->tc_co_uuid); +- assert_rc_equal(rc, 0); ++ // rc = vos_cont_destroy(tcx->tc_po_hdl, tcx->tc_co_uuid); ++ // assert_rc_equal(rc, 0); + /* fallthrough */ + case TCX_PO_CREATE_OPEN: + rc = vos_pool_close(tcx->tc_po_hdl); + assert_rc_equal(rc, 0); +- rc = vos_pool_destroy(tcx->tc_po_name, tcx->tc_po_uuid); +- assert_rc_equal(rc, 0); ++ // rc = vos_pool_destroy(tcx->tc_po_name, tcx->tc_po_uuid); ++ // assert_rc_equal(rc, 0); + free(tcx->tc_po_name); + /* fallthrough */ + } +diff --git a/src/vos/tests/vts_common.h b/src/vos/tests/vts_common.h +index 2a08cbd8ff..b7dc09dcfe 100644 +--- a/src/vos/tests/vts_common.h ++++ b/src/vos/tests/vts_common.h +@@ -83,7 +83,7 @@ bool + vts_file_exists(const char *filename); + + int +-vts_alloc_gen_fname(char **fname); ++vts_alloc_gen_fname(char *po_uuid, char **fname); + + int + vts_pool_fallocate(char **fname); +diff --git a/src/vos/tests/vts_io.c b/src/vos/tests/vts_io.c +index 5ec1bb08f7..abc269b1f6 100644 +--- a/src/vos/tests/vts_io.c ++++ b/src/vos/tests/vts_io.c +@@ -956,7 +956,7 @@ io_obj_cache_test(void **state) + struct vos_object *obj1, *obj2; + daos_epoch_range_t epr = {0, 1}; + daos_unit_oid_t oids[2]; +- char *po_name; ++ char *po_name = ""; + uuid_t pool_uuid; + daos_handle_t l_poh, l_coh; + struct daos_lru_cache *old_cache; +@@ -970,8 +970,8 @@ io_obj_cache_test(void **state) + old_cache = tls->vtl_ocache; + tls->vtl_ocache = occ; + +- rc = vts_alloc_gen_fname(&po_name); +- assert_int_equal(rc, 0); ++ // rc = vts_alloc_gen_fname(&po_name); ++ // assert_int_equal(rc, 0); + + uuid_generate_time_safe(pool_uuid); + rc = vos_pool_create(po_name, pool_uuid, VPOOL_256M, 0, 0, 0 /* version */, &l_poh); +@@ -1105,7 +1105,7 @@ io_obj_cache_test(void **state) + assert_rc_equal(rc, 0); + vos_obj_cache_destroy(occ); + tls->vtl_ocache = old_cache; +- free(po_name); ++ // free(po_name); + } + + static void +diff --git a/src/vos/tests/vts_pool.c b/src/vos/tests/vts_pool.c +index acfd4e46a8..8e2fe3742c 100644 +--- a/src/vos/tests/vts_pool.c ++++ b/src/vos/tests/vts_pool.c +@@ -49,7 +49,7 @@ static int + pool_file_setup(void **state) + { + struct vp_test_args *arg = *state; +- int ret = 0; ++ // int ret = 0; + + D_ALLOC(arg->fname, sizeof(char *)); + assert_ptr_not_equal(arg->fname, NULL); +@@ -57,8 +57,8 @@ pool_file_setup(void **state) + D_ALLOC_ARRAY(arg->poh, 10); + assert_ptr_not_equal(arg->poh, NULL); + +- ret = vts_alloc_gen_fname(&arg->fname[0]); +- assert_int_equal(ret, 0); ++ // ret = vts_alloc_gen_fname(&arg->fname[0]); ++ // assert_int_equal(ret, 0); + return 0; + } + +@@ -153,8 +153,8 @@ pool_ops_run(void **state) + VPOOL_TEST_WAL_SZ, 0, + 0 /* version */, poh); + } else { +- ret = vts_alloc_gen_fname(&arg->fname[j]); +- assert_int_equal(ret, 0); ++ // ret = vts_alloc_gen_fname(&arg->fname[j]); ++ // assert_int_equal(ret, 0); + ret = vos_pool_create_ex(arg->fname[j], arg->uuid[j], + VPOOL_256M, 0, VPOOL_TEST_WAL_SZ, + 0, 0 /* version */, poh); diff --git a/src/test/daos_dtx/01_stop_using_test_args_reset.patch b/src/test/daos_dtx/01_stop_using_test_args_reset.patch new file mode 100644 index 00000000000..be3a02bd50d --- /dev/null +++ b/src/test/daos_dtx/01_stop_using_test_args_reset.patch @@ -0,0 +1,127 @@ +diff --git a/src/dtx/tests/dts_local.c b/src/dtx/tests/dts_local.c +index deecc597f2..3463d661e7 100644 +--- a/src/dtx/tests/dts_local.c ++++ b/src/dtx/tests/dts_local.c +@@ -264,5 +264,5 @@ run_local_tests(const char *cfg) + + dts_global_init(); + +- return cmocka_run_group_tests_name(test_name, local_tests_all, setup_io, teardown_io); ++ return cmocka_run_group_tests_name(test_name, local_tests_all, NULL, NULL); + } +diff --git a/src/dtx/tests/dts_local_rdb.c b/src/dtx/tests/dts_local_rdb.c +index eeff78553d..212113c07e 100644 +--- a/src/dtx/tests/dts_local_rdb.c ++++ b/src/dtx/tests/dts_local_rdb.c +@@ -114,5 +114,5 @@ run_local_rdb_tests(const char *cfg) + + dts_global_init(); + +- return cmocka_run_group_tests_name(test_name, tests_all, setup_io, teardown_io); ++ return cmocka_run_group_tests_name(test_name, tests_all, NULL, NULL); + } +diff --git a/src/dtx/tests/dts_utils.c b/src/dtx/tests/dts_utils.c +index 8a819e325a..c884872143 100644 +--- a/src/dtx/tests/dts_utils.c ++++ b/src/dtx/tests/dts_utils.c +@@ -136,20 +136,22 @@ _dts_fetch_and_validate(daos_handle_t coh, struct dts_local_args *la, unsigned d + + /** Setup and teardown functions */ + ++static struct io_test_args test_args; + static struct dts_local_args local_args; + + int + setup_local_args(void **state) + { +- struct io_test_args *arg = *state; ++ struct io_test_args *arg = &test_args; + struct dts_local_args *la = &local_args; +- int int_flag = is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64); ++ int int_flag; + int rc; + +- memset(&local_args, 0, sizeof(local_args)); ++ test_args_init(&test_args, VPOOL_SIZE); ++ ++ int_flag = is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64); + +- /** i.a. recreates the container */ +- test_args_reset(arg, VPOOL_SIZE); ++ memset(&local_args, 0, sizeof(local_args)); + + /** prepare OID */ + la->oid = gen_oid(arg->otype); +@@ -181,6 +183,8 @@ setup_local_args(void **state) + /** attach local arguments */ + arg->custom = la; + ++ *state = arg; ++ + return 0; + } + +@@ -197,5 +201,7 @@ teardown_local_args(void **state) + /** detach local arguments */ + arg->custom = NULL; + ++ test_args_fini(arg); ++ + return 0; + } +diff --git a/src/vos/tests/vts_io.c b/src/vos/tests/vts_io.c +index abc269b1f6..e59defec2a 100644 +--- a/src/vos/tests/vts_io.c ++++ b/src/vos/tests/vts_io.c +@@ -201,14 +201,18 @@ test_args_init(struct io_test_args *args, + } + snprintf(args->fname, VTS_BUF_SIZE, "%s/vpool.test_%x", + vos_path, init_type); ++} + +- ++void ++test_args_fini(struct io_test_args *args) ++{ ++ vts_ctx_fini(&args->ctx); + } + + void + test_args_reset(struct io_test_args *args, uint64_t pool_size) + { +- vts_ctx_fini(&args->ctx); ++ test_args_fini(args); + test_args_init(args, pool_size); + } + +@@ -256,7 +260,7 @@ teardown_io(void **state) + } + + assert_ptr_equal(arg, &test_args); +- vts_ctx_fini(&arg->ctx); ++ test_args_fini(arg); + return 0; + } + +diff --git a/src/vos/tests/vts_io.h b/src/vos/tests/vts_io.h +index fe67d0dc7b..a8858d6384 100644 +--- a/src/vos/tests/vts_io.h ++++ b/src/vos/tests/vts_io.h +@@ -1,5 +1,5 @@ + /** +- * (C) Copyright 2016-2022 Intel Corporation. ++ * (C) Copyright 2016-2024 Intel Corporation. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ +@@ -99,6 +99,10 @@ daos_unit_oid_t gen_oid(enum daos_otype_t type); + void reset_oid_stable(uint32_t seed); + daos_unit_oid_t gen_oid_stable(enum daos_otype_t type); + void inc_cntr(unsigned long op_flags); ++void ++test_args_init(struct io_test_args *args, uint64_t pool_size); ++void ++ test_args_fini(struct io_test_args *args); + void test_args_reset(struct io_test_args *args, + uint64_t pool_size); + int io_test_obj_update(struct io_test_args *arg, diff --git a/src/test/daos_dtx/02_reduce_memory_requirements.patch b/src/test/daos_dtx/02_reduce_memory_requirements.patch new file mode 100644 index 00000000000..8d94baf790b --- /dev/null +++ b/src/test/daos_dtx/02_reduce_memory_requirements.patch @@ -0,0 +1,32 @@ +diff --git a/src/dtx/tests/dts_utils.c b/src/dtx/tests/dts_utils.c +index c884872143..607b20d732 100644 +--- a/src/dtx/tests/dts_utils.c ++++ b/src/dtx/tests/dts_utils.c +@@ -147,7 +147,7 @@ setup_local_args(void **state) + int int_flag; + int rc; + +- test_args_init(&test_args, VPOOL_SIZE); ++ test_args_init(&test_args, VPOOL_64M); + + int_flag = is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64); + +diff --git a/src/vos/tests/vts_common.h b/src/vos/tests/vts_common.h +index b7dc09dcfe..0e3c7fa3a9 100644 +--- a/src/vos/tests/vts_common.h ++++ b/src/vos/tests/vts_common.h +@@ -1,5 +1,5 @@ + /** +- * (C) Copyright 2016-2023 Intel Corporation. ++ * (C) Copyright 2016-2024 Intel Corporation. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ +@@ -35,6 +35,7 @@ + } while (0) + #endif /* FAULT_INJECTION */ + ++#define VPOOL_64M (64ULL << 20) + #define VPOOL_256M (256ULL << 20) + #define VPOOL_1G (1ULL << 30) + #define VPOOL_2G (2ULL << 30) diff --git a/src/test/daos_dtx/03_CMOCKA_FILTER_SUPPORTED.patch b/src/test/daos_dtx/03_CMOCKA_FILTER_SUPPORTED.patch new file mode 100644 index 00000000000..dacd9b23cd7 --- /dev/null +++ b/src/test/daos_dtx/03_CMOCKA_FILTER_SUPPORTED.patch @@ -0,0 +1,13 @@ +diff --git a/site_scons/site_tools/compiler_setup.py b/site_scons/site_tools/compiler_setup.py +index 9f25ccace7..a149b2ceb8 100644 +--- a/site_scons/site_tools/compiler_setup.py ++++ b/site_scons/site_tools/compiler_setup.py +@@ -73,7 +73,7 @@ def _base_setup(env): + env.AppendUnique(CPPDEFINES={'FAULT_INJECTION': '1'}) + env.AppendUnique(CPPDEFINES={'BUILD_PIPELINE': '1'}) + +- env.AppendUnique(CPPDEFINES={'CMOCKA_FILTER_SUPPORTED': '0'}) ++ env.AppendUnique(CPPDEFINES={'CMOCKA_FILTER_SUPPORTED': '1'}) + + env.AppendUnique(CPPDEFINES='_GNU_SOURCE') + diff --git a/src/test/daos_dtx/04_force_use_sys_db.patch b/src/test/daos_dtx/04_force_use_sys_db.patch new file mode 100644 index 00000000000..0024a4d7fee --- /dev/null +++ b/src/test/daos_dtx/04_force_use_sys_db.patch @@ -0,0 +1,19 @@ +diff --git a/src/vos/vos_common.c b/src/vos/vos_common.c +index 0e274437a3..a5fce7d36a 100644 +--- a/src/vos/vos_common.c ++++ b/src/vos/vos_common.c +@@ -1028,10 +1028,10 @@ vos_self_init_ext(const char *db_path, bool use_sys_db, int tgt_id, bool nvme_in + if (rc) + goto failed; + +- if (use_sys_db) +- rc = vos_db_init(db_path); +- else +- rc = vos_db_init_ex(db_path, "self_db", true, true); ++ // if (use_sys_db) ++ rc = vos_db_init(db_path); ++ // else ++ // rc = vos_db_init_ex(db_path, "self_db", true, true); + if (rc) + goto failed; + diff --git a/src/test/daos_dtx/05_dts_basic_create_open_close.patch b/src/test/daos_dtx/05_dts_basic_create_open_close.patch new file mode 100644 index 00000000000..406c05f29ef --- /dev/null +++ b/src/test/daos_dtx/05_dts_basic_create_open_close.patch @@ -0,0 +1,278 @@ +diff --git a/src/dtx/tests/dts_utils.c b/src/dtx/tests/dts_utils.c +index 607b20d732..8b63d77509 100644 +--- a/src/dtx/tests/dts_utils.c ++++ b/src/dtx/tests/dts_utils.c +@@ -136,22 +136,13 @@ _dts_fetch_and_validate(daos_handle_t coh, struct dts_local_args *la, unsigned d + + /** Setup and teardown functions */ + +-static struct io_test_args test_args; +-static struct dts_local_args local_args; +- +-int +-setup_local_args(void **state) ++static void ++local_args_init(struct io_test_args *arg, struct dts_local_args *la) + { +- struct io_test_args *arg = &test_args; +- struct dts_local_args *la = &local_args; +- int int_flag; +- int rc; +- +- test_args_init(&test_args, VPOOL_64M); +- +- int_flag = is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64); ++ int int_flag = is_daos_obj_type_set(arg->otype, DAOS_OT_DKEY_UINT64); ++ int rc; + +- memset(&local_args, 0, sizeof(local_args)); ++ memset(la, 0, sizeof(*la)); + + /** prepare OID */ + la->oid = gen_oid(arg->otype); +@@ -179,6 +170,28 @@ setup_local_args(void **state) + assert_rc_equal(rc, 0); + + la->epoch = START_EPOCH; ++} ++ ++static void ++local_args_fini(struct dts_local_args *la) ++{ ++ /** finalize scatter-gather lists */ ++ d_sgl_fini(&la->sgl, false); ++ d_sgl_fini(&la->fetch_sgl, false); ++} ++ ++static struct io_test_args test_args; ++static struct dts_local_args local_args; ++ ++int ++setup_local_args(void **state) ++{ ++ struct io_test_args *arg = &test_args; ++ struct dts_local_args *la = &local_args; ++ ++ test_args_init(&test_args, VPOOL_64M, true /* create */); ++ ++ local_args_init(arg, la); + + /** attach local arguments */ + arg->custom = la; +@@ -194,9 +207,7 @@ teardown_local_args(void **state) + struct io_test_args *arg = *state; + struct dts_local_args *la = arg->custom; + +- /** finalize scatter-gather lists */ +- d_sgl_fini(&la->sgl, false); +- d_sgl_fini(&la->fetch_sgl, false); ++ local_args_fini(la); + + /** detach local arguments */ + arg->custom = NULL; +@@ -205,3 +216,37 @@ teardown_local_args(void **state) + + return 0; + } ++ ++int ++dts_basic_create(void **state) ++{ ++ struct io_test_args *arg = &test_args; ++ ++ test_args_init(&test_args, VPOOL_64M, true /* create */); ++ ++ *state = arg; ++ ++ return 0; ++} ++ ++int ++dts_basic_close(void **state) ++{ ++ struct io_test_args *arg = *state; ++ ++ test_args_fini(arg); ++ ++ return 0; ++} ++ ++int ++dts_basic_open(void **state) ++{ ++ struct io_test_args *arg = &test_args; ++ ++ test_args_init(&test_args, VPOOL_64M, false /* open */); ++ ++ *state = arg; ++ ++ return 0; ++} +diff --git a/src/dtx/tests/dts_utils.h b/src/dtx/tests/dts_utils.h +index 3f42a9c58d..2943906775 100644 +--- a/src/dtx/tests/dts_utils.h ++++ b/src/dtx/tests/dts_utils.h +@@ -112,6 +112,15 @@ setup_local_args(void **state); + int + teardown_local_args(void **state); + ++int ++dts_basic_create(void **state); ++ ++int ++dts_basic_close(void **state); ++ ++int ++dts_basic_open(void **state); ++ + #define BASIC_UT(NO, NAME, FUNC) \ + { \ + "DTX" #NO ": " NAME, FUNC, setup_local_args, teardown_local_args \ +diff --git a/src/vos/tests/vts_common.c b/src/vos/tests/vts_common.c +index d3d886e9a1..a2fc94b353 100644 +--- a/src/vos/tests/vts_common.c ++++ b/src/vos/tests/vts_common.c +@@ -1,5 +1,5 @@ + /** +- * (C) Copyright 2016-2022 Intel Corporation. ++ * (C) Copyright 2016-2024 Intel Corporation. + * + * SPDX-License-Identifier: BSD-2-Clause-Patent + */ +@@ -95,7 +95,7 @@ exit: + } + + int +-vts_ctx_init(struct vos_test_ctx *tcx, size_t psize) ++vts_ctx_init(struct vos_test_ctx *tcx, size_t psize, bool create) + { + int rc; + char uuid_str[] = "dd6728be-696a-11ef-a059-a4bf0165c389"; +@@ -111,31 +111,41 @@ vts_ctx_init(struct vos_test_ctx *tcx, size_t psize) + rc = vts_alloc_gen_fname(uuid_str, &tcx->tc_po_name); + assert_int_equal(rc, 0); + +- if (vts_file_exists(tcx->tc_po_name)) { +- rc = remove(tcx->tc_po_name); +- assert_int_equal(rc, 0); ++ if (create) { ++ if (vts_file_exists(tcx->tc_po_name)) { ++ rc = remove(tcx->tc_po_name); ++ assert_int_equal(rc, 0); ++ } ++ } else { ++ assert_true(vts_file_exists(tcx->tc_po_name)); + } + + // uuid_generate_time_safe(tcx->tc_co_uuid); + uuid_parse(uuid_str2, tcx->tc_co_uuid); + +- /* specify @psize as both NVMe size and SCM size */ +- rc = vos_pool_create(tcx->tc_po_name, tcx->tc_po_uuid, psize, psize, 0, 0 /* version */, +- &tcx->tc_po_hdl); +- if (rc) { +- print_error("vpool create %s failed with error : %d\n", +- tcx->tc_po_name, rc); +- goto failed; +- } +- tcx->tc_step = TCX_PO_CREATE_OPEN; ++ if (create) { ++ /* specify @psize as both NVMe size and SCM size */ ++ rc = vos_pool_create(tcx->tc_po_name, tcx->tc_po_uuid, psize, psize, 0, ++ 0 /* version */, &tcx->tc_po_hdl); ++ if (rc) { ++ print_error("vpool create %s failed with error : %d\n", tcx->tc_po_name, ++ rc); ++ goto failed; ++ } ++ tcx->tc_step = TCX_PO_CREATE_OPEN; + +- rc = vos_cont_create(tcx->tc_po_hdl, tcx->tc_co_uuid); +- if (rc) { +- print_error("vos container creation error: "DF_RC"\n", +- DP_RC(rc)); +- goto failed; ++ rc = vos_cont_create(tcx->tc_po_hdl, tcx->tc_co_uuid); ++ if (rc) { ++ print_error("vos container creation error: " DF_RC "\n", DP_RC(rc)); ++ goto failed; ++ } ++ tcx->tc_step = TCX_CO_CREATE; ++ } else { ++ rc = vos_pool_open(tcx->tc_po_name, tcx->tc_po_uuid, 0, &tcx->tc_po_hdl); ++ assert_int_equal(rc, 0); ++ /* the container should already exists */ ++ tcx->tc_step = TCX_CO_CREATE; + } +- tcx->tc_step = TCX_CO_CREATE; + + rc = vos_cont_open(tcx->tc_po_hdl, tcx->tc_co_uuid, + &tcx->tc_co_hdl); +diff --git a/src/vos/tests/vts_common.h b/src/vos/tests/vts_common.h +index 0e3c7fa3a9..aa4b8bc504 100644 +--- a/src/vos/tests/vts_common.h ++++ b/src/vos/tests/vts_common.h +@@ -94,8 +94,7 @@ vts_pool_fallocate(char **fname); + * test context for I/O tests + */ + int +-vts_ctx_init(struct vos_test_ctx *tcx, +- size_t pool_size); ++vts_ctx_init(struct vos_test_ctx *tcx, size_t pool_size, bool create); + + void + vts_ctx_fini(struct vos_test_ctx *tcx); +diff --git a/src/vos/tests/vts_io.c b/src/vos/tests/vts_io.c +index e59defec2a..94ea64fe99 100644 +--- a/src/vos/tests/vts_io.c ++++ b/src/vos/tests/vts_io.c +@@ -167,8 +167,7 @@ static enum daos_otype_t init_type; + static int init_num_keys; + + void +-test_args_init(struct io_test_args *args, +- uint64_t pool_size) ++test_args_init(struct io_test_args *args, uint64_t pool_size, bool create) + { + int rc; + +@@ -177,7 +176,7 @@ test_args_init(struct io_test_args *args, + + vts_epoch_gen = 1; + +- rc = vts_ctx_init(&args->ctx, pool_size); ++ rc = vts_ctx_init(&args->ctx, pool_size, create); + if (rc != 0) + print_error("rc = "DF_RC"\n", DP_RC(rc)); + assert_rc_equal(rc, 0); +@@ -213,7 +212,7 @@ void + test_args_reset(struct io_test_args *args, uint64_t pool_size) + { + test_args_fini(args); +- test_args_init(args, pool_size); ++ test_args_init(args, pool_size, true /* create */); + } + + static struct io_test_args test_args; +@@ -226,7 +225,7 @@ setup_io(void **state) + struct vos_ts_table *table; + + srand(time(NULL)); +- test_args_init(&test_args, VPOOL_SIZE); ++ test_args_init(&test_args, VPOOL_SIZE, true /* create */); + + table = vos_ts_table_get(true); + if (table == NULL) +diff --git a/src/vos/tests/vts_io.h b/src/vos/tests/vts_io.h +index a8858d6384..aa3c4cc54d 100644 +--- a/src/vos/tests/vts_io.h ++++ b/src/vos/tests/vts_io.h +@@ -100,7 +100,7 @@ void reset_oid_stable(uint32_t seed); + daos_unit_oid_t gen_oid_stable(enum daos_otype_t type); + void inc_cntr(unsigned long op_flags); + void +-test_args_init(struct io_test_args *args, uint64_t pool_size); ++test_args_init(struct io_test_args *args, uint64_t pool_size, bool create); + void + test_args_fini(struct io_test_args *args); + void test_args_reset(struct io_test_args *args, diff --git a/src/test/daos_dtx/06_basic_dtx_ut.patch b/src/test/daos_dtx/06_basic_dtx_ut.patch new file mode 100644 index 00000000000..6e8270c7c81 --- /dev/null +++ b/src/test/daos_dtx/06_basic_dtx_ut.patch @@ -0,0 +1,226 @@ +diff --git a/src/dtx/tests/SConscript b/src/dtx/tests/SConscript +index 160bff9113..95cf6fd4ac 100644 +--- a/src/dtx/tests/SConscript ++++ b/src/dtx/tests/SConscript +@@ -19,7 +19,7 @@ def scons(): + + test_src = ['dtx_tests.c', 'sched_mock.c', 'ult_mock.c', 'srv_mock.c', 'pl_map_mock.c', + '../../common/tls.c', 'dts_utils.c', 'dts_local.c', 'dts_local_rdb.c', +- 'dts_structs.c', vts_objs] ++ 'dts_structs.c', 'dts_xxx.c', vts_objs] + dtx_tests = tenv.d_program('dtx_tests', test_src, LIBS=libraries) + + tenv.Install('$PREFIX/bin/', [dtx_tests]) +diff --git a/src/dtx/tests/dts_xxx.c b/src/dtx/tests/dts_xxx.c +new file mode 100644 +index 0000000000..e9eaa799e5 +--- /dev/null ++++ b/src/dtx/tests/dts_xxx.c +@@ -0,0 +1,186 @@ ++/** ++ * (C) Copyright 2024 Intel Corporation. ++ * ++ * SPDX-License-Identifier: BSD-2-Clause-Patent ++ */ ++/** ++ * XXX ++ */ ++#define D_LOGFAC DD_FAC(tests) ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "valgrind/pmemcheck.h" ++ ++#include "vts_io.h" ++#include "dts_utils.h" ++ ++/* Please see dtx_is_valid_handle() for details. */ ++#define MINIMAL_VALID_HLC 1 ++#define MINIMAL_VALID_DTX_ID {.dti_uuid = {0}, .dti_hlc = MINIMAL_VALID_HLC } ++ ++/* Please see dtx_epoch_chosen() for details. */ ++#define MINIMAL_CHOSEN_DTX_EPOCH { 1 } ++ ++#define DTX_NUM 2 /* arbitrarily chosen */ ++ ++/* ++ * Each next DTX has one more record starting from one record for the first DTX. ++ * So overall number of requiered SVT records is an arithmetic series: ++ * S = (a1 + an) * n / 2 ++ */ ++#define SVT_REC_NUM ((1 + DTX_NUM) * DTX_NUM / 2) ++ ++#ifndef VALGRIND_PMC_EMIT_LOG ++#define VALGRIND_PMC_EMIT_LOG(_) /* NOP */ ++#endif /* VG_PMEMCHECK_ENABLED */ ++ ++static void ++heap_warmup(struct umem_instance *umm) ++{ ++ int rc; ++ ++ rc = umem_tx_begin(umm, NULL); ++ assert_rc_equal(rc, 0); ++ for (int i = 0; i < 512; ++i) { ++ (void)umem_alloc(umm, sizeof(struct vos_irec_df)); ++ } ++ rc = umem_tx_abort(umm, DER_SUCCESS); ++ assert_rc_equal(rc, -DER_CANCELED); ++} ++ ++static void ++svt_records_alloc(struct umem_instance *umm, umem_off_t svt_records[]) ++{ ++ umem_off_t rec; ++ struct vos_irec_df *svt; ++ int rc; ++ ++ rc = umem_tx_begin(umm, NULL); ++ assert_rc_equal(rc, 0); ++ for (int i = 0; i < SVT_REC_NUM; ++i) { ++ rec = umem_zalloc(umm, sizeof(struct vos_irec_df)); ++ svt = umem_off2ptr(umm, umem_off2offset(rec)); ++ svt->ir_dtx = DTX_LID_RESERVED + 1; /* arbitrarily picked */ ++ svt_records[i] = rec; ++ } ++ rc = umem_tx_end(umm, DER_SUCCESS); ++ assert_rc_equal(rc, 0); ++} ++ ++static void ++xxx_a(void **state) ++{ ++ struct io_test_args *arg = *state; ++ struct vos_container *vc = vos_hdl2cont(arg->ctx.tc_co_hdl); ++ struct umem_instance *umm = vos_pool2umm(vc->vc_pool); ++ ++ /* prepare SVT records */ ++ vc = vos_hdl2cont(arg->ctx.tc_co_hdl); ++ umm = vos_pool2umm(vc->vc_pool); ++ ++ heap_warmup(umm); ++} ++ ++static void ++xxx_b(void **state) ++{ ++ struct io_test_args *arg = *state; ++ struct dtx_id dti = MINIMAL_VALID_DTX_ID; ++ struct dtx_epoch epoch = MINIMAL_CHOSEN_DTX_EPOCH; ++ uint16_t sub_modification_cnt = 1; ++ uint32_t pm_ver = 0; ++ daos_unit_oid_t *leader_oid = &arg->oid; ++ struct dtx_id *dti_cos = NULL; ++ int dti_cos_cnt = 0; ++ uint32_t flags = 0; ++ struct dtx_memberships *mbs = NULL; ++ struct dtx_handle *dth = NULL; ++ struct ds_cont_child *cont = NULL; ++ struct vos_container *vc = vos_hdl2cont(arg->ctx.tc_co_hdl); ++ struct umem_instance *umm = vos_pool2umm(vc->vc_pool); ++ uint32_t tx_id; ++ umem_off_t svt_records[SVT_REC_NUM] = {UMOFF_NULL}; ++ struct vos_irec_df *svt; ++ int rc; ++ ++ heap_warmup(umm); ++ ++ VALGRIND_PMC_EMIT_LOG("PMREORDER_DTX_BASIC.BEGIN"); ++ ++ /* prepare SVT records */ ++ svt_records_alloc(umm, svt_records); ++ ++ for (int i = 0, r = 0; i < DTX_NUM; ++i, ++dti.dti_hlc, ++epoch.oe_value) { ++ /* begin a DTX transaction */ ++ rc = dtx_begin(arg->ctx.tc_co_hdl, &dti, &epoch, ++ sub_modification_cnt, pm_ver, leader_oid, dti_cos, ++ dti_cos_cnt, flags, mbs, &dth); ++ assert_rc_equal(rc, 0); ++ /* begin the associated VOS transaction */ ++ rc = vos_tx_begin(dth, umm, false); ++ assert_rc_equal(rc, 0); ++ /* begin the first sub-modification */ ++ rc = dtx_sub_init(dth, leader_oid, 0); ++ assert_rc_equal(rc, 0); ++ /* register a few records */ ++ for (int j = 0; j <= i; ++j, ++r) { ++ rc = vos_dtx_register_record(umm, svt_records[r], DTX_RT_SVT, &tx_id); ++ assert_rc_equal(rc, 0); ++ } ++ /* end both VOS and DTX transactions */ ++ rc = vos_tx_end(vc, dth, NULL, NULL, false, NULL, DER_SUCCESS); ++ assert_rc_equal(rc, 0); ++ rc = dtx_end(dth, cont, DER_SUCCESS); ++ assert_rc_equal(rc, 0); ++ } ++ ++ /* commit every other DTX transaction */ ++ struct dtx_id dtis[DTX_NUM / 2] = {0}; ++ for (int i = 0; i < DTX_NUM / 2; ++i) { ++ dtis[i].dti_hlc = MINIMAL_VALID_HLC + i * 2; ++ } ++ /* this API call returns the number of committed transactions */ ++ rc = vos_dtx_commit(arg->ctx.tc_co_hdl, dtis, DTX_NUM / 2, NULL); ++ assert_rc_equal(rc, DTX_NUM / 2); ++ ++ /* abort every other DTX transaction */ ++ for (int i = 0; i < DTX_NUM / 2; ++i) { ++ dti.dti_hlc = MINIMAL_VALID_HLC + i * 2 + 1; ++ rc = vos_dtx_abort(arg->ctx.tc_co_hdl, &dti, DAOS_EPOCH_MAX); ++ assert_rc_equal(rc, 0); ++ } ++ ++ VALGRIND_PMC_EMIT_LOG("PMREORDER_DTX_BASIC.END"); ++ ++ /* assert respective records were either committed or aborted */ ++ for (int i = 0, r = 0; i < DTX_NUM; ++i) { ++ for (int j = 0; j <= i; ++j, ++r) { ++ svt = umem_off2ptr(umm, umem_off2offset(svt_records[r])); ++ if (i % 2 == 0) { ++ assert_rc_equal(svt->ir_dtx, DTX_LID_COMMITTED); ++ } else { ++ assert_rc_equal(svt->ir_dtx, DTX_LID_ABORTED); ++ } ++ } ++ } ++} ++ ++static const struct CMUnitTest xxx_tests_all[] = { ++ {"DTX400.a: xxx", xxx_a, dts_basic_create, dts_basic_close}, ++ {"DTX400.b: xxx", xxx_b, dts_basic_open, dts_basic_close}, ++}; ++ ++int ++run_xxx_tests(const char *cfg) ++{ ++ const char *test_name = "DTX xxx"; ++ ++ dts_global_init(); ++ ++ return cmocka_run_group_tests_name(test_name, xxx_tests_all, NULL, NULL); ++} +diff --git a/src/dtx/tests/dtx_tests.c b/src/dtx/tests/dtx_tests.c +index 6197e3680b..b06a2f4ea8 100644 +--- a/src/dtx/tests/dtx_tests.c ++++ b/src/dtx/tests/dtx_tests.c +@@ -25,6 +25,8 @@ int + run_local_rdb_tests(const char *cfg); + int + run_structs_tests(const char *cfg); ++int ++run_xxx_tests(const char *cfg); + + static void + print_usage() +@@ -50,6 +52,7 @@ run_all_tests(int keys) + failed += run_local_tests(cfg_desc_io); + failed += run_local_rdb_tests(cfg_desc_io); + failed += run_structs_tests(cfg_desc_io); ++ failed += run_xxx_tests(cfg_desc_io); + + return failed; + } diff --git a/src/test/daos_dtx/07_disable_ABT.patch b/src/test/daos_dtx/07_disable_ABT.patch new file mode 100644 index 00000000000..1199c1807bf --- /dev/null +++ b/src/test/daos_dtx/07_disable_ABT.patch @@ -0,0 +1,34 @@ +diff --git a/src/vos/vos_common.c b/src/vos/vos_common.c +index 93bf1757f1..b01947e98a 100644 +--- a/src/vos/vos_common.c ++++ b/src/vos/vos_common.c +@@ -969,7 +969,7 @@ vos_self_fini_locked(void) + vos_self_nvme_fini(); + + vos_standalone_tls_fini(); +- ABT_finalize(); ++ // ABT_finalize(); + } + + void +@@ -1005,16 +1005,16 @@ vos_self_init_ext(const char *db_path, bool use_sys_db, int tgt_id, bool nvme_in + goto out; + } + +- rc = ABT_init(0, NULL); +- if (rc != 0) +- goto out; ++ // rc = ABT_init(0, NULL); ++ // if (rc != 0) ++ // goto out; + + vos_start_epoch = 0; + + #if VOS_STANDALONE + rc = vos_standalone_tls_init(DAOS_TGT_TAG); + if (rc) { +- ABT_finalize(); ++ // ABT_finalize(); + goto out; + } + #endif diff --git a/src/test/daos_dtx/08_cmocka_filter_fix.patch b/src/test/daos_dtx/08_cmocka_filter_fix.patch new file mode 100644 index 00000000000..c1f511dcdbb --- /dev/null +++ b/src/test/daos_dtx/08_cmocka_filter_fix.patch @@ -0,0 +1,21 @@ +diff --git a/src/dtx/tests/dtx_tests.c b/src/dtx/tests/dtx_tests.c +index b06a2f4ea8..7236a2bda0 100644 +--- a/src/dtx/tests/dtx_tests.c ++++ b/src/dtx/tests/dtx_tests.c +@@ -61,6 +61,7 @@ int + main(int argc, char **argv) + { + int rc = 0; ++ char filter[1024]; + int nr_failed = 0; + int opt = 0; + int index = 0; +@@ -107,8 +108,6 @@ main(int argc, char **argv) + #if CMOCKA_FILTER_SUPPORTED == 1 /** requires cmocka 1.1.5 */ + { + /** Add wildcards for easier filtering */ +- char filter[sizeof(optarg) + 2]; +- + sprintf(filter, "*%s*", optarg); + cmocka_set_test_filter(filter); + printf("Test filter: %s\n", filter); diff --git a/src/test/daos_dtx/09_fix_size_t_from_int.patch b/src/test/daos_dtx/09_fix_size_t_from_int.patch new file mode 100644 index 00000000000..dcc2403f6f7 --- /dev/null +++ b/src/test/daos_dtx/09_fix_size_t_from_int.patch @@ -0,0 +1,13 @@ +diff --git a/src/include/daos_types.h b/src/include/daos_types.h +index 6db21423ce..0b2d16834b 100644 +--- a/src/include/daos_types.h ++++ b/src/include/daos_types.h +@@ -240,7 +240,7 @@ static inline bool + daos_is_valid_uuid_string(const char *uuid) + { + const char *p; +- int len = DAOS_UUID_STR_SIZE - 1; /* Not include the terminated '\0' */ ++ size_t len = DAOS_UUID_STR_SIZE - 1; /* Not include the terminated '\0' */ + int i; + + if (strnlen(uuid, len) != len) diff --git a/src/test/daos_dtx/Makefile b/src/test/daos_dtx/Makefile new file mode 100644 index 00000000000..ba826503b08 --- /dev/null +++ b/src/test/daos_dtx/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +# +# src/test/daos_dtx/Makefile -- build a daos_dtx validation executable +# +PMDK_BUILD_DAOS_TESTS ?= n +ifeq ($(PMDK_BUILD_DAOS_TESTS),y) # compile conditionally + +# check for required env vars +ifeq ($(DAOS_SRC_PATH),) +$(error DAOS_SRC_PATH is required) +endif + +ifeq ($(DAOS_INSTALL_PATH),) +$(error DAOS_INSTALL_PATH is required) +endif + +TARGET = daos_dtx +OBJS = daos_dtx.o + +BUILD_STATIC_DEBUG=n +BUILD_STATIC_NONDEBUG=n + +LIBPMEMOBJ=y + +include ../Makefile.inc +INCS += -I$(DAOS_SRC_PATH)/src/utils/ddb/ -I$(DAOS_INSTALL_PATH)/include/ +LIBS += -L$(DAOS_INSTALL_PATH)/lib64/daos_srv/ +DYNAMIC_LIBS += -lddb + +else +# required to support general targets like `cstyle` +include ../Makefile.inc +$(info Set PMDK_BUILD_DAOS_TESTS=y to build DAOS tests) +endif # PMDK_BUILD_DAOS_TESTS == y diff --git a/src/test/daos_dtx/README.md b/src/test/daos_dtx/README.md new file mode 100644 index 00000000000..cda802837e4 --- /dev/null +++ b/src/test/daos_dtx/README.md @@ -0,0 +1,31 @@ +# Required DAOS patches + +- `00_harmonize_VOS_pool_path.patch` which: + - harmonizes the VOS pool path in tests with normal DTX engine + - fixes both pool and container UUIDs so it is predictable +- `01_stop_using_test_args_reset.patch` which: + - stops the use of test_args_reset() + +> The use of the test_args_reset() utility breaks the setup/teardown symmetry. +If a test requires a pool/container to be recreated it has to do it in its +setup/teardown instead of relying on the test suite setup/teardown +(e.g. setup_io/teardown_io) and then calling test_args_reset() over and over +again. If a pool/container has been created in the setup, it should be destroyed +in the respective teardown. + +- `02_reduce_memory_requirements.patch` which: + - reduces the memory requirements for UTs +- `03_CMOCKA_FILTER_SUPPORTED.patch` which: + - `CMOCKA_FILTER_SUPPORTED=1` +- `04_force_use_sys_db.patch` which: + - forces the use of sys_db +- `05_dts_basic_create_open_close.patch` which: + - introduces dts_basic_create/open/close +- `06_basic_dtx_ut.patch` which: + - introduces a basic DTX life-cycle UT +- `07_disable_ABT.patch` which: + - prevents ABT from screwing with Valgrind +- `08_cmocka_filter_fix.patch` which: + - fixes cmocka's filter (invalid size calculation) +- `09_fix_size_t_from_int.patch` which: + - fixes conversion to size_t from int diff --git a/src/test/daos_dtx/TEST0 b/src/test/daos_dtx/TEST0 new file mode 100755 index 00000000000..7ce3ee8430c --- /dev/null +++ b/src/test/daos_dtx/TEST0 @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +# +# src/test/daos_dtx/TEST0 -- a kick-start test +# +# This directory contains both Bash-based and Python-based tests. The real +# Bash-based tests' numbering starts where the Python-based tests' numbering +# ends. However, the Bash-based test framework relies on the existence of +# this TEST0 file to keep looking for other Bash-based tests. +# + +. ../unittest/unittest.sh + +. ./common.sh + +require_fs_type any +require_build_type $COMMON_BUILD_TYPE +require_test_type short + +setup + +pass diff --git a/src/test/daos_dtx/TEST2 b/src/test/daos_dtx/TEST2 new file mode 100755 index 00000000000..761b5348b38 --- /dev/null +++ b/src/test/daos_dtx/TEST2 @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +# +# src/test/daos_dtx/TEST2 -- a test employing pmreorder +# + +. ../unittest/unittest.sh + +. ./common.sh + +common_require + +setup + +common_setup + +common_record +common_replay_and_check + +check + +pass diff --git a/src/test/daos_dtx/TESTS.py b/src/test/daos_dtx/TESTS.py new file mode 100755 index 00000000000..06a6c4bb9c8 --- /dev/null +++ b/src/test/daos_dtx/TESTS.py @@ -0,0 +1,34 @@ +#!../env.py +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation +# + + +import testframework as t +from testframework import granularity as g + + +@g.require_granularity(g.ANY) +@t.require_command('dtx_tests') +# The 'debug' build is chosen arbitrarily to ensure these tests are run only +# once. All used binares are provided externally. +@t.require_build('debug') +# There is no multithreading employed in this test. +@t.require_valgrind_disabled('helgrind', 'drd') +class DTX_TESTS(t.Test): + test_type = t.Short + + def run(self, ctx): + cmd = ['dtx_tests', '-S', ctx.testdir] + ctx.exec(*cmd, '-f', 'DTX400.a', cmd_requires_cwd=False) + ctx.exec(*cmd, '-f', 'DTX400.b', cmd_requires_cwd=False) + + +@t.require_valgrind_enabled('memcheck') +class TEST0(DTX_TESTS): + pass + + +@t.require_valgrind_enabled('pmemcheck') +class TEST1(DTX_TESTS): + pass diff --git a/src/test/daos_dtx/common.sh b/src/test/daos_dtx/common.sh new file mode 100755 index 00000000000..ec8eb4d0cbb --- /dev/null +++ b/src/test/daos_dtx/common.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2024, Intel Corporation + +# +# src/test/daos_dtx/common.sh -- common bits and pieces +# + +TESTS_BIN=dtx_tests +VERIFY_BIN=ddb + +# The 'debug' build is chosen arbitrarily to ensure these tests are run only +# once. All used binares are provided externally. +COMMON_BUILD_TYPE=debug + +function common_require() { + require_fs_type any + require_build_type $COMMON_BUILD_TYPE + require_test_type medium + require_command $TESTS_BIN + require_command $VERIFY_BIN + VERIFY_BIN=$(which $VERIFY_BIN) # an absolute path is required + PMEMOBJ_TESTS_BIN=$(ldd $(which $TESTS_BIN) | grep pmemobj | cut -d ' ' -f 3) + if [ ! -e "$PMEMOBJ_TESTS_BIN" ]; then + msg=$(interactive_red STDOUT "FAIL:") + echo -e "$UNITTEST_NAME: $msg Can not find LIBPMEMOBJ for $TESTS_BIN" + exit 1 + fi + require_pmemcheck_version_ge 1 0 $PMEMOBJ_TESTS_BIN + require_pmemcheck_version_lt 2 0 $PMEMOBJ_TESTS_BIN + require_pmreorder $PMEMOBJ_TESTS_BIN +} + +function common_setup() { + if [ -n $DAOS_PATH ]; then + export LD_LIBRARY_PATH=$DAOS_PATH/prereq/debug/ofi/lib:$LD_LIBRARY_PATH + fi + export PMEMOBJ_LOG_LEVEL=10 + + PREP_CMD="$TESTS_BIN -S $DIR -f DTX400.a" + PMEMCHECK_CMD="$TESTS_BIN -S $DIR -f DTX400.b" + + PMREORDER_CMD="./daos_dtx cmd_verify" +} + +function common_record() { + # create a pool and a container first to reduce the size of the recording + expect_normal_exit $PREP_CMD + + SYS_FILE="$DIR/daos_sys/sys_db" + POOL_FILE="$DIR/dd6728be-696a-11ef-a059-a4bf0165c389/vpool.0" + + # backup the sys file + # (the pool file is backed up when the store log is recorded below) + cp $SYS_FILE $SYS_FILE.pmr + + export PMREORDER_EMIT_LOG=1 # ask PMDK to emit its markers as well + pmreorder_create_store_log "$POOL_FILE" "$PMEMCHECK_CMD" + export -n PMREORDER_EMIT_LOG # stop the export + + # restore the sys file + mv $SYS_FILE.pmr $SYS_FILE + + # Get rid of unnecessary markers just to speed things up. + # The markers to be removed were hand-picked to match the tested scenario. + STORE_LOG=store_log$UNITTEST_NUM.log + tr '|' '\n' < $STORE_LOG > $STORE_LOG.cpy + grep -v "libpmemobj" $STORE_LOG.cpy | \ + grep -v "libpmem" | \ + grep -v "pmemobj_ctl_set" | \ + grep -v "pmemobj_open" | \ + grep -v "pmemobj_close" | \ + grep -v "pmemobj_root" | \ + grep -v "pmem_memcpy" | \ + grep -v "pmem_memset" > $STORE_LOG.fixed + tr '\n' '|' < $STORE_LOG.fixed > $STORE_LOG + rm $STORE_LOG.cpy $STORE_LOG.fixed +} + +function common_replay_and_check() { + # skip reordering and checking stores outside of the markers + DEFAULT_ENGINE=NoReorderNoCheck + # XXX The accumulative reordering is sufficient considering the nature of + # the scenario at hand where the key risk is that not all stores + # will be executed. The order of these stores is irrelevant. + # Please see the source code for the details of the tested scenario. + # Note: ReorderFull is too time-consuming for this scenario. + EXTENDED_MACROS="PMREORDER_DTX_BASIC=NoReorderDoCheck" + + # Since we do not aim at testing PMDK itself here it is assumed the PMDK + # APIs just work. No need to reorder or to check its actions step by step. + # The PMDK APIs on the list were hand-picked to match the APIs used. + # FUNCS="pmemobj_tx_xalloc pmemobj_tx_add_range_direct pmemobj_tx_xadd_range pmemobj_tx_abort pmemobj_tx_commit" + # for func in $FUNCS; do + # EXTENDED_MACROS="$EXTENDED_MACROS,$func=NoReorderNoCheck" + # done + + export LD_LIBRARY_PATH="/opt/daos/lib64/daos_srv/:$LD_LIBRARY_PATH" + pmreorder_expect_success $DEFAULT_ENGINE "$EXTENDED_MACROS" "$PMREORDER_CMD" +} diff --git a/src/test/daos_dtx/daos_dtx.c b/src/test/daos_dtx/daos_dtx.c new file mode 100644 index 00000000000..2d7f15bfcf2 --- /dev/null +++ b/src/test/daos_dtx/daos_dtx.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2024, Intel Corporation */ + +/* + * daos_dtx.c -- XXX + */ + +#include + +#include "unittest.h" + +#define SYS_DB_NAME "sys_db" + +#define DTX_DUMP_PATH "/591d19e4-69fe-11ef-b13d-a4bf0165c389" + +static bool +is_sys_db(const char *path) +{ + const char *file_name = strrchr(path, '/'); + ++file_name; + return strncmp(file_name, SYS_DB_NAME, sizeof(SYS_DB_NAME)) == 0; +} + +/* + * cmd_verify -- XXX + */ +static int +cmd_verify(const struct test_case *tc, int argc, char *argv[]) +{ + struct ddb_ctx ctx; + struct open_options open; + struct dtx_dump_options dtx_dump; + int rc; + + if (argc < 1) { + UT_FATAL("usage: %s filename", __FUNCTION__); + } + + const char *path = argv[0]; + + if (is_sys_db(path)) { + /* + * pmreorder asks to verify the consistency of each of + * the recorded files separately. This test ignores changes made + * to sys_db so just skip it. + */ + END(0); + } + + fprintf(stderr, "%s %s\n", __FUNCTION__, path); + + /* + * The setting preferred by the pmreorder's verify implementations. + */ + int y = 1; + pmemobj_ctl_set(NULL, "copy_on_write.at_open", &y); + + rc = ddb_init(); + UT_ASSERTeq(rc, 0); + + ddb_ctx_init(&ctx); + ctx.dc_io_ft.ddb_print_message = ctx.dc_io_ft.ddb_print_error; + + /* open */ + open.write_mode = false; + open.path = (char *)path; + rc = ddb_run_open(&ctx, &open); + UT_ASSERTeq(rc, 0); + + /* dtx_dump */ + dtx_dump.active = true; + dtx_dump.committed = true; + dtx_dump.path = DTX_DUMP_PATH; + rc = ddb_run_dtx_dump(&ctx, &dtx_dump); + UT_ASSERTeq(rc, 0); + + /* close */ + rc = ddb_run_close(&ctx); + UT_ASSERTeq(rc, 0); + + ddb_fini(); + + /* + * If the verify did not fail till now it has passed successfully. + * Return the result ASAP. + */ + END(0); +} + +static struct test_case test_cases[] = { + TEST_CASE(cmd_verify), +}; + +int +main(int argc, char *argv[]) +{ + START(argc, argv, "daos_dtx"); + + TEST_CASE_PROCESS(argc, argv, test_cases, ARRAY_SIZE(test_cases)); + + DONE(NULL); +} diff --git a/src/test/unittest/context.py b/src/test/unittest/context.py index 8cf7a1d2c42..79766740212 100644 --- a/src/test/unittest/context.py +++ b/src/test/unittest/context.py @@ -1,5 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause -# Copyright 2019-2023, Intel Corporation +# Copyright 2019-2024, Intel Corporation # """ @@ -290,7 +290,7 @@ def new_poolset(self, path): return _Poolset(path, self) def exec(self, cmd, *args, expected_exitcode=0, stderr_file=None, - stdout_file=None, std_input=None): + stdout_file=None, std_input=None, cmd_requires_cwd=True): """ Execute binary in the current test context as a separate process. @@ -320,8 +320,8 @@ def exec(self, cmd, *args, expected_exitcode=0, stderr_file=None, # change cmd into list for supbrocess type compliance cmd = [cmd, ] - cmd[0] = os.path.join(self.cwd, cmd[0]) + \ - self.build.exesuffix + if cmd_requires_cwd: + cmd[0] = os.path.join(self.cwd, cmd[0]) + self.build.exesuffix if self.valgrind: cmd = self.valgrind.cmd + cmd