xref: /freebsd/sys/contrib/openzfs/tests/unit/test_zap.c (revision d9497217456002b0ddad3cd319570d0b098daa29)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * http://www.illumos.org/license/CDDL.
11  */
12 
13 /*
14  * Copyright (c) 2026, TrueNAS.
15  */
16 
17 #include <stdbool.h>
18 
19 #include <sys/zap.h>
20 #include <sys/btree.h>
21 typedef struct spa spa_t;	/* forward decl for zap_impl.h */
22 #include <sys/zap_impl.h>
23 
24 #include "mock_dmu.h"
25 #include "unit.h"
26 
27 /* ========== */
28 
29 /*
30  * Normally defined and initialised in arc.c.  We define and initialise it
31  * ourselves here so this mock can be linked without arc.c.
32  */
33 uint64_t zfs_crc64_table[256];
34 
35 static void
mock_crc64_init(void)36 mock_crc64_init(void)
37 {
38 	for (int i = 0; i < 256; i++) {
39 		uint64_t ct = i;
40 		for (int j = 8; j > 0; j--)
41 			ct = (ct >> 1) ^ (-(ct & 1) & ZFS_CRC64_POLY);
42 		zfs_crc64_table[i] = ct;
43 	}
44 }
45 
46 /* Misc utility functions. */
47 
48 #define	rd64(ptr, off)	(*(uint64_t *)((const char *)(ptr) + (off)))
49 
50 /* ========== */
51 
52 /* ZAP-specific mocks and other test helpers. */
53 
54 /* Create a microzap backed by a mock dnode. */
55 static dnode_t *
mock_zap_create_microzap(void)56 mock_zap_create_microzap(void) {
57 	/*
58 	 * We use DMU_OTN_ZAP_DATA so that DMU_OT_BYTESWAP() returns
59 	 * DMU_BSWAP_ZAP without consulting dmu_ot[], which is not currently
60 	 * provided in the mock.
61 	 */
62 	mock_dnode_t *mdn = mock_dnode_create(512, DMU_OTN_ZAP_DATA);
63 	dnode_t *dn = (dnode_t *)mdn;
64 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
65 	mzap_create_impl(dn, 0, 0, tx);
66 	mock_tx_destroy((mock_dmu_tx_t *)tx);
67 	return (dn);
68 }
69 
70 /* Create a fatzap backed by a mock dnode. */
71 static dnode_t *
mock_zap_create_fatzap(void)72 mock_zap_create_fatzap(void)
73 {
74 	/*
75 	 * We can only create microzaps directly. They only take u64s as a
76 	 * value, so we add a u16 to trigger an upgrade to fatzap.
77 	 */
78 	dnode_t *dn = mock_zap_create_microzap();
79 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
80 	uint16_t upgrade = 0;
81 	zap_add_by_dnode(dn, "_upgrade", sizeof (uint16_t), 1, &upgrade, tx);
82 	zap_remove_by_dnode(dn, "_upgrade", tx);
83 	mock_tx_destroy((mock_dmu_tx_t *)tx);
84 	return (dn);
85 }
86 
87 static bool
mock_zap_is_microzap(dnode_t * dn)88 mock_zap_is_microzap(dnode_t *dn)
89 {
90 	/* check block 0 has a microzap header */
91 	const void *blk = mock_dnode_block_data((mock_dnode_t *)dn, 0);
92 	return (rd64(blk, 0) == ZBT_MICRO);
93 }
94 
95 static bool
mock_zap_is_fatzap(dnode_t * dn)96 mock_zap_is_fatzap(dnode_t *dn)
97 {
98 	/* check block 0 has a fatzap header */
99 	const void *blk = mock_dnode_block_data((mock_dnode_t *)dn, 0);
100 	return (rd64(blk, 0) == ZBT_HEADER && rd64(blk, 8) == ZAP_MAGIC);
101 }
102 
103 static void
mock_zap_destroy(dnode_t * dn)104 mock_zap_destroy(dnode_t *dn)
105 {
106 	mock_dnode_t *mdn = (mock_dnode_t *)dn;
107 	unit_eq(mock_dnode_refcount(mdn), 1);
108 	mock_dnode_destroy(mdn);
109 }
110 
111 /* Create a ZAP of the type named in the given test params. */
112 static dnode_t *
mock_zap_create_params(const MunitParameter params[],const char * key)113 mock_zap_create_params(const MunitParameter params[], const char *key) {
114 	const char *type = munit_parameters_get(params, key);
115 	if (type == NULL)
116 		munit_error("mock_zap_create_params: missing type param");
117 	else if (strcmp(type, "micro") == 0)
118 		return (mock_zap_create_microzap());
119 	else if (strcmp(type, "fat") == 0)
120 		return (mock_zap_create_fatzap());
121 	else
122 		munit_errorf("mock_zap_create_params: invalid type '%s'", type);
123 	__builtin_unreachable();
124 }
125 
126 /*
127  * Confirm the stored ZAP is of the type named in the given test params. This
128  * is useful for sanity checks within tests that a ZAP wasn't unexpectedly
129  * upgraded during the test.
130  */
131 static bool
mock_zap_is_params(dnode_t * dn,const MunitParameter params[],const char * key)132 mock_zap_is_params(dnode_t *dn, const MunitParameter params[],
133     const char *key)
134 {
135 	const char *type = munit_parameters_get(params, key);
136 	if (type == NULL)
137 		munit_error("mock_zap_is_params: missing type param");
138 	else if (strcmp(type, "micro") == 0)
139 		return (mock_zap_is_microzap(dn));
140 	else if (strcmp(type, "fat") == 0)
141 		return (mock_zap_is_fatzap(dn));
142 	else
143 		munit_errorf("mock_zap_is_params: invalid type '%s'", type);
144 	__builtin_unreachable();
145 }
146 
147 /* ========== */
148 
149 /*
150  * Sanity checks for mock ZAPs. Ensures that the mock_zap_create_* functions
151  * really do create the right kind of ZAPs, since many of the tests need to
152  * run against both kinds to confirm that they all work the same way.
153  */
154 static MunitResult
test_mock_microzap_sanity(const MunitParameter params[],void * data)155 test_mock_microzap_sanity(const MunitParameter params[], void *data)
156 {
157 	(void) params, (void) data;
158 
159 	dnode_t *dn = mock_zap_create_microzap();
160 	unit_true(mock_zap_is_microzap(dn));
161 	mock_zap_destroy(dn);
162 
163 	return (MUNIT_OK);
164 }
165 
166 static MunitResult
test_mock_fatzap_sanity(const MunitParameter params[],void * data)167 test_mock_fatzap_sanity(const MunitParameter params[], void *data)
168 {
169 	(void) params, (void) data;
170 
171 	dnode_t *dn = mock_zap_create_fatzap();
172 	unit_true(mock_zap_is_fatzap(dn));
173 	mock_zap_destroy(dn);
174 
175 	return (MUNIT_OK);
176 }
177 
178 /* ========== */
179 
180 /*
181  * A simple add, lookup and remove test. Confirms basic operation. These are
182  * tested together simply because all other tests rely on these primitives.
183  */
184 static MunitResult
test_zap_basic(const MunitParameter params[],void * data)185 test_zap_basic(const MunitParameter params[], void *data)
186 {
187 	(void) data;
188 
189 	dnode_t *dn = mock_zap_create_params(params, "type");
190 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
191 
192 	/* Insert a few entries. */
193 	uint64_t val42 = 42;
194 	uint64_t val99 = 99;
195 	uint64_t val0  = 0;
196 
197 	unit_ok(zap_add_by_dnode(dn, "hello",
198 	    sizeof (uint64_t), 1, &val42, tx));
199 	unit_ok(zap_add_by_dnode(dn, "world",
200 	    sizeof (uint64_t), 1, &val99, tx));
201 	unit_ok(zap_add_by_dnode(dn, "zero",
202 	    sizeof (uint64_t), 1, &val0, tx));
203 
204 	/* Lookup each entry. */
205 	uint64_t result = 0;
206 	unit_ok(zap_lookup_by_dnode(dn, "hello",
207 	    sizeof (uint64_t), 1, &result));
208 	unit_eq(result, 42);
209 
210 	unit_ok(zap_lookup_by_dnode(dn, "world",
211 	    sizeof (uint64_t), 1, &result));
212 	unit_eq(result, 99);
213 
214 	unit_ok(zap_lookup_by_dnode(dn, "zero",
215 	    sizeof (uint64_t), 1, &result));
216 	unit_eq(result, 0);
217 
218 	/* Non-existent key should return ENOENT. */
219 	unit_err(zap_lookup_by_dnode(dn, "nope",
220 	    sizeof (uint64_t), 1, &result), ENOENT);
221 
222 	/* Removing an entry should make it impossible to look up. */
223 	unit_ok(zap_remove_by_dnode(dn, "world", tx));
224 	unit_err(zap_lookup_by_dnode(dn, "world",
225 	    sizeof (uint64_t), 1, &result), ENOENT);
226 
227 	mock_tx_destroy((mock_dmu_tx_t *)tx);
228 	unit_true(mock_zap_is_params(dn, params, "type"));
229 	mock_zap_destroy(dn);
230 
231 	return (MUNIT_OK);
232 }
233 
234 /* ========== */
235 
236 /*
237  * "Core" ZAP API tests. Covers the most basic functionality upon which which
238  * everything else is built.
239  *
240  * Note that to avoid microzap upgrade here, we only short keys and
241  * single-uint64 values.
242  */
243 
244 /* zap_add: add new items. */
245 static MunitResult
test_zap_add(const MunitParameter params[],void * data)246 test_zap_add(const MunitParameter params[], void *data)
247 {
248 	(void) data;
249 
250 	dnode_t *dn = mock_zap_create_params(params, "type");
251 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
252 
253 	/* A key added can be found by that name. */
254 	uint64_t va = 1, var = 0;
255 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &va, tx));
256 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &var));
257 	unit_eq(var, 1);
258 
259 	/* Another key added can be found by that name. */
260 	uint64_t vb = 2, vbr = 0;
261 	unit_ok(zap_add_by_dnode(dn, "b", sizeof (uint64_t), 1, &vb, tx));
262 	unit_ok(zap_lookup_by_dnode(dn, "b", sizeof (uint64_t), 1, &vbr));
263 	unit_eq(vbr, 2);
264 
265 	/* The first key is still findable with the right value. */
266 	var = 0;
267 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &var));
268 	unit_eq(var, 1);
269 
270 	/* Adding the key again fails. */
271 	unit_err(zap_add_by_dnode(dn, "a",
272 	    sizeof (uint64_t), 1, &va, tx), EEXIST);
273 
274 	/* Adding the key with a different value still fails. */
275 	va = 2;
276 	unit_err(zap_add_by_dnode(dn, "a",
277 	    sizeof (uint64_t), 1, &va, tx), EEXIST);
278 
279 	/* And is still findable with the original value. */
280 	var = 0;
281 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &var));
282 	unit_eq(var, 1);
283 
284 	mock_tx_destroy((mock_dmu_tx_t *)tx);
285 	unit_true(mock_zap_is_params(dn, params, "type"));
286 	mock_zap_destroy(dn);
287 
288 	return (MUNIT_OK);
289 }
290 
291 /* zap_update: add new or replace existing items. */
292 static MunitResult
test_zap_update(const MunitParameter params[],void * data)293 test_zap_update(const MunitParameter params[], void *data)
294 {
295 	(void) data;
296 
297 	dnode_t *dn = mock_zap_create_params(params, "type");
298 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
299 
300 	/* Update on a non-existent key inserts it. */
301 	uint64_t va = 1, var = 0;
302 	unit_ok(zap_update_by_dnode(dn, "a", sizeof (uint64_t), 1, &va, tx));
303 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &var));
304 	unit_eq(var, 1);
305 
306 	/* Update on an existing key replaces it without error. */
307 	va = 2;
308 	unit_ok(zap_update_by_dnode(dn, "a", sizeof (uint64_t), 1, &va, tx));
309 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &var));
310 	unit_eq(var, 2);
311 
312 	/* Count should still be 1 (no duplicate was created). */
313 	uint64_t count = 0;
314 	unit_ok(zap_count_by_dnode(dn, &count));
315 	unit_eq(count, 1);
316 
317 	mock_tx_destroy((mock_dmu_tx_t *)tx);
318 	unit_true(mock_zap_is_params(dn, params, "type"));
319 	mock_zap_destroy(dn);
320 
321 	return (MUNIT_OK);
322 }
323 
324 /* zap_remove: remove existing items. */
325 static MunitResult
test_zap_remove(const MunitParameter params[],void * data)326 test_zap_remove(const MunitParameter params[], void *data)
327 {
328 	(void) data;
329 
330 	dnode_t *dn = mock_zap_create_params(params, "type");
331 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
332 
333 	/* Removing a non-existing key fails. */
334 	unit_err(zap_remove_by_dnode(dn, "a", tx), ENOENT);
335 
336 	/* Adding two keys. */
337 	uint64_t va = 1, vb = 2;
338 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &va, tx));
339 	unit_ok(zap_add_by_dnode(dn, "b", sizeof (uint64_t), 1, &vb, tx));
340 
341 	/* Remove an existing key succeeds. */
342 	unit_ok(zap_remove_by_dnode(dn, "a", tx));
343 
344 	/* After removing, looking up removed key fails. */
345 	uint64_t var = 0;
346 	unit_err(
347 	    zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &var), ENOENT);
348 
349 	/* Looking up the other key succeeds, and has the correct value. */
350 	uint64_t vbr = 0;
351 	unit_ok(zap_lookup_by_dnode(dn, "b", sizeof (uint64_t), 1, &vbr));
352 	unit_eq(vbr, 2);
353 
354 	mock_tx_destroy((mock_dmu_tx_t *)tx);
355 	unit_true(mock_zap_is_params(dn, params, "type"));
356 	mock_zap_destroy(dn);
357 
358 	return (MUNIT_OK);
359 }
360 
361 /* zap_count: number of entries, typically without lookup or traversal. */
362 static MunitResult
test_zap_count(const MunitParameter params[],void * data)363 test_zap_count(const MunitParameter params[], void *data)
364 {
365 	(void) data;
366 
367 	dnode_t *dn = mock_zap_create_params(params, "type");
368 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
369 
370 	/* A new ZAP has zero entries. */
371 	uint64_t count = 0;
372 	unit_ok(zap_count_by_dnode(dn, &count));
373 	unit_eq(count, 0);
374 
375 	/* Adding two keys bumps the count to 2. */
376 	uint64_t v = 1;
377 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &v, tx));
378 	unit_ok(zap_add_by_dnode(dn, "b", sizeof (uint64_t), 1, &v, tx));
379 	unit_ok(zap_count_by_dnode(dn, &count));
380 	unit_eq(count, 2);
381 
382 	/* Removing a key reduces the count. */
383 	unit_ok(zap_remove_by_dnode(dn, "a", tx));
384 	unit_ok(zap_count_by_dnode(dn, &count));
385 	unit_eq(count, 1);
386 
387 	mock_tx_destroy((mock_dmu_tx_t *)tx);
388 	unit_true(mock_zap_is_params(dn, params, "type"));
389 	mock_zap_destroy(dn);
390 
391 	return (MUNIT_OK);
392 }
393 
394 /* zap_contains: existence check without reading the value. */
395 static MunitResult
test_zap_contains(const MunitParameter params[],void * data)396 test_zap_contains(const MunitParameter params[], void *data)
397 {
398 	(void) data;
399 
400 	dnode_t *dn = mock_zap_create_params(params, "type");
401 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
402 
403 	uint64_t v = 1;
404 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &v, tx));
405 	unit_ok(zap_contains_by_dnode(dn, "a"));
406 	unit_err(zap_contains_by_dnode(dn, "b"), ENOENT);
407 
408 	mock_tx_destroy((mock_dmu_tx_t *)tx);
409 	unit_true(mock_zap_is_params(dn, params, "type"));
410 	mock_zap_destroy(dn);
411 
412 	return (MUNIT_OK);
413 }
414 
415 /* zap_length: item metadata without reading the value. */
416 static MunitResult
test_zap_length(const MunitParameter params[],void * data)417 test_zap_length(const MunitParameter params[], void *data)
418 {
419 	(void) data;
420 
421 	dnode_t *dn = mock_zap_create_params(params, "type");
422 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
423 
424 	/* uint64: integer_size=8, num_integers=1. */
425 	uint64_t v = 42;
426 	unit_ok(zap_add_by_dnode(dn, "u64",
427 	    sizeof (uint64_t), 1, &v, tx));
428 
429 	uint64_t isz = 0, nint = 0;
430 	unit_ok(zap_length_by_dnode(dn, "u64", &isz, &nint));
431 	unit_eq(isz, 8);
432 	unit_eq(nint, 1);
433 
434 	/* Missing key returns ENOENT. */
435 	unit_err(zap_length_by_dnode(dn, "nope", &isz, &nint), ENOENT);
436 
437 	/* Either output pointer may be NULL. */
438 	isz = 0; nint = 0;
439 	unit_ok(zap_length_by_dnode(dn, "u64", NULL, &nint));
440 	unit_ok(zap_length_by_dnode(dn, "u64", &isz, NULL));
441 	unit_eq(isz, 8);
442 	unit_eq(nint, 1);
443 
444 	mock_tx_destroy((mock_dmu_tx_t *)tx);
445 	unit_true(mock_zap_is_params(dn, params, "type"));
446 	mock_zap_destroy(dn);
447 
448 	return (MUNIT_OK);
449 }
450 
451 /* zap_increment: add integer value to existing integer */
452 static MunitResult
test_zap_increment(const MunitParameter params[],void * data)453 test_zap_increment(const MunitParameter params[], void *data)
454 {
455 	(void) data;
456 
457 	dnode_t *dn = mock_zap_create_params(params, "type");
458 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
459 
460 	uint64_t r = 0;
461 
462 	/* Increment a missing key creates it with that value. */
463 	unit_ok(zap_increment_by_dnode(dn, "a", 5, tx));
464 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &r));
465 	unit_eq(r, 5);
466 
467 	/* Further increments accumulate. */
468 	unit_ok(zap_increment_by_dnode(dn, "a", 3, tx));
469 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &r));
470 	unit_eq(r, 8);
471 
472 	/* Decrement works. */
473 	unit_ok(zap_increment_by_dnode(dn, "a", -2, tx));
474 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &r));
475 	unit_eq(r, 6);
476 
477 	/* Zero delta leaves it unchanged. */
478 	r = 0;
479 	unit_ok(zap_increment_by_dnode(dn, "a", 0, tx));
480 	unit_ok(zap_lookup_by_dnode(dn, "a", sizeof (uint64_t), 1, &r));
481 	unit_eq(r, 6);
482 
483 	/* Decrementing to zero removes the entry. */
484 	unit_ok(zap_increment_by_dnode(dn, "a", -6, tx));
485 	unit_err(zap_lookup_by_dnode(dn, "a",
486 	    sizeof (uint64_t), 1, &r), ENOENT);
487 
488 	/* Delta of zero is a no-op even for a missing key. */
489 	unit_ok(zap_increment_by_dnode(dn, "a", 0, tx));
490 	unit_err(zap_lookup_by_dnode(dn, "a",
491 	    sizeof (uint64_t), 1, &r), ENOENT);
492 
493 	mock_tx_destroy((mock_dmu_tx_t *)tx);
494 	unit_true(mock_zap_is_params(dn, params, "type"));
495 	mock_zap_destroy(dn);
496 
497 	return (MUNIT_OK);
498 }
499 
500 /* ========== */
501 
502 /*
503  * zap_add_int/zap_remove_int/zap_lookup_int: single uint64_t value,
504  * stringified to form the key.
505  */
506 static MunitResult
test_zap_int(const MunitParameter params[],void * data)507 test_zap_int(const MunitParameter params[], void *data)
508 {
509 	(void) data;
510 
511 	dnode_t *dn = mock_zap_create_params(params, "type");
512 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
513 
514 	/* Add some ints. */
515 	unit_ok(zap_add_int_by_dnode(dn, 5, tx));
516 	unit_ok(zap_add_int_by_dnode(dn, 17, tx));
517 
518 	/* Confirm they're there. */
519 	unit_ok(zap_lookup_int_by_dnode(dn, 17));
520 	unit_ok(zap_lookup_int_by_dnode(dn, 5));
521 
522 	/* But not something we didn't add. */
523 	unit_err(zap_lookup_int_by_dnode(dn, 23), ENOENT);
524 
525 	/* Adding something that already exists fails. */
526 	unit_err(zap_add_int_by_dnode(dn, 17, tx), EEXIST);
527 
528 	/* Removing it works, and then it can't be found. */
529 	unit_ok(zap_remove_int_by_dnode(dn, 17, tx));
530 	unit_err(zap_lookup_int_by_dnode(dn, 17), ENOENT);
531 
532 	/* Add it can be added back. */
533 	unit_ok(zap_add_int_by_dnode(dn, 17, tx));
534 	unit_ok(zap_lookup_int_by_dnode(dn, 17));
535 
536 	mock_tx_destroy((mock_dmu_tx_t *)tx);
537 	unit_true(mock_zap_is_params(dn, params, "type"));
538 	mock_zap_destroy(dn);
539 
540 	return (MUNIT_OK);
541 }
542 
543 /* zap_*_int_key: like zap_*_int, but with separate value. */
544 static MunitResult
test_zap_int_keys(const MunitParameter params[],void * data)545 test_zap_int_keys(const MunitParameter params[], void *data)
546 {
547 	(void) data;
548 
549 	dnode_t *dn = mock_zap_create_params(params, "type");
550 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
551 
552 	/* Add some ints. */
553 	unit_ok(zap_add_int_key_by_dnode(dn, 5, 17, tx));
554 	unit_ok(zap_add_int_key_by_dnode(dn, 23, 35, tx));
555 
556 	/* Confirm they're there. */
557 	uint64_t r = 0;
558 	unit_ok(zap_lookup_int_key_by_dnode(dn, 5, &r));
559 	unit_eq(r, 17);
560 	unit_ok(zap_lookup_int_key_by_dnode(dn, 23, &r));
561 	unit_eq(r, 35);
562 
563 	/* But not something we didn't add. */
564 	unit_err(zap_lookup_int_key_by_dnode(dn, 79, &r), ENOENT);
565 
566 	/* Adding something that already exists fails. */
567 	unit_err(zap_add_int_key_by_dnode(dn, 23, 51, tx), EEXIST);
568 
569 	/* Updating it works though. */
570 	unit_ok(zap_update_int_key_by_dnode(dn, 23, 51, tx));
571 
572 	/* Removing it works, and then it can't be found. */
573 	unit_ok(zap_remove_int_by_dnode(dn, 23, tx));
574 	unit_err(zap_lookup_int_key_by_dnode(dn, 23, &r), ENOENT);
575 
576 	/* Add it can be added back. */
577 	unit_ok(zap_add_int_key_by_dnode(dn, 23, 11, tx));
578 	unit_ok(zap_lookup_int_key_by_dnode(dn, 23, &r));
579 	unit_eq(r, 11);
580 
581 	mock_tx_destroy((mock_dmu_tx_t *)tx);
582 	unit_true(mock_zap_is_params(dn, params, "type"));
583 	mock_zap_destroy(dn);
584 
585 	return (MUNIT_OK);
586 }
587 
588 /* ========== */
589 
590 /*
591  * Separate stats tests for each ZAP type, since they are about internals and
592  * so can and will produce different results.
593  */
594 
595 static MunitResult
test_microzap_stats(const MunitParameter params[],void * data)596 test_microzap_stats(const MunitParameter params[], void *data)
597 {
598 	(void) params; (void) data;
599 
600 	dnode_t *dn = mock_zap_create_microzap();
601 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
602 
603 	zap_stats_t zs;
604 	uint64_t v = 1;
605 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &v, tx));
606 	unit_ok(zap_add_by_dnode(dn, "b", sizeof (uint64_t), 1, &v, tx));
607 	unit_ok(zap_get_stats_by_dnode(dn, &zs));
608 
609 	/* We added two entries. */
610 	unit_eq(zs.zs_num_entries, 2);
611 
612 	/* MicroZAP is always a single block. */
613 	unit_eq(zs.zs_num_blocks, 1);
614 
615 	/* Blocksize matches what we passed to mock_dnode_create(). */
616 	unit_eq(zs.zs_blocksize, 512);
617 
618 	mock_tx_destroy((mock_dmu_tx_t *)tx);
619 	unit_true(mock_zap_is_microzap(dn));
620 	mock_zap_destroy(dn);
621 
622 	return (MUNIT_OK);
623 }
624 
625 static MunitResult
test_fatzap_stats(const MunitParameter params[],void * data)626 test_fatzap_stats(const MunitParameter params[], void *data)
627 {
628 	(void) params; (void) data;
629 
630 	dnode_t *dn = mock_zap_create_fatzap();
631 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
632 
633 	zap_stats_t zs;
634 	uint64_t v = 1;
635 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &v, tx));
636 	unit_ok(zap_add_by_dnode(dn, "b", sizeof (uint64_t), 1, &v, tx));
637 	unit_ok(zap_get_stats_by_dnode(dn, &zs));
638 
639 	/* We added two entries. */
640 	unit_eq(zs.zs_num_entries, 2);
641 
642 	/* One header block, one leaf block. */
643 	unit_eq(zs.zs_num_blocks, 2);
644 
645 	/* FatZAP block size set by tuneable. */
646 	unit_eq(zs.zs_blocksize, 1 << fzap_default_block_shift);
647 
648 	mock_tx_destroy((mock_dmu_tx_t *)tx);
649 	unit_true(mock_zap_is_fatzap(dn));
650 	mock_zap_destroy(dn);
651 
652 	return (MUNIT_OK);
653 }
654 
655 /* ========== */
656 
657 /* Cursor tests. */
658 
659 /*
660  * Basic cursor test. Add a bunch of keys+values to a ZAP, read them back
661  * via cursor, confirm they're all there and nothing else is.
662  */
663 static MunitResult
test_cursor(const MunitParameter params[],void * data)664 test_cursor(const MunitParameter params[], void *data)
665 {
666 	(void) data;
667 
668 	dnode_t *dn = mock_zap_create_params(params, "type");
669 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
670 
671 	/* For each ASCII letter as key, add a unique value to the ZAP. */
672 	for (int i = 0; i < 26; i++) {
673 		char c = (char)i + 'a';
674 		char k[2] = { c, '\0' };
675 		uint64_t v = (uint64_t)c * 11;
676 		unit_ok(zap_add_by_dnode(dn, k, sizeof (uint64_t), 1, &v, tx));
677 	}
678 
679 	/* Sanity check; confirm they're all there by count. */
680 	uint64_t count = 0;
681 	unit_ok(zap_count_by_dnode(dn, &count));
682 	unit_eq(count, 26);
683 
684 	zap_cursor_t zc;
685 	zap_attribute_t *za = zap_attribute_alloc();
686 
687 	unit_ok(zap_cursor_init_by_dnode(&zc, dn));
688 
689 	/*
690 	 * Cursors don't guarantee an order, so we run over them them all,
691 	 * confirm the key matches the value, and then set a bit for each
692 	 * one we've seen. By the end, we should have seen them all.
693 	 */
694 	uint64_t seen = 0;
695 	for (int i = 0; i < 26; i++) {
696 		unit_ok(zap_cursor_retrieve(&zc, za));
697 
698 		/* Confirm attribute has the right details for the value. */
699 		unit_eq(za->za_integer_length, sizeof (uint64_t));
700 		unit_eq(za->za_num_integers, 1);
701 
702 		/*
703 		 * And the right key in za_name. Note that we don't check
704 		 * za_name_len, which is the length of a buffer that can
705 		 * definitely hold the key, not the key length itself.
706 		 */
707 		char c = za->za_name[0];
708 		unit_true(c >= 'a' && c <= 'z');
709 		unit_zero(za->za_name[1]);
710 
711 		/* Check the value in the attribute. */
712 		uint64_t v = (uint64_t)c * 11;
713 		unit_eq(za->za_first_integer, v);
714 
715 		/*
716 		 * Also do a direct lookup and confirm the value matches
717 		 * the value from the attribute.
718 		 */
719 		char k[2] = { c, '\0' };
720 		uint64_t result = 0;
721 		unit_ok(zap_lookup_by_dnode(dn, k,
722 		    sizeof (uint64_t), 1, &result));
723 		unit_eq(result, v);
724 
725 		/* This one is good, set the bit to remember this fact. */
726 		seen |= 1 << (c-'a');
727 
728 		zap_cursor_advance(&zc);
729 	}
730 
731 	/* There should be no more keys in the ZAP. */
732 	unit_err(zap_cursor_retrieve(&zc, za), ENOENT);
733 
734 	/* Bits 0-25 should be set if we've seen them all. */
735 	unit_eq(seen, (1 << 26) - 1);
736 
737 	zap_attribute_free(za);
738 	zap_cursor_fini(&zc);
739 
740 	mock_tx_destroy((mock_dmu_tx_t *)tx);
741 	unit_true(mock_zap_is_params(dn, params, "type"));
742 	mock_zap_destroy(dn);
743 
744 	return (MUNIT_OK);
745 }
746 
747 /*
748  * Cursor serialize test. Add a bunch of items, use the cursor to read half of
749  * them back, then serialize the cursor. Reload the cursor from the serialized
750  * state and confirm that we pick up where we left off. Then do it again to
751  * ensure it doesn't rely on any internal state.
752  */
753 static MunitResult
test_cursor_serialize(const MunitParameter params[],void * data)754 test_cursor_serialize(const MunitParameter params[], void *data)
755 {
756 	(void) data;
757 
758 	dnode_t *dn = mock_zap_create_params(params, "type");
759 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
760 
761 	/* For each ASCII letter as key, add a unique value to the ZAP. */
762 	for (int i = 0; i < 26; i++) {
763 		char c = (char)i + 'a';
764 		char k[2] = { c, '\0' };
765 		uint64_t v = (uint64_t)c * 11;
766 		unit_ok(zap_add_by_dnode(dn, k, sizeof (uint64_t), 1, &v, tx));
767 	}
768 
769 	/* Sanity check; confirm they're all there by count. */
770 	uint64_t count = 0;
771 	unit_ok(zap_count_by_dnode(dn, &count));
772 	unit_eq(count, 26);
773 
774 	/*
775 	 * Like test_cursor above, we'll walk over the ZAP and set bits
776 	 * for each key we see.
777 	 */
778 	zap_cursor_t zc;
779 	zap_attribute_t *za = zap_attribute_alloc();
780 	uint64_t seen = 0;
781 
782 	unit_ok(zap_cursor_init_by_dnode(&zc, dn));
783 	for (int i = 0; i < 13; i++) {
784 		unit_ok(zap_cursor_retrieve(&zc, za));
785 
786 		char c = za->za_name[0];
787 		unit_true(c >= 'a' && c <= 'z');
788 
789 		/* This one is good, set the bit to remember this fact. */
790 		seen |= 1 << (c-'a');
791 
792 		zap_cursor_advance(&zc);
793 	}
794 
795 	/* Serialise the and terminate the cursor. */
796 	uint64_t cookie = zap_cursor_serialize(&zc);
797 	zap_cursor_fini(&zc);
798 
799 	/*
800 	 * Record the bits we saw in the first iteration; we'll use this
801 	 * when we reload the cursor a second time below.
802 	 */
803 	uint64_t orig_seen = seen;
804 
805 	/* Reinitialise the cursor from the cookie. */
806 	unit_ok(zap_cursor_init_serialized_by_dnode(&zc, dn, cookie));
807 
808 	/* Loop over the remaining entries and track them. */
809 	for (int i = 0; i < 13; i++) {
810 		unit_ok(zap_cursor_retrieve(&zc, za));
811 
812 		char c = za->za_name[0];
813 		unit_true(c >= 'a' && c <= 'z');
814 
815 		/* This one is good, set the bit to remember this fact. */
816 		seen |= 1 << (c-'a');
817 
818 		zap_cursor_advance(&zc);
819 	}
820 
821 	/* There should be no more keys in the ZAP. */
822 	unit_err(zap_cursor_retrieve(&zc, za), ENOENT);
823 
824 	/* Bits 0-25 should be set if we've seen them all. */
825 	unit_eq(seen, (1 << 26) - 1);
826 
827 	/* Cursor done. */
828 	zap_cursor_fini(&zc);
829 
830 	/*
831 	 * Restore the seen state to before when we reinitialised the saved
832 	 * cursor.
833 	 */
834 	seen = orig_seen;
835 
836 	/*
837 	 * Do it all again a second time. This is making sure that the saved
838 	 * cursor is usable even after the its been "used".
839 	 */
840 	unit_ok(zap_cursor_init_serialized_by_dnode(&zc, dn, cookie));
841 	for (int i = 0; i < 13; i++) {
842 		unit_ok(zap_cursor_retrieve(&zc, za));
843 
844 		char c = za->za_name[0];
845 		unit_true(c >= 'a' && c <= 'z');
846 
847 		seen |= 1 << (c-'a');
848 
849 		zap_cursor_advance(&zc);
850 	}
851 
852 	unit_err(zap_cursor_retrieve(&zc, za), ENOENT);
853 	unit_eq(seen, (1 << 26) - 1);
854 
855 	zap_attribute_free(za);
856 	zap_cursor_fini(&zc);
857 
858 	mock_tx_destroy((mock_dmu_tx_t *)tx);
859 	unit_true(mock_zap_is_params(dn, params, "type"));
860 	mock_zap_destroy(dn);
861 
862 	return (MUNIT_OK);
863 }
864 
865 /*
866  * The following tests confirm that the cursor is properly cleaning up dnode
867  * holds taken (or not) across the lifetime of the cursor. The test is not
868  * about how or when it takes holds, only that the dnode refcount is the
869  * same before zap_cursor_init() as after zap_cursor_fini().
870  */
871 static MunitResult
test_cursor_release_unused(const MunitParameter params[],void * data)872 test_cursor_release_unused(const MunitParameter params[], void *data)
873 {
874 	(void) data;
875 
876 	dnode_t *dn = mock_zap_create_params(params, "type");
877 
878 	uint64_t refcount = mock_dnode_refcount((mock_dnode_t *)dn);
879 
880 	zap_cursor_t zc;
881 	unit_ok(zap_cursor_init_by_dnode(&zc, dn));
882 	zap_cursor_fini(&zc);
883 
884 	unit_eq(refcount, mock_dnode_refcount((mock_dnode_t *)dn));
885 
886 	unit_true(mock_zap_is_params(dn, params, "type"));
887 	mock_zap_destroy(dn);
888 
889 	return (MUNIT_OK);
890 }
891 
892 static MunitResult
test_cursor_release_advance(const MunitParameter params[],void * data)893 test_cursor_release_advance(const MunitParameter params[], void *data)
894 {
895 	(void) data;
896 
897 	dnode_t *dn = mock_zap_create_params(params, "type");
898 
899 	uint64_t refcount = mock_dnode_refcount((mock_dnode_t *)dn);
900 
901 	zap_cursor_t zc;
902 	unit_ok(zap_cursor_init_by_dnode(&zc, dn));
903 	zap_cursor_advance(&zc);
904 	zap_cursor_fini(&zc);
905 
906 	unit_eq(refcount, mock_dnode_refcount((mock_dnode_t *)dn));
907 
908 	unit_true(mock_zap_is_params(dn, params, "type"));
909 	mock_zap_destroy(dn);
910 
911 	return (MUNIT_OK);
912 }
913 
914 static MunitResult
test_cursor_release_empty(const MunitParameter params[],void * data)915 test_cursor_release_empty(const MunitParameter params[], void *data)
916 {
917 	(void) data;
918 
919 	dnode_t *dn = mock_zap_create_params(params, "type");
920 
921 	uint64_t refcount = mock_dnode_refcount((mock_dnode_t *)dn);
922 
923 	zap_cursor_t zc;
924 	zap_attribute_t *za = zap_attribute_alloc();
925 
926 	unit_ok(zap_cursor_init_by_dnode(&zc, dn));
927 	unit_err(zap_cursor_retrieve(&zc, za), ENOENT);
928 
929 	zap_attribute_free(za);
930 	zap_cursor_fini(&zc);
931 
932 	unit_eq(refcount, mock_dnode_refcount((mock_dnode_t *)dn));
933 
934 	unit_true(mock_zap_is_params(dn, params, "type"));
935 	mock_zap_destroy(dn);
936 
937 	return (MUNIT_OK);
938 }
939 
940 static MunitResult
test_cursor_release_one(const MunitParameter params[],void * data)941 test_cursor_release_one(const MunitParameter params[], void *data)
942 {
943 	(void) data;
944 
945 	dnode_t *dn = mock_zap_create_params(params, "type");
946 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
947 
948 	uint64_t v = 1;
949 	unit_ok(zap_add_by_dnode(dn, "a", sizeof (uint64_t), 1, &v, tx));
950 	unit_ok(zap_add_by_dnode(dn, "b", sizeof (uint64_t), 1, &v, tx));
951 
952 	uint64_t refcount = mock_dnode_refcount((mock_dnode_t *)dn);
953 
954 	zap_cursor_t zc;
955 	zap_attribute_t *za = zap_attribute_alloc();
956 
957 	unit_ok(zap_cursor_init_by_dnode(&zc, dn));
958 	unit_ok(zap_cursor_retrieve(&zc, za));
959 
960 	zap_attribute_free(za);
961 	zap_cursor_fini(&zc);
962 
963 	unit_eq(refcount, mock_dnode_refcount((mock_dnode_t *)dn));
964 
965 	mock_tx_destroy((mock_dmu_tx_t *)tx);
966 	unit_true(mock_zap_is_params(dn, params, "type"));
967 	mock_zap_destroy(dn);
968 
969 	return (MUNIT_OK);
970 }
971 
972 /* ========== */
973 
974 /* zap_value_search: find key with given uint64 value. */
975 static MunitResult
test_zap_value_search(const MunitParameter params[],void * data)976 test_zap_value_search(const MunitParameter params[], void *data)
977 {
978 	(void) data;
979 
980 	dnode_t *dn = mock_zap_create_params(params, "type");
981 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
982 
983 	/* Add some items. */
984 	uint64_t v1 = 1, v2 = 2, v3 = 3;
985 	unit_ok(zap_add_by_dnode(dn, "one", sizeof (uint64_t), 1, &v1, tx));
986 	unit_ok(zap_add_by_dnode(dn, "two", sizeof (uint64_t), 1, &v2, tx));
987 	unit_ok(zap_add_by_dnode(dn, "three", sizeof (uint64_t), 1, &v3, tx));
988 
989 	char name[ZAP_MAXNAMELEN];
990 
991 	/* Find one of them. */
992 	unit_ok(zap_value_search_by_dnode(dn, 2, 0, name, sizeof (name)));
993 	unit_str_eq(name, "two");
994 
995 	/* Nonexistent value. */
996 	unit_err(zap_value_search_by_dnode(dn, 10, 0,
997 	    name, sizeof (name)), ENOENT);
998 
999 	/* Buffer too small for the key. */
1000 	unit_err(zap_value_search_by_dnode(dn, 3, 0, name, 2), ENAMETOOLONG);
1001 
1002 	mock_tx_destroy((mock_dmu_tx_t *)tx);
1003 	unit_true(mock_zap_is_params(dn, params, "type"));
1004 	mock_zap_destroy(dn);
1005 
1006 	return (MUNIT_OK);
1007 }
1008 
1009 /* zap_value_search: value masks */
1010 static MunitResult
test_zap_value_search_mask(const MunitParameter params[],void * data)1011 test_zap_value_search_mask(const MunitParameter params[], void *data)
1012 {
1013 	(void) data;
1014 
1015 	dnode_t *dn = mock_zap_create_params(params, "type");
1016 	dmu_tx_t *tx = (dmu_tx_t *)mock_tx_create();
1017 
1018 	/*
1019 	 * Add a set of values. These all have the same bottom 16 bits, with
1020 	 * different upper 48 bits, segmented so we can mask them in different
1021 	 * and interesting ways.
1022 	 */
1023 	uint64_t v1 = 0x000000000000f0f0ull;
1024 	uint64_t v2 = 0x00000000fffff0f0ull;
1025 	uint64_t v3 = 0x0000ffff0000f0f0ull;
1026 	uint64_t v4 = 0xffff00000000f0f0ull;
1027 
1028 	/*
1029 	 * Generate four random keys. We do this because zap_value_search() is
1030 	 * implemented with a simple cursor walk, so will always return the
1031 	 * first match in hash order, which with fixed keys will always give
1032 	 * exactly the same results. Using random keys ensures the test values
1033 	 * are encountered in different orders between test runs, giving us
1034 	 * better coverage when there are multiple matches.
1035 	 */
1036 
1037 	char k1[9], k2[9], k3[9], k4[9];
1038 	unit_rand_str(k1, sizeof (k1));
1039 	unit_rand_str(k2, sizeof (k2));
1040 	unit_rand_str(k3, sizeof (k3));
1041 	unit_rand_str(k4, sizeof (k4));
1042 
1043 	unit_ok(zap_add_by_dnode(dn, k1, sizeof (uint64_t), 1, &v1, tx));
1044 	unit_ok(zap_add_by_dnode(dn, k2, sizeof (uint64_t), 1, &v2, tx));
1045 	unit_ok(zap_add_by_dnode(dn, k3, sizeof (uint64_t), 1, &v3, tx));
1046 	unit_ok(zap_add_by_dnode(dn, k4, sizeof (uint64_t), 1, &v4, tx));
1047 
1048 	char name[ZAP_MAXNAMELEN];
1049 
1050 	/* 0 mask is equivalent to all bits set in mask ie exact match. */
1051 	unit_ok(zap_value_search_by_dnode(dn,
1052 	    0xf0f0, 0, name, sizeof (name)));
1053 	unit_str_eq(name, k1);
1054 	unit_ok(zap_value_search_by_dnode(dn,
1055 	    0xf0f0, 0xffffffffffffffffull, name, sizeof (name)));
1056 	unit_str_eq(name, k1);
1057 
1058 	/* Low 16 bits could match any. */
1059 	unit_ok(zap_value_search_by_dnode(dn,
1060 	    0xf0f0, 0xffff, name, sizeof (name)));
1061 
1062 	/* Low 32 bits, 3/1 matches. */
1063 	unit_ok(zap_value_search_by_dnode(dn,
1064 	    0x0000f0f0, 0xffffffff, name, sizeof (name)));
1065 	unit_true(strcmp(name, k1) == 0 || strcmp(name, k3) == 0 ||
1066 	    strcmp(name, k4) == 0);
1067 	unit_ok(zap_value_search_by_dnode(dn,
1068 	    0xfffff0f0, 0xffffffff, name, sizeof (name)));
1069 	unit_str_eq(name, k2);
1070 
1071 	/* Low 48 bits, 2/1/1 matches */
1072 	unit_ok(zap_value_search_by_dnode(dn,
1073 	    0x00000000f0f0ull, 0xffffffffffffull, name, sizeof (name)));
1074 	unit_true(strcmp(name, k1) == 0 || strcmp(name, k4) == 0);
1075 	unit_ok(zap_value_search_by_dnode(dn,
1076 	    0x0000fffff0f0ull, 0xffffffffffffull, name, sizeof (name)));
1077 	unit_str_eq(name, k2);
1078 	unit_ok(zap_value_search_by_dnode(dn,
1079 	    0xffff0000f0f0ull, 0xffffffffffffull, name, sizeof (name)));
1080 	unit_str_eq(name, k3);
1081 
1082 	/* Value doesn't exist directly, but matches when mask applied. */
1083 	unit_ok(zap_value_search_by_dnode(dn,
1084 	    0xffffffff, 0xffff0000, name, sizeof (name)));
1085 	unit_str_eq(name, k2);
1086 
1087 	mock_tx_destroy((mock_dmu_tx_t *)tx);
1088 	unit_true(mock_zap_is_params(dn, params, "type"));
1089 	mock_zap_destroy(dn);
1090 
1091 	return (MUNIT_OK);
1092 }
1093 
1094 /* ========== */
1095 
1096 /* Test suite definition and boilerplate. */
1097 
1098 #define	UNIT_PARAM_ZAP_TYPES(p)	\
1099 	UNIT_PARAM((p), "micro", "fat")
1100 
1101 static const MunitParameterEnum zap_type_params[] = {
1102 	UNIT_PARAM_ZAP_TYPES("type"),
1103 	{ 0 },
1104 };
1105 
1106 #define	UNIT_TEST_ZAP_TYPES(name, func)	\
1107 	UNIT_TEST(name, func, zap_type_params)
1108 
1109 static const MunitTest zap_tests[] = {
1110 	UNIT_TEST("mock_microzap_sanity",	test_mock_microzap_sanity),
1111 	UNIT_TEST("mock_fatzap_sanity",		test_mock_fatzap_sanity),
1112 
1113 	UNIT_TEST_ZAP_TYPES("zap_basic",	test_zap_basic),
1114 
1115 	UNIT_TEST_ZAP_TYPES("zap_add",		test_zap_add),
1116 	UNIT_TEST_ZAP_TYPES("zap_update",	test_zap_update),
1117 	UNIT_TEST_ZAP_TYPES("zap_remove",	test_zap_remove),
1118 	UNIT_TEST_ZAP_TYPES("zap_count",	test_zap_count),
1119 	UNIT_TEST_ZAP_TYPES("zap_contains",	test_zap_contains),
1120 	UNIT_TEST_ZAP_TYPES("zap_length",	test_zap_length),
1121 
1122 	UNIT_TEST_ZAP_TYPES("zap_increment",	test_zap_increment),
1123 
1124 	UNIT_TEST_ZAP_TYPES("zap_int",		test_zap_int),
1125 	UNIT_TEST_ZAP_TYPES("zap_int_keys",	test_zap_int_keys),
1126 
1127 	UNIT_TEST("microzap_stats",		test_microzap_stats),
1128 	UNIT_TEST("fatzap_stats",		test_fatzap_stats),
1129 
1130 	UNIT_TEST_ZAP_TYPES("cursor",		test_cursor),
1131 	UNIT_TEST_ZAP_TYPES("cursor_serialize",	test_cursor_serialize),
1132 
1133 	UNIT_TEST_ZAP_TYPES(
1134 	    "cursor_release_unused",	test_cursor_release_unused),
1135 	UNIT_TEST_ZAP_TYPES(
1136 	    "cursor_release_advance",	test_cursor_release_advance),
1137 	UNIT_TEST_ZAP_TYPES(
1138 	    "cursor_release_empty",	test_cursor_release_empty),
1139 	UNIT_TEST_ZAP_TYPES(
1140 	    "cursor_release_one",	test_cursor_release_one),
1141 
1142 	UNIT_TEST_ZAP_TYPES(
1143 	    "zap_value_search",		test_zap_value_search),
1144 	UNIT_TEST_ZAP_TYPES(
1145 	    "zap_value_search_mask",	test_zap_value_search_mask),
1146 
1147 	{ 0 },
1148 };
1149 
1150 static const MunitSuite zap_test_suite = {
1151 	"zap.",
1152 	zap_tests,
1153 	NULL,
1154 	1,
1155 	MUNIT_SUITE_OPTION_NONE,
1156 };
1157 
1158 int
main(int argc,char ** argv)1159 main(int argc, char **argv)
1160 {
1161 	mock_crc64_init();
1162 
1163 	zap_init();
1164 
1165 	int rc = munit_suite_main(&zap_test_suite, NULL, argc, argv);
1166 
1167 	zap_fini();
1168 
1169 	return (rc);
1170 }
1171