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