1*dfc11533SChris Williamson /*
2*dfc11533SChris Williamson  * CDDL HEADER START
3*dfc11533SChris Williamson  *
4*dfc11533SChris Williamson  * This file and its contents are supplied under the terms of the
5*dfc11533SChris Williamson  * Common Development and Distribution License ("CDDL"), version 1.0.
6*dfc11533SChris Williamson  * You may only use this file in accordance with the terms of version
7*dfc11533SChris Williamson  * 1.0 of the CDDL.
8*dfc11533SChris Williamson  *
9*dfc11533SChris Williamson  * A full copy of the text of the CDDL should have accompanied this
10*dfc11533SChris Williamson  * source.  A copy of the CDDL is also available via the Internet at
11*dfc11533SChris Williamson  * http://www.illumos.org/license/CDDL.
12*dfc11533SChris Williamson  *
13*dfc11533SChris Williamson  * CDDL HEADER END
14*dfc11533SChris Williamson  */
15*dfc11533SChris Williamson 
16*dfc11533SChris Williamson /*
17*dfc11533SChris Williamson  * Copyright (c) 2016 by Delphix. All rights reserved.
18*dfc11533SChris Williamson  */
19*dfc11533SChris Williamson 
20*dfc11533SChris Williamson #include <stdio.h>
21*dfc11533SChris Williamson #include <stdlib.h>
22*dfc11533SChris Williamson #include <string.h>
23*dfc11533SChris Williamson #include <strings.h>
24*dfc11533SChris Williamson #include <libzfs_core.h>
25*dfc11533SChris Williamson #include <sys/nvpair.h>
26*dfc11533SChris Williamson 
27*dfc11533SChris Williamson nvlist_t *nvl;
28*dfc11533SChris Williamson const char *pool;
29*dfc11533SChris Williamson boolean_t unexpected_failures;
30*dfc11533SChris Williamson 
31*dfc11533SChris Williamson static boolean_t
nvlist_equal(nvlist_t * nvla,nvlist_t * nvlb)32*dfc11533SChris Williamson nvlist_equal(nvlist_t *nvla, nvlist_t *nvlb)
33*dfc11533SChris Williamson {
34*dfc11533SChris Williamson 	if (fnvlist_num_pairs(nvla) != fnvlist_num_pairs(nvlb))
35*dfc11533SChris Williamson 		return (B_FALSE);
36*dfc11533SChris Williamson 	/*
37*dfc11533SChris Williamson 	 * The nvlists have the same number of pairs and keys are unique, so
38*dfc11533SChris Williamson 	 * if every key in A is also in B and assigned to the same value, the
39*dfc11533SChris Williamson 	 * lists are identical.
40*dfc11533SChris Williamson 	 */
41*dfc11533SChris Williamson 	for (nvpair_t *pair = nvlist_next_nvpair(nvla, NULL);
42*dfc11533SChris Williamson 	    pair != NULL; pair = nvlist_next_nvpair(nvla, pair)) {
43*dfc11533SChris Williamson 		char *key = nvpair_name(pair);
44*dfc11533SChris Williamson 
45*dfc11533SChris Williamson 		if (!nvlist_exists(nvlb, key))
46*dfc11533SChris Williamson 			return (B_FALSE);
47*dfc11533SChris Williamson 
48*dfc11533SChris Williamson 		if (nvpair_type(pair) !=
49*dfc11533SChris Williamson 		    nvpair_type(fnvlist_lookup_nvpair(nvlb, key)))
50*dfc11533SChris Williamson 			return (B_FALSE);
51*dfc11533SChris Williamson 
52*dfc11533SChris Williamson 		switch (nvpair_type(pair)) {
53*dfc11533SChris Williamson 		case DATA_TYPE_BOOLEAN_VALUE:
54*dfc11533SChris Williamson 			if (fnvpair_value_boolean_value(pair) !=
55*dfc11533SChris Williamson 			    fnvlist_lookup_boolean_value(nvlb, key)) {
56*dfc11533SChris Williamson 				return (B_FALSE);
57*dfc11533SChris Williamson 			}
58*dfc11533SChris Williamson 			break;
59*dfc11533SChris Williamson 		case DATA_TYPE_STRING:
60*dfc11533SChris Williamson 			if (strcmp(fnvpair_value_string(pair),
61*dfc11533SChris Williamson 			    fnvlist_lookup_string(nvlb, key))) {
62*dfc11533SChris Williamson 				return (B_FALSE);
63*dfc11533SChris Williamson 			}
64*dfc11533SChris Williamson 			break;
65*dfc11533SChris Williamson 		case DATA_TYPE_INT64:
66*dfc11533SChris Williamson 			if (fnvpair_value_int64(pair) !=
67*dfc11533SChris Williamson 			    fnvlist_lookup_int64(nvlb, key)) {
68*dfc11533SChris Williamson 				return (B_FALSE);
69*dfc11533SChris Williamson 			}
70*dfc11533SChris Williamson 			break;
71*dfc11533SChris Williamson 		case DATA_TYPE_NVLIST:
72*dfc11533SChris Williamson 			if (!nvlist_equal(fnvpair_value_nvlist(pair),
73*dfc11533SChris Williamson 			    fnvlist_lookup_nvlist(nvlb, key))) {
74*dfc11533SChris Williamson 				return (B_FALSE);
75*dfc11533SChris Williamson 			}
76*dfc11533SChris Williamson 			break;
77*dfc11533SChris Williamson 		default:
78*dfc11533SChris Williamson 			(void) printf("Unexpected type for nvlist_equal\n");
79*dfc11533SChris Williamson 			return (B_FALSE);
80*dfc11533SChris Williamson 		}
81*dfc11533SChris Williamson 	}
82*dfc11533SChris Williamson 	return (B_TRUE);
83*dfc11533SChris Williamson }
84*dfc11533SChris Williamson 
85*dfc11533SChris Williamson static void
test(const char * testname,boolean_t expect_success,boolean_t expect_match)86*dfc11533SChris Williamson test(const char *testname, boolean_t expect_success, boolean_t expect_match)
87*dfc11533SChris Williamson {
88*dfc11533SChris Williamson 	char *progstr = "input = ...; return {output=input}";
89*dfc11533SChris Williamson 
90*dfc11533SChris Williamson 	nvlist_t *outnvl;
91*dfc11533SChris Williamson 
92*dfc11533SChris Williamson 	(void) printf("\nrunning test '%s'; input:\n", testname);
93*dfc11533SChris Williamson 	dump_nvlist(nvl, 4);
94*dfc11533SChris Williamson 
95*dfc11533SChris Williamson 	int err = lzc_channel_program(pool, progstr,
96*dfc11533SChris Williamson 	    10 * 1000 * 1000, 10 * 1024 * 1024, nvl, &outnvl);
97*dfc11533SChris Williamson 
98*dfc11533SChris Williamson 	(void) printf("lzc_channel_program returned %u\n", err);
99*dfc11533SChris Williamson 	dump_nvlist(outnvl, 5);
100*dfc11533SChris Williamson 
101*dfc11533SChris Williamson 	if (err == 0 && expect_match) {
102*dfc11533SChris Williamson 		/*
103*dfc11533SChris Williamson 		 * Verify that outnvl is the same as input nvl, if we expect
104*dfc11533SChris Williamson 		 * them to be. The input and output will never match if the
105*dfc11533SChris Williamson 		 * input contains an array (since arrays are converted to lua
106*dfc11533SChris Williamson 		 * tables), so this is only asserted for some test cases.
107*dfc11533SChris Williamson 		 */
108*dfc11533SChris Williamson 		nvlist_t *real_outnvl = fnvlist_lookup_nvlist(outnvl, "return");
109*dfc11533SChris Williamson 		real_outnvl = fnvlist_lookup_nvlist(real_outnvl, "output");
110*dfc11533SChris Williamson 		if (!nvlist_equal(nvl, real_outnvl)) {
111*dfc11533SChris Williamson 			unexpected_failures = B_TRUE;
112*dfc11533SChris Williamson 			(void) printf("unexpected input/output mismatch for "
113*dfc11533SChris Williamson 			    "case: %s\n", testname);
114*dfc11533SChris Williamson 		}
115*dfc11533SChris Williamson 	}
116*dfc11533SChris Williamson 	if (err != 0 && expect_success) {
117*dfc11533SChris Williamson 		unexpected_failures = B_TRUE;
118*dfc11533SChris Williamson 		(void) printf("unexpected FAIL of case: %s\n", testname);
119*dfc11533SChris Williamson 	}
120*dfc11533SChris Williamson 
121*dfc11533SChris Williamson 	fnvlist_free(nvl);
122*dfc11533SChris Williamson 	nvl = fnvlist_alloc();
123*dfc11533SChris Williamson }
124*dfc11533SChris Williamson 
125*dfc11533SChris Williamson static void
run_tests(void)126*dfc11533SChris Williamson run_tests(void)
127*dfc11533SChris Williamson {
128*dfc11533SChris Williamson 	const char *key = "key";
129*dfc11533SChris Williamson 
130*dfc11533SChris Williamson 	/* Note: maximum nvlist key length is 32KB */
131*dfc11533SChris Williamson 	int len = 1024 * 31;
132*dfc11533SChris Williamson 	char *bigstring = malloc(len);
133*dfc11533SChris Williamson 	for (int i = 0; i < len; i++)
134*dfc11533SChris Williamson 		bigstring[i] = 'a' + i % 26;
135*dfc11533SChris Williamson 	bigstring[len - 1] = '\0';
136*dfc11533SChris Williamson 
137*dfc11533SChris Williamson 	nvl = fnvlist_alloc();
138*dfc11533SChris Williamson 
139*dfc11533SChris Williamson 	fnvlist_add_boolean(nvl, key);
140*dfc11533SChris Williamson 	test("boolean", B_TRUE, B_FALSE);
141*dfc11533SChris Williamson 
142*dfc11533SChris Williamson 	fnvlist_add_boolean_value(nvl, key, B_TRUE);
143*dfc11533SChris Williamson 	test("boolean_value", B_FALSE, B_FALSE);
144*dfc11533SChris Williamson 
145*dfc11533SChris Williamson 	fnvlist_add_byte(nvl, key, 1);
146*dfc11533SChris Williamson 	test("byte", B_FALSE, B_FALSE);
147*dfc11533SChris Williamson 
148*dfc11533SChris Williamson 	fnvlist_add_int8(nvl, key, 1);
149*dfc11533SChris Williamson 	test("int8", B_FALSE, B_FALSE);
150*dfc11533SChris Williamson 
151*dfc11533SChris Williamson 	fnvlist_add_uint8(nvl, key, 1);
152*dfc11533SChris Williamson 	test("uint8", B_FALSE, B_FALSE);
153*dfc11533SChris Williamson 
154*dfc11533SChris Williamson 	fnvlist_add_int16(nvl, key, 1);
155*dfc11533SChris Williamson 	test("int16", B_FALSE, B_FALSE);
156*dfc11533SChris Williamson 
157*dfc11533SChris Williamson 	fnvlist_add_uint16(nvl, key, 1);
158*dfc11533SChris Williamson 	test("uint16", B_FALSE, B_FALSE);
159*dfc11533SChris Williamson 
160*dfc11533SChris Williamson 	fnvlist_add_int32(nvl, key, 1);
161*dfc11533SChris Williamson 	test("int32", B_FALSE, B_FALSE);
162*dfc11533SChris Williamson 
163*dfc11533SChris Williamson 	fnvlist_add_uint32(nvl, key, 1);
164*dfc11533SChris Williamson 	test("uint32", B_FALSE, B_FALSE);
165*dfc11533SChris Williamson 
166*dfc11533SChris Williamson 	fnvlist_add_int64(nvl, key, 1);
167*dfc11533SChris Williamson 	test("int64", B_TRUE, B_TRUE);
168*dfc11533SChris Williamson 
169*dfc11533SChris Williamson 	fnvlist_add_uint64(nvl, key, 1);
170*dfc11533SChris Williamson 	test("uint64", B_FALSE, B_FALSE);
171*dfc11533SChris Williamson 
172*dfc11533SChris Williamson 	fnvlist_add_string(nvl, key, "1");
173*dfc11533SChris Williamson 	test("string", B_TRUE, B_TRUE);
174*dfc11533SChris Williamson 
175*dfc11533SChris Williamson 
176*dfc11533SChris Williamson 	{
177*dfc11533SChris Williamson 		nvlist_t *val = fnvlist_alloc();
178*dfc11533SChris Williamson 		fnvlist_add_string(val, "subkey", "subvalue");
179*dfc11533SChris Williamson 		fnvlist_add_nvlist(nvl, key, val);
180*dfc11533SChris Williamson 		fnvlist_free(val);
181*dfc11533SChris Williamson 		test("nvlist", B_TRUE, B_TRUE);
182*dfc11533SChris Williamson 	}
183*dfc11533SChris Williamson 	{
184*dfc11533SChris Williamson 		boolean_t val[2] = { B_FALSE, B_TRUE };
185*dfc11533SChris Williamson 		fnvlist_add_boolean_array(nvl, key, val, 2);
186*dfc11533SChris Williamson 		test("boolean_array", B_FALSE, B_FALSE);
187*dfc11533SChris Williamson 	}
188*dfc11533SChris Williamson 	{
189*dfc11533SChris Williamson 		uchar_t val[2] = { 0, 1 };
190*dfc11533SChris Williamson 		fnvlist_add_byte_array(nvl, key, val, 2);
191*dfc11533SChris Williamson 		test("byte_array", B_FALSE, B_FALSE);
192*dfc11533SChris Williamson 	}
193*dfc11533SChris Williamson 	{
194*dfc11533SChris Williamson 		int8_t val[2] = { 0, 1 };
195*dfc11533SChris Williamson 		fnvlist_add_int8_array(nvl, key, val, 2);
196*dfc11533SChris Williamson 		test("int8_array", B_FALSE, B_FALSE);
197*dfc11533SChris Williamson 	}
198*dfc11533SChris Williamson 	{
199*dfc11533SChris Williamson 		uint8_t val[2] = { 0, 1 };
200*dfc11533SChris Williamson 		fnvlist_add_uint8_array(nvl, key, val, 2);
201*dfc11533SChris Williamson 		test("uint8_array", B_FALSE, B_FALSE);
202*dfc11533SChris Williamson 	}
203*dfc11533SChris Williamson 	{
204*dfc11533SChris Williamson 		int16_t val[2] = { 0, 1 };
205*dfc11533SChris Williamson 		fnvlist_add_int16_array(nvl, key, val, 2);
206*dfc11533SChris Williamson 		test("int16_array", B_FALSE, B_FALSE);
207*dfc11533SChris Williamson 	}
208*dfc11533SChris Williamson 	{
209*dfc11533SChris Williamson 		uint16_t val[2] = { 0, 1 };
210*dfc11533SChris Williamson 		fnvlist_add_uint16_array(nvl, key, val, 2);
211*dfc11533SChris Williamson 		test("uint16_array", B_FALSE, B_FALSE);
212*dfc11533SChris Williamson 	}
213*dfc11533SChris Williamson 	{
214*dfc11533SChris Williamson 		int32_t val[2] = { 0, 1 };
215*dfc11533SChris Williamson 		fnvlist_add_int32_array(nvl, key, val, 2);
216*dfc11533SChris Williamson 		test("int32_array", B_FALSE, B_FALSE);
217*dfc11533SChris Williamson 	}
218*dfc11533SChris Williamson 	{
219*dfc11533SChris Williamson 		uint32_t val[2] = { 0, 1 };
220*dfc11533SChris Williamson 		fnvlist_add_uint32_array(nvl, key, val, 2);
221*dfc11533SChris Williamson 		test("uint32_array", B_FALSE, B_FALSE);
222*dfc11533SChris Williamson 	}
223*dfc11533SChris Williamson 	{
224*dfc11533SChris Williamson 		int64_t val[2] = { 0, 1 };
225*dfc11533SChris Williamson 		fnvlist_add_int64_array(nvl, key, val, 2);
226*dfc11533SChris Williamson 		test("int64_array", B_TRUE, B_FALSE);
227*dfc11533SChris Williamson 	}
228*dfc11533SChris Williamson 	{
229*dfc11533SChris Williamson 		uint64_t val[2] = { 0, 1 };
230*dfc11533SChris Williamson 		fnvlist_add_uint64_array(nvl, key, val, 2);
231*dfc11533SChris Williamson 		test("uint64_array", B_FALSE, B_FALSE);
232*dfc11533SChris Williamson 	}
233*dfc11533SChris Williamson 	{
234*dfc11533SChris Williamson 		char *const val[2] = { "0", "1" };
235*dfc11533SChris Williamson 		fnvlist_add_string_array(nvl, key, val, 2);
236*dfc11533SChris Williamson 		test("string_array", B_TRUE, B_FALSE);
237*dfc11533SChris Williamson 	}
238*dfc11533SChris Williamson 	{
239*dfc11533SChris Williamson 		nvlist_t *val[2];
240*dfc11533SChris Williamson 		val[0] = fnvlist_alloc();
241*dfc11533SChris Williamson 		fnvlist_add_string(val[0], "subkey", "subvalue");
242*dfc11533SChris Williamson 		val[1] = fnvlist_alloc();
243*dfc11533SChris Williamson 		fnvlist_add_string(val[1], "subkey2", "subvalue2");
244*dfc11533SChris Williamson 		fnvlist_add_nvlist_array(nvl, key, val, 2);
245*dfc11533SChris Williamson 		fnvlist_free(val[0]);
246*dfc11533SChris Williamson 		fnvlist_free(val[1]);
247*dfc11533SChris Williamson 		test("nvlist_array", B_FALSE, B_FALSE);
248*dfc11533SChris Williamson 	}
249*dfc11533SChris Williamson 	{
250*dfc11533SChris Williamson 		fnvlist_add_string(nvl, bigstring, "1");
251*dfc11533SChris Williamson 		test("large_key", B_TRUE, B_TRUE);
252*dfc11533SChris Williamson 	}
253*dfc11533SChris Williamson 	{
254*dfc11533SChris Williamson 		fnvlist_add_string(nvl, key, bigstring);
255*dfc11533SChris Williamson 		test("large_value", B_TRUE, B_TRUE);
256*dfc11533SChris Williamson 	}
257*dfc11533SChris Williamson 	{
258*dfc11533SChris Williamson 		for (int i = 0; i < 1024; i++) {
259*dfc11533SChris Williamson 			char buf[32];
260*dfc11533SChris Williamson 			(void) snprintf(buf, sizeof (buf), "key-%u", i);
261*dfc11533SChris Williamson 			fnvlist_add_int64(nvl, buf, i);
262*dfc11533SChris Williamson 		}
263*dfc11533SChris Williamson 		test("many_keys", B_TRUE, B_TRUE);
264*dfc11533SChris Williamson 	}
265*dfc11533SChris Williamson 	{
266*dfc11533SChris Williamson 		for (int i = 0; i < 10; i++) {
267*dfc11533SChris Williamson 			nvlist_t *newval = fnvlist_alloc();
268*dfc11533SChris Williamson 			fnvlist_add_nvlist(newval, "key", nvl);
269*dfc11533SChris Williamson 			fnvlist_free(nvl);
270*dfc11533SChris Williamson 			nvl = newval;
271*dfc11533SChris Williamson 		}
272*dfc11533SChris Williamson 		test("deeply_nested_pos", B_TRUE, B_TRUE);
273*dfc11533SChris Williamson 	}
274*dfc11533SChris Williamson 	{
275*dfc11533SChris Williamson 		for (int i = 0; i < 90; i++) {
276*dfc11533SChris Williamson 			nvlist_t *newval = fnvlist_alloc();
277*dfc11533SChris Williamson 			fnvlist_add_nvlist(newval, "key", nvl);
278*dfc11533SChris Williamson 			fnvlist_free(nvl);
279*dfc11533SChris Williamson 			nvl = newval;
280*dfc11533SChris Williamson 		}
281*dfc11533SChris Williamson 		test("deeply_nested_neg", B_FALSE, B_FALSE);
282*dfc11533SChris Williamson 	}
283*dfc11533SChris Williamson 
284*dfc11533SChris Williamson 	free(bigstring);
285*dfc11533SChris Williamson 	fnvlist_free(nvl);
286*dfc11533SChris Williamson }
287*dfc11533SChris Williamson 
288*dfc11533SChris Williamson int
main(int argc,const char * argv[])289*dfc11533SChris Williamson main(int argc, const char *argv[])
290*dfc11533SChris Williamson {
291*dfc11533SChris Williamson 	(void) libzfs_core_init();
292*dfc11533SChris Williamson 
293*dfc11533SChris Williamson 	if (argc != 2) {
294*dfc11533SChris Williamson 		(void) printf("usage: %s <pool>\n",
295*dfc11533SChris Williamson 		    argv[0]);
296*dfc11533SChris Williamson 		exit(2);
297*dfc11533SChris Williamson 	}
298*dfc11533SChris Williamson 	pool = argv[1];
299*dfc11533SChris Williamson 
300*dfc11533SChris Williamson 	run_tests();
301*dfc11533SChris Williamson 
302*dfc11533SChris Williamson 	libzfs_core_fini();
303*dfc11533SChris Williamson 	return (unexpected_failures);
304*dfc11533SChris Williamson }
305