From a099e04b0b49bce74d45e269f9386c12ca86d7a7 Mon Sep 17 00:00:00 2001 From: Karthick Ariyaratnam Date: Tue, 7 May 2024 19:49:24 -0400 Subject: [PATCH] Migrate kvstore.c unit tests to new test framework. (#446) This PR migrates all tests related to kvstore into new test framework as part of the parent issue https://github.com/valkey-io/valkey/issues/428. --------- Signed-off-by: Karthick Ariyaratnam Signed-off-by: Madelyn Olson Co-authored-by: Madelyn Olson Signed-off-by: Karthick Ariyaratnam --- src/kvstore.c | 147 ---------------------------- src/kvstore.h | 4 - src/server.c | 1 - src/unit/test_files.h | 7 ++ src/unit/test_kvstore.c | 205 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 152 deletions(-) create mode 100644 src/unit/test_kvstore.c diff --git a/src/kvstore.c b/src/kvstore.c index 2f954157b3..ccf79a6f18 100644 --- a/src/kvstore.c +++ b/src/kvstore.c @@ -865,150 +865,3 @@ int kvstoreDictDelete(kvstore *kvs, int didx, const void *key) { } return ret; } - -#ifdef SERVER_TEST -#include -#include "testhelp.h" - -#define TEST(name) printf("test — %s\n", name); - -uint64_t hashTestCallback(const void *key) { - return dictGenHashFunction((unsigned char*)key, strlen((char*)key)); -} - -void freeTestCallback(dict *d, void *val) { - UNUSED(d); - zfree(val); -} - -dictType KvstoreDictTestType = { - hashTestCallback, - NULL, - NULL, - NULL, - freeTestCallback, - NULL, - NULL -}; - -char *stringFromInt(int value) { - char buf[32]; - int len; - char *s; - - len = snprintf(buf, sizeof(buf), "%d",value); - s = zmalloc(len+1); - memcpy(s, buf, len); - s[len] = '\0'; - return s; -} - -/* ./valkey-server test kvstore */ -int kvstoreTest(int argc, char **argv, int flags) { - UNUSED(argc); - UNUSED(argv); - UNUSED(flags); - - int i; - void *key; - dictEntry *de; - kvstoreIterator *kvs_it; - kvstoreDictIterator *kvs_di; - - int didx = 0; - int curr_slot = 0; - kvstore *kvs1 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND); - kvstore *kvs2 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND | KVSTORE_FREE_EMPTY_DICTS); - - TEST("Add 16 keys") { - for (i = 0; i < 16; i++) { - de = kvstoreDictAddRaw(kvs1, didx, stringFromInt(i), NULL); - assert(de != NULL); - de = kvstoreDictAddRaw(kvs2, didx, stringFromInt(i), NULL); - assert(de != NULL); - } - assert(kvstoreDictSize(kvs1, didx) == 16); - assert(kvstoreSize(kvs1) == 16); - assert(kvstoreDictSize(kvs2, didx) == 16); - assert(kvstoreSize(kvs2) == 16); - } - - TEST("kvstoreIterator case 1: removing all keys does not delete the empty dict") { - kvs_it = kvstoreIteratorInit(kvs1); - while((de = kvstoreIteratorNext(kvs_it)) != NULL) { - curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); - key = dictGetKey(de); - assert(kvstoreDictDelete(kvs1, curr_slot, key) == DICT_OK); - } - kvstoreIteratorRelease(kvs_it); - - dict *d = kvstoreGetDict(kvs1, didx); - assert(d != NULL); - assert(kvstoreDictSize(kvs1, didx) == 0); - assert(kvstoreSize(kvs1) == 0); - } - - TEST("kvstoreIterator case 2: removing all keys will delete the empty dict") { - kvs_it = kvstoreIteratorInit(kvs2); - while((de = kvstoreIteratorNext(kvs_it)) != NULL) { - curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); - key = dictGetKey(de); - assert(kvstoreDictDelete(kvs2, curr_slot, key) == DICT_OK); - } - kvstoreIteratorRelease(kvs_it); - - /* Make sure the dict was removed from the rehashing list. */ - while (kvstoreIncrementallyRehash(kvs2, 1000)) {} - - dict *d = kvstoreGetDict(kvs2, didx); - assert(d == NULL); - assert(kvstoreDictSize(kvs2, didx) == 0); - assert(kvstoreSize(kvs2) == 0); - } - - TEST("Add 16 keys again") { - for (i = 0; i < 16; i++) { - de = kvstoreDictAddRaw(kvs1, didx, stringFromInt(i), NULL); - assert(de != NULL); - de = kvstoreDictAddRaw(kvs2, didx, stringFromInt(i), NULL); - assert(de != NULL); - } - assert(kvstoreDictSize(kvs1, didx) == 16); - assert(kvstoreSize(kvs1) == 16); - assert(kvstoreDictSize(kvs2, didx) == 16); - assert(kvstoreSize(kvs2) == 16); - } - - TEST("kvstoreDictIterator case 1: removing all keys does not delete the empty dict") { - kvs_di = kvstoreGetDictSafeIterator(kvs1, didx); - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { - key = dictGetKey(de); - assert(kvstoreDictDelete(kvs1, didx, key) == DICT_OK); - } - kvstoreReleaseDictIterator(kvs_di); - - dict *d = kvstoreGetDict(kvs1, didx); - assert(d != NULL); - assert(kvstoreDictSize(kvs1, didx) == 0); - assert(kvstoreSize(kvs1) == 0); - } - - TEST("kvstoreDictIterator case 2: removing all keys will delete the empty dict") { - kvs_di = kvstoreGetDictSafeIterator(kvs2, didx); - while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { - key = dictGetKey(de); - assert(kvstoreDictDelete(kvs2, didx, key) == DICT_OK); - } - kvstoreReleaseDictIterator(kvs_di); - - dict *d = kvstoreGetDict(kvs2, didx); - assert(d == NULL); - assert(kvstoreDictSize(kvs2, didx) == 0); - assert(kvstoreSize(kvs2) == 0); - } - - kvstoreRelease(kvs1); - kvstoreRelease(kvs2); - return 0; -} -#endif diff --git a/src/kvstore.h b/src/kvstore.h index b3d8a0e4aa..56a4861997 100644 --- a/src/kvstore.h +++ b/src/kvstore.h @@ -72,8 +72,4 @@ dictEntry *kvstoreDictTwoPhaseUnlinkFind(kvstore *kvs, int didx, const void *key void kvstoreDictTwoPhaseUnlinkFree(kvstore *kvs, int didx, dictEntry *he, dictEntry **plink, int table_index); int kvstoreDictDelete(kvstore *kvs, int didx, const void *key); -#ifdef SERVER_TEST -int kvstoreTest(int argc, char *argv[], int flags); -#endif - #endif /* DICTARRAY_H_ */ diff --git a/src/server.c b/src/server.c index f267211850..6dcbd9492d 100644 --- a/src/server.c +++ b/src/server.c @@ -6910,7 +6910,6 @@ struct serverTest { {"sds", sdsTest}, {"dict", dictTest}, {"listpack", listpackTest}, - {"kvstore", kvstoreTest}, }; serverTestProc *getTestProcByName(const char *name) { int numtests = sizeof(serverTests)/sizeof(struct serverTest); diff --git a/src/unit/test_files.h b/src/unit/test_files.h index 05fe3b4499..600369bbe7 100644 --- a/src/unit/test_files.h +++ b/src/unit/test_files.h @@ -16,6 +16,11 @@ int test_intsetUpgradeFromint16Toint64(int argc, char **argv, int flags); int test_intsetUpgradeFromint32Toint64(int argc, char **argv, int flags); int test_intsetStressLookups(int argc, char **argv, int flags); int test_intsetStressAddDelete(int argc, char **argv, int flags); +int test_kvstoreAdd16Keys(int argc, char **argv, int flags); +int test_kvstoreIteratorRemoveAllKeysNoDeleteEmptyDict(int argc, char **argv, int flags); +int test_kvstoreIteratorRemoveAllKeysDeleteEmptyDict(int argc, char **argv, int flags); +int test_kvstoreDictIteratorRemoveAllKeysNoDeleteEmptyDict(int argc, char **argv, int flags); +int test_kvstoreDictIteratorRemoveAllKeysDeleteEmptyDict(int argc, char **argv, int flags); int test_string2ll(int argc, char **argv, int flags); int test_string2l(int argc, char **argv, int flags); int test_ll2string(int argc, char **argv, int flags); @@ -29,6 +34,7 @@ int test_zmallocAllocZeroBytesAndFree(int argc, char **argv, int flags); unitTest __test_crc64_c[] = {{"test_crc64", test_crc64}, {NULL, NULL}}; unitTest __test_crc64combine_c[] = {{"test_crc64combine", test_crc64combine}, {NULL, NULL}}; unitTest __test_intset_c[] = {{"test_intsetValueEncodings", test_intsetValueEncodings}, {"test_intsetBasicAdding", test_intsetBasicAdding}, {"test_intsetLargeNumberRandomAdd", test_intsetLargeNumberRandomAdd}, {"test_intsetUpgradeFromint16Toint32", test_intsetUpgradeFromint16Toint32}, {"test_intsetUpgradeFromint16Toint64", test_intsetUpgradeFromint16Toint64}, {"test_intsetUpgradeFromint32Toint64", test_intsetUpgradeFromint32Toint64}, {"test_intsetStressLookups", test_intsetStressLookups}, {"test_intsetStressAddDelete", test_intsetStressAddDelete}, {NULL, NULL}}; +unitTest __test_kvstore_c[] = {{"test_kvstoreAdd16Keys", test_kvstoreAdd16Keys}, {"test_kvstoreIteratorRemoveAllKeysNoDeleteEmptyDict", test_kvstoreIteratorRemoveAllKeysNoDeleteEmptyDict}, {"test_kvstoreIteratorRemoveAllKeysDeleteEmptyDict", test_kvstoreIteratorRemoveAllKeysDeleteEmptyDict}, {"test_kvstoreDictIteratorRemoveAllKeysNoDeleteEmptyDict", test_kvstoreDictIteratorRemoveAllKeysNoDeleteEmptyDict}, {"test_kvstoreDictIteratorRemoveAllKeysDeleteEmptyDict", test_kvstoreDictIteratorRemoveAllKeysDeleteEmptyDict}, {NULL, NULL}}; unitTest __test_util_c[] = {{"test_string2ll", test_string2ll}, {"test_string2l", test_string2l}, {"test_ll2string", test_ll2string}, {"test_ld2string", test_ld2string}, {"test_fixedpoint_d2string", test_fixedpoint_d2string}, {"test_reclaimFilePageCache", test_reclaimFilePageCache}, {NULL, NULL}}; unitTest __test_zmalloc_c[] = {{"test_zmallocInitialUsedMemory", test_zmallocInitialUsedMemory}, {"test_zmallocAllocReallocCallocAndFree", test_zmallocAllocReallocCallocAndFree}, {"test_zmallocAllocZeroBytesAndFree", test_zmallocAllocZeroBytesAndFree}, {NULL, NULL}}; @@ -39,6 +45,7 @@ struct unitTestSuite { {"test_crc64.c", __test_crc64_c}, {"test_crc64combine.c", __test_crc64combine_c}, {"test_intset.c", __test_intset_c}, + {"test_kvstore.c", __test_kvstore_c}, {"test_util.c", __test_util_c}, {"test_zmalloc.c", __test_zmalloc_c}, }; diff --git a/src/unit/test_kvstore.c b/src/unit/test_kvstore.c new file mode 100644 index 0000000000..65a8389a84 --- /dev/null +++ b/src/unit/test_kvstore.c @@ -0,0 +1,205 @@ +#include "../kvstore.c" +#undef UNUSED +#include "test_help.h" + +uint64_t hashTestCallback(const void *key) { + return dictGenHashFunction((unsigned char*)key, strlen((char*)key)); +} + +void freeTestCallback(dict *d, void *val) { + UNUSED(d); + zfree(val); +} + +dictType KvstoreDictTestType = { + hashTestCallback, + NULL, + NULL, + NULL, + freeTestCallback, + NULL, + NULL +}; + +char *stringFromInt(int value) { + char buf[32]; + int len; + char *s; + + len = snprintf(buf, sizeof(buf), "%d",value); + s = zmalloc(len+1); + memcpy(s, buf, len); + s[len] = '\0'; + return s; +} + +int test_kvstoreAdd16Keys(int argc, char **argv, int flags) { + UNUSED(argc); + UNUSED(argv); + UNUSED(flags); + + int i; + dictEntry *de; + + int didx = 0; + kvstore *kvs1 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND); + kvstore *kvs2 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND | KVSTORE_FREE_EMPTY_DICTS); + + for (i = 0; i < 16; i++) { + de = kvstoreDictAddRaw(kvs1, didx, stringFromInt(i), NULL); + TEST_ASSERT(de != NULL); + de = kvstoreDictAddRaw(kvs2, didx, stringFromInt(i), NULL); + TEST_ASSERT(de != NULL); + } + TEST_ASSERT(kvstoreDictSize(kvs1, didx) == 16); + TEST_ASSERT(kvstoreSize(kvs1) == 16); + TEST_ASSERT(kvstoreDictSize(kvs2, didx) == 16); + TEST_ASSERT(kvstoreSize(kvs2) == 16); + + kvstoreRelease(kvs1); + kvstoreRelease(kvs2); + return 0; +} + +int test_kvstoreIteratorRemoveAllKeysNoDeleteEmptyDict(int argc, char **argv, int flags) { + UNUSED(argc); + UNUSED(argv); + UNUSED(flags); + + int i; + void *key; + dictEntry *de; + kvstoreIterator *kvs_it; + + int didx = 0; + int curr_slot = 0; + kvstore *kvs1 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND); + + for (i = 0; i < 16; i++) { + de = kvstoreDictAddRaw(kvs1, didx, stringFromInt(i), NULL); + TEST_ASSERT(de != NULL); + } + + kvs_it = kvstoreIteratorInit(kvs1); + while((de = kvstoreIteratorNext(kvs_it)) != NULL) { + curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + key = dictGetKey(de); + TEST_ASSERT(kvstoreDictDelete(kvs1, curr_slot, key) == DICT_OK); + } + kvstoreIteratorRelease(kvs_it); + + dict *d = kvstoreGetDict(kvs1, didx); + TEST_ASSERT(d != NULL); + TEST_ASSERT(kvstoreDictSize(kvs1, didx) == 0); + TEST_ASSERT(kvstoreSize(kvs1) == 0); + + kvstoreRelease(kvs1); + return 0; +} + +int test_kvstoreIteratorRemoveAllKeysDeleteEmptyDict(int argc, char **argv, int flags) { + UNUSED(argc); + UNUSED(argv); + UNUSED(flags); + + int i; + void *key; + dictEntry *de; + kvstoreIterator *kvs_it; + + int didx = 0; + int curr_slot = 0; + kvstore *kvs2 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND | KVSTORE_FREE_EMPTY_DICTS); + + for (i = 0; i < 16; i++) { + de = kvstoreDictAddRaw(kvs2, didx, stringFromInt(i), NULL); + TEST_ASSERT(de != NULL); + } + + kvs_it = kvstoreIteratorInit(kvs2); + while((de = kvstoreIteratorNext(kvs_it)) != NULL) { + curr_slot = kvstoreIteratorGetCurrentDictIndex(kvs_it); + key = dictGetKey(de); + TEST_ASSERT(kvstoreDictDelete(kvs2, curr_slot, key) == DICT_OK); + } + kvstoreIteratorRelease(kvs_it); + + /* Make sure the dict was removed from the rehashing list. */ + while (kvstoreIncrementallyRehash(kvs2, 1000)) {} + + dict *d = kvstoreGetDict(kvs2, didx); + TEST_ASSERT(d == NULL); + TEST_ASSERT(kvstoreDictSize(kvs2, didx) == 0); + TEST_ASSERT(kvstoreSize(kvs2) == 0); + + kvstoreRelease(kvs2); + return 0; +} + +int test_kvstoreDictIteratorRemoveAllKeysNoDeleteEmptyDict(int argc, char **argv, int flags) { + UNUSED(argc); + UNUSED(argv); + UNUSED(flags); + + int i; + void *key; + dictEntry *de; + kvstoreDictIterator *kvs_di; + + int didx = 0; + kvstore *kvs1 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND); + + for (i = 0; i < 16; i++) { + de = kvstoreDictAddRaw(kvs1, didx, stringFromInt(i), NULL); + TEST_ASSERT(de != NULL); + } + + kvs_di = kvstoreGetDictSafeIterator(kvs1, didx); + while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + key = dictGetKey(de); + TEST_ASSERT(kvstoreDictDelete(kvs1, didx, key) == DICT_OK); + } + kvstoreReleaseDictIterator(kvs_di); + + dict *d = kvstoreGetDict(kvs1, didx); + TEST_ASSERT(d != NULL); + TEST_ASSERT(kvstoreDictSize(kvs1, didx) == 0); + TEST_ASSERT(kvstoreSize(kvs1) == 0); + + kvstoreRelease(kvs1); + return 0; +} + +int test_kvstoreDictIteratorRemoveAllKeysDeleteEmptyDict(int argc, char **argv, int flags) { + UNUSED(argc); + UNUSED(argv); + UNUSED(flags); + + int i; + void *key; + dictEntry *de; + kvstoreDictIterator *kvs_di; + + int didx = 0; + kvstore *kvs2 = kvstoreCreate(&KvstoreDictTestType, 0, KVSTORE_ALLOCATE_DICTS_ON_DEMAND | KVSTORE_FREE_EMPTY_DICTS); + + for (i = 0; i < 16; i++) { + de = kvstoreDictAddRaw(kvs2, didx, stringFromInt(i), NULL); + TEST_ASSERT(de != NULL); + } + + kvs_di = kvstoreGetDictSafeIterator(kvs2, didx); + while((de = kvstoreDictIteratorNext(kvs_di)) != NULL) { + key = dictGetKey(de); + TEST_ASSERT(kvstoreDictDelete(kvs2, didx, key) == DICT_OK); + } + kvstoreReleaseDictIterator(kvs_di); + + dict *d = kvstoreGetDict(kvs2, didx); + TEST_ASSERT(d == NULL); + TEST_ASSERT(kvstoreDictSize(kvs2, didx) == 0); + TEST_ASSERT(kvstoreSize(kvs2) == 0); + + kvstoreRelease(kvs2); + return 0; +}