1 #include "iwkv.h"
2 #include "iwlog.h"
3 #include "iwutils.h"
4 #include "iwcfg.h"
5 #include "iwkv_tests.h"
6 #include "iwkv_internal.h"
7
8 uint32_t g_seed;
9 uint32_t g_rnd_data_pos;
10 #define RND_DATA_SZ (10*1048576)
11 char RND_DATA[RND_DATA_SZ];
12
rndbuf_next(uint32_t len)13 static void *rndbuf_next(uint32_t len) {
14 assert(len <= RND_DATA_SZ);
15 if (g_rnd_data_pos + len > RND_DATA_SZ) {
16 g_rnd_data_pos = 0;
17 }
18 const char *ret = RND_DATA + g_rnd_data_pos;
19 g_rnd_data_pos += len;
20 return (void *) ret;
21 }
22
init_suite(void)23 int init_suite(void) {
24 iwrc rc = iwkv_init();
25 RCRET(rc);
26 uint64_t ts;
27 iwp_current_time_ms(&ts, false);
28 ts = IW_SWAB64(ts);
29 ts >>= 32;
30 g_seed = ts;
31
32 fprintf(stderr, "\nRandom seed: %u\n", g_seed);
33 iwu_rand_seed(g_seed);
34 for (int i = 0; i < RND_DATA_SZ; ++i) {
35 RND_DATA[i] = ' ' + iwu_rand_range(95); // ascii space ... ~
36 }
37 return rc;
38 }
39
clean_suite(void)40 int clean_suite(void) {
41 return 0;
42 }
43
iwkv_test4_4(void)44 static void iwkv_test4_4(void) {
45 char *path = "iwkv_test4_4.db";
46 IWKV iwkv;
47 IWDB db1;
48 IWKV_val key = {0};
49 IWKV_val val = {0};
50 IWKV_OPTS opts = {
51 .path = path,
52 .oflags = IWKV_TRUNC,
53 .random_seed = g_seed,
54 .wal = {
55 .enabled = true,
56 .savepoint_timeout_sec = 2,
57 .checkpoint_timeout_sec = 300
58 }
59 };
60 iwrc rc = iwkv_open(&opts, &iwkv);
61 CU_ASSERT_EQUAL_FATAL(rc, 0);
62 rc = iwkv_db(iwkv, 1, 0, &db1);
63 CU_ASSERT_EQUAL_FATAL(rc, 0);
64
65 key.data = "key00001";
66 key.size = strlen(key.data);
67 val.data = "value00001";
68 val.size = strlen(val.data);
69 rc = iwkv_put(db1, &key, &val, 0);
70 CU_ASSERT_EQUAL_FATAL(rc, 0);
71
72 CU_ASSERT_FALSE(iwal_synched(iwkv));
73
74 sleep(4);
75
76 CU_ASSERT_TRUE(iwal_synched(iwkv));
77
78 rc = iwkv_close(&iwkv);
79 CU_ASSERT_EQUAL_FATAL(rc, 0);
80 }
81
iwkv_test4_3_impl(int fmt_version)82 static void iwkv_test4_3_impl(int fmt_version) {
83 char *path = "iwkv_test4_3.db";
84 IWKV iwkv;
85 IWDB db1;
86 IWKV_val key = {0};
87 IWKV_val val = {0};
88 IWKV_OPTS opts = {
89 .path = path,
90 .oflags = IWKV_TRUNC | IWKV_NO_TRIM_ON_CLOSE,
91 .random_seed = g_seed,
92 .fmt_version = fmt_version,
93 .wal = {
94 .enabled = true,
95 .check_crc_on_checkpoint = true,
96 .savepoint_timeout_sec = UINT32_MAX
97 }
98 };
99 iwrc rc = iwkv_open(&opts, &iwkv);
100 CU_ASSERT_EQUAL_FATAL(rc, 0);
101 rc = iwkv_db(iwkv, 1, 0, &db1);
102 CU_ASSERT_EQUAL_FATAL(rc, 0);
103
104 key.data = "key00001";
105 key.size = strlen(key.data);
106 val.data = "value00001";
107 val.size = strlen(val.data);
108 rc = iwkv_put(db1, &key, &val, 0);
109 CU_ASSERT_EQUAL_FATAL(rc, 0);
110
111 rc = iwkv_sync(iwkv, 0);
112 CU_ASSERT_EQUAL_FATAL(rc, 0);
113
114 key.data = "key00002";
115 key.size = strlen(key.data);
116 val.data = "value00002";
117 val.size = strlen(val.data);
118 rc = iwkv_put(db1, &key, &val, 0);
119 CU_ASSERT_EQUAL_FATAL(rc, 0);
120
121 rc = iwkv_sync(iwkv, 0);
122 CU_ASSERT_EQUAL_FATAL(rc, 0);
123
124 key.data = "key00003";
125 key.size = strlen(key.data);
126 val.data = "value00003";
127 val.size = strlen(val.data);
128 rc = iwkv_put(db1, &key, &val, 0);
129 CU_ASSERT_EQUAL_FATAL(rc, 0);
130
131 iwkvd_trigger_xor(IWKVD_WAL_NO_CHECKPOINT_ON_CLOSE);
132
133 rc = iwkv_close(&iwkv);
134 CU_ASSERT_EQUAL_FATAL(rc, 0);
135
136 // Now reopen and roll WAL log
137
138 iwkvd_trigger_xor(IWKVD_WAL_NO_CHECKPOINT_ON_CLOSE);
139
140 opts.oflags &= ~IWKV_TRUNC;
141 rc = iwkv_open(&opts, &iwkv);
142 CU_ASSERT_EQUAL_FATAL(rc, 0);
143 rc = iwkv_db(iwkv, 1, 0, &db1);
144 CU_ASSERT_EQUAL_FATAL(rc, 0);
145
146 key.data = "key00001";
147 key.size = strlen(key.data);
148 rc = iwkv_get(db1, &key, &val);
149 CU_ASSERT_EQUAL_FATAL(rc, 0); // !!!!
150 CU_ASSERT_NSTRING_EQUAL(val.data, "value00001", val.size);
151 iwkv_kv_dispose(0, &val);
152
153 key.data = "key00002";
154 key.size = strlen(key.data);
155 rc = iwkv_get(db1, &key, &val);
156 CU_ASSERT_EQUAL_FATAL(rc, 0);
157 CU_ASSERT_NSTRING_EQUAL(val.data, "value00002", val.size);
158 iwkv_kv_dispose(0, &val);
159
160 key.data = "key00003";
161 key.size = strlen(key.data);
162 rc = iwkv_get(db1, &key, &val);
163 CU_ASSERT_EQUAL_FATAL(rc, IWKV_ERROR_NOTFOUND);
164
165 rc = iwkv_close(&iwkv);
166 CU_ASSERT_EQUAL_FATAL(rc, 0);
167 }
168
iwkv_test4_3_v1()169 static void iwkv_test4_3_v1() {
170 iwkv_test4_3_impl(1);
171 }
172
iwkv_test4_3_v2()173 static void iwkv_test4_3_v2() {
174 iwkv_test4_3_impl(2);
175 }
176
iwkv_test2_impl(char * path,const char * walpath,uint32_t num,uint32_t vrange)177 static void iwkv_test2_impl(char *path, const char *walpath, uint32_t num, uint32_t vrange) {
178 g_rnd_data_pos = 0;
179 char kbuf[100];
180 iwrc rc;
181 IWKV iwkv;
182 IWDB db1;
183 if (walpath) {
184 unlink(walpath);
185 }
186 IWKV_val key = {0};
187 IWKV_val val = {0};
188 IWKV_OPTS opts = {
189 .path = path,
190 .oflags = IWKV_TRUNC,
191 .random_seed = g_seed,
192 .wal = {
193 .enabled = (walpath != NULL),
194 .check_crc_on_checkpoint = true,
195 .savepoint_timeout_sec = UINT32_MAX,
196 .wal_buffer_sz = 64 * 1024,
197 .checkpoint_buffer_sz = 32 * 1024 * 1024
198 }
199 };
200 rc = iwkv_open(&opts, &iwkv);
201 CU_ASSERT_EQUAL_FATAL(rc, 0);
202
203 rc = iwkv_db(iwkv, 1, 0, &db1);
204 CU_ASSERT_EQUAL_FATAL(rc, 0);
205
206 key.data = kbuf;
207
208 for (int i = 0; i < num; ++i) {
209 int k = iwu_rand_range(num);
210 snprintf(key.data, sizeof(kbuf), "%016d", k);
211 key.size = strlen(key.data);
212 uint32_t value_size = iwu_rand_range(vrange + 1);
213 if (value_size == 0) {
214 value_size = 1;
215 }
216 val.data = rndbuf_next(value_size);
217 val.size = value_size;
218 rc = iwkv_put(db1, &key, &val, 0);
219 CU_ASSERT_EQUAL_FATAL(rc, 0);
220 }
221 rc = iwkv_close(&iwkv);
222 CU_ASSERT_EQUAL_FATAL(rc, 0);
223 }
224
iwkv_test4_2(void)225 static void iwkv_test4_2(void) {
226 uint32_t num = 1000;
227 uint32_t vrange = 100000;
228 iwkv_test2_impl("iwkv_test4_2.db", NULL, num, vrange);
229 iwkv_test2_impl("iwkv_test4_2wal.db", "iwkv_test4_2wal.db-wal", num, vrange);
230 FILE *iw1 = fopen("iwkv_test4_2.db", "rb");
231 CU_ASSERT_PTR_NOT_NULL_FATAL(iw1);
232 FILE *iw2 = fopen("iwkv_test4_2wal.db", "rb");
233 CU_ASSERT_PTR_NOT_NULL_FATAL(iw2);
234 int ret = cmp_files(iw1, iw2);
235 CU_ASSERT_FALSE(ret);
236 fclose(iw1);
237 fclose(iw2);
238 }
239
iwkv_test1_impl(char * path,const char * walpath)240 static void iwkv_test1_impl(char *path, const char *walpath) {
241 iwrc rc;
242 IWKV iwkv;
243 IWDB db1, db2;
244 if (walpath) {
245 unlink(walpath);
246 }
247 IWKV_val key = {0};
248 IWKV_val val = {0};
249 IWKV_OPTS opts = {
250 .path = path,
251 .oflags = IWKV_TRUNC,
252 .wal = {
253 .enabled = (walpath != NULL),
254 .savepoint_timeout_sec = UINT32_MAX
255 }
256 };
257 rc = iwkv_open(&opts, &iwkv);
258 CU_ASSERT_EQUAL_FATAL(rc, 0);
259
260 rc = iwkv_db(iwkv, 1, 0, &db1);
261 CU_ASSERT_EQUAL_FATAL(rc, 0);
262
263 rc = iwkv_db(iwkv, 2, 0, &db2);
264 CU_ASSERT_EQUAL_FATAL(rc, 0);
265
266 key.data = "foo";
267 key.size = strlen(key.data);
268 val.data = "bar";
269 val.size = strlen(val.data);
270 rc = iwkv_put(db1, &key, &val, 0);
271 CU_ASSERT_EQUAL_FATAL(rc, 0);
272
273 key.data = "foozz";
274 key.size = strlen(key.data);
275 val.data = "bazz";
276 val.size = strlen(val.data);
277 rc = iwkv_put(db2, &key, &val, 0);
278 CU_ASSERT_EQUAL_FATAL(rc, 0);
279
280 key.data = "foozz2";
281 key.size = strlen(key.data);
282 val.data = "bazzbazzbazzbazz";
283 val.size = strlen(val.data);
284 rc = iwkv_put(db2, &key, &val, 0);
285 CU_ASSERT_EQUAL_FATAL(rc, 0);
286
287 key.data = "foozz";
288 key.size = strlen(key.data);
289 rc = iwkv_del(db2, &key, 0);
290 CU_ASSERT_EQUAL_FATAL(rc, 0);
291
292 rc = iwkv_db_destroy(&db2);
293 CU_ASSERT_EQUAL_FATAL(rc, 0);
294
295 rc = iwkv_close(&iwkv);
296 CU_ASSERT_EQUAL_FATAL(rc, 0);
297 }
298
iwkv_test4_1(void)299 static void iwkv_test4_1(void) {
300 iwkv_test1_impl("iwkv_test4_1.db", NULL);
301 iwkv_test1_impl("iwkv_test4_1wal.db", "iwkv_test4_1wal.db-wal");
302 FILE *iw1 = fopen("iwkv_test4_1.db", "rb");
303 CU_ASSERT_PTR_NOT_NULL_FATAL(iw1);
304 FILE *iw2 = fopen("iwkv_test4_1wal.db", "rb");
305 CU_ASSERT_PTR_NOT_NULL_FATAL(iw2);
306 int ret = cmp_files(iw1, iw2);
307 CU_ASSERT_FALSE(ret);
308 fclose(iw1);
309 fclose(iw2);
310 }
311
main()312 int main() {
313 CU_pSuite pSuite = NULL;
314
315 /* Initialize the CUnit test registry */
316 if (CUE_SUCCESS != CU_initialize_registry()) return CU_get_error();
317
318 /* Add a suite to the registry */
319 pSuite = CU_add_suite("iwkv_test4", init_suite, clean_suite);
320
321 if (NULL == pSuite) {
322 CU_cleanup_registry();
323 return CU_get_error();
324 }
325 /* Add the tests to the suite */
326 if (
327 (NULL == CU_add_test(pSuite, "iwkv_test4_1", iwkv_test4_1)) ||
328 (NULL == CU_add_test(pSuite, "iwkv_test4_2", iwkv_test4_2)) ||
329 (NULL == CU_add_test(pSuite, "iwkv_test4_3_v1", iwkv_test4_3_v1)) ||
330 (NULL == CU_add_test(pSuite, "iwkv_test4_3_v2", iwkv_test4_3_v2)) ||
331 (NULL == CU_add_test(pSuite, "iwkv_test4_4", iwkv_test4_4))
332 ) {
333 CU_cleanup_registry();
334 return CU_get_error();
335 }
336
337 /* Run all tests using the CUnit Basic interface */
338 CU_basic_set_mode(CU_BRM_VERBOSE);
339 CU_basic_run_tests();
340 int ret = CU_get_error() || CU_get_number_of_failures();
341 CU_cleanup_registry();
342 return ret;
343 }
344