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