]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/property_test.c
Fix a test ordering issue.
[thirdparty/openssl.git] / test / property_test.c
1 /*
2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
3 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
4 *
5 * Licensed under the Apache License 2.0 (the "License"). You may not use
6 * this file except in compliance with the License. You can obtain a copy
7 * in the file LICENSE in the source distribution or at
8 * https://www.openssl.org/source/license.html
9 */
10
11 #include <stdarg.h>
12 #include "testutil.h"
13 #include "internal/nelem.h"
14 #include "internal/property.h"
15 #include "../crypto/property/property_lcl.h"
16
17 static int add_property_names(const char *n, ...)
18 {
19 va_list args;
20 int res = 1;
21
22 va_start(args, n);
23 do {
24 if (!TEST_int_ne(ossl_property_name(n, 1), 0))
25 res = 0;
26 } while ((n = va_arg(args, const char *)) != NULL);
27 va_end(args);
28 return res;
29 }
30
31 static int test_property_string(void)
32 {
33 OSSL_METHOD_STORE *store;
34 int res = 0;
35 OSSL_PROPERTY_IDX i, j;
36
37 if (TEST_ptr(store = ossl_method_store_new())
38 && TEST_int_eq(ossl_property_name("fnord", 0), 0)
39 && TEST_int_ne(ossl_property_name("fnord", 1), 0)
40 && TEST_int_ne(ossl_property_name("name", 1), 0)
41 /* Property value checks */
42 && TEST_int_eq(ossl_property_value("fnord", 0), 0)
43 && TEST_int_ne(i = ossl_property_value("no", 0), 0)
44 && TEST_int_ne(j = ossl_property_value("yes", 0), 0)
45 && TEST_int_ne(i, j)
46 && TEST_int_eq(ossl_property_value("yes", 1), j)
47 && TEST_int_eq(ossl_property_value("no", 1), i)
48 && TEST_int_ne(i = ossl_property_value("illuminati", 1), 0)
49 && TEST_int_eq(j = ossl_property_value("fnord", 1), i + 1)
50 && TEST_int_eq(ossl_property_value("fnord", 1), j)
51 /* Check name and values are distinct */
52 && TEST_int_eq(ossl_property_value("cold", 0), 0)
53 && TEST_int_ne(ossl_property_name("fnord", 0),
54 ossl_property_value("fnord", 0)))
55 res = 1;
56 ossl_method_store_free(store);
57 return res;
58 }
59
60 static const struct {
61 const char *defn;
62 const char *query;
63 int e;
64 } parser_tests[] = {
65 { "", "sky=blue", 0 },
66 { "", "sky!=blue", 1 },
67 { "groan", "", 1 },
68 { "cold=yes", "cold=yes", 1 },
69 { "cold=yes", "cold", 1 },
70 { "cold=yes", "cold!=no", 1 },
71 { "groan", "groan=yes", 1 },
72 { "groan", "groan=no", 0 },
73 { "groan", "groan!=yes", 0 },
74 { "cold=no", "cold", 0 },
75 { "cold=no", "cold=no", 1 },
76 { "groan", "cold", 0 },
77 { "groan", "cold=no", 1 },
78 { "groan", "cold!=yes", 1 },
79 { "groan=blue", "groan=yellow", 0 },
80 { "groan=blue", "groan!=yellow", 1 },
81 { "today=monday, tomorrow=3", "today!=2", 1 },
82 { "today=monday, tomorrow=3", "today!='monday'", 0 },
83 { "today=monday, tomorrow=3", "tomorrow=3", 1 },
84 { "n=0x3", "n=3", 1 },
85 { "n=0x3", "n=-3", 0 },
86 { "n=0x33", "n=51", 1 },
87 { "n=033", "n=27", 1 },
88 { "n=0", "n=00", 1 },
89 { "n=0x0", "n=0", 1 },
90 };
91
92 static int test_property_parse(int n)
93 {
94 OSSL_METHOD_STORE *store;
95 OSSL_PROPERTY_LIST *p = NULL, *q = NULL;
96 int r = 0;
97
98 if (TEST_ptr(store = ossl_method_store_new())
99 && add_property_names("sky", "groan", "cold", "today", "tomorrow", "n",
100 NULL)
101 && TEST_ptr(p = ossl_parse_property(parser_tests[n].defn))
102 && TEST_ptr(q = ossl_parse_query(parser_tests[n].query))
103 && TEST_int_eq(ossl_property_match(q, p), parser_tests[n].e))
104 r = 1;
105 ossl_property_free(p);
106 ossl_property_free(q);
107 ossl_method_store_free(store);
108 return r;
109 }
110
111 static const struct {
112 const char *q_global;
113 const char *q_local;
114 const char *prop;
115 } merge_tests[] = {
116 { "", "colour=blue", "colour=blue" },
117 { "colour=blue", "", "colour=blue" },
118 { "colour=red", "colour=blue", "colour=blue" },
119 { "clouds=pink, urn=red", "urn=blue, colour=green",
120 "urn=blue, colour=green, clouds=pink" },
121 { "pot=gold", "urn=blue", "pot=gold, urn=blue" },
122 { "night", "day", "day=yes, night=yes" },
123 { "day", "night", "day=yes, night=yes" },
124 { "", "", "" },
125 /*
126 * The following four leave 'day' unspecified in the query, and will match
127 * any definition
128 */
129 { "day=yes", "-day", "day=no" },
130 { "day=yes", "-day", "day=yes" },
131 { "day=yes", "-day", "day=arglebargle" },
132 { "day=yes", "-day", "pot=sesquioxidizing" },
133 { "day, night", "-night, day", "day=yes, night=no" },
134 { "-day", "day=yes", "day=yes" },
135 };
136
137 static int test_property_merge(int n)
138 {
139 OSSL_METHOD_STORE *store;
140 OSSL_PROPERTY_LIST *q_global = NULL, *q_local = NULL;
141 OSSL_PROPERTY_LIST *q_combined = NULL, *prop = NULL;
142 int r = 0;
143
144 if (TEST_ptr(store = ossl_method_store_new())
145 && add_property_names("colour", "urn", "clouds", "pot", "day", "night",
146 NULL)
147 && TEST_ptr(prop = ossl_parse_property(merge_tests[n].prop))
148 && TEST_ptr(q_global = ossl_parse_query(merge_tests[n].q_global))
149 && TEST_ptr(q_local = ossl_parse_query(merge_tests[n].q_local))
150 && TEST_ptr(q_combined = ossl_property_merge(q_local, q_global))
151 && TEST_true(ossl_property_match(q_combined, prop)))
152 r = 1;
153 ossl_property_free(q_global);
154 ossl_property_free(q_local);
155 ossl_property_free(q_combined);
156 ossl_property_free(prop);
157 ossl_method_store_free(store);
158 return r;
159 }
160
161 static int test_property_defn_cache(void)
162 {
163 OSSL_METHOD_STORE *store;
164 OSSL_PROPERTY_LIST *red, *blue;
165 int r = 0;
166
167 if (TEST_ptr(store = ossl_method_store_new())
168 && add_property_names("red", "blue", NULL)
169 && TEST_ptr(red = ossl_parse_property("red"))
170 && TEST_ptr(blue = ossl_parse_property("blue"))
171 && TEST_ptr_ne(red, blue)
172 && TEST_true(ossl_prop_defn_set("red", red))
173 && TEST_true(ossl_prop_defn_set("blue", blue))
174 && TEST_ptr_eq(ossl_prop_defn_get("red"), red)
175 && TEST_ptr_eq(ossl_prop_defn_get("blue"), blue))
176 r = 1;
177 ossl_method_store_free(store);
178 return r;
179 }
180
181 static const struct {
182 const char *defn;
183 const char *query;
184 int e;
185 } definition_tests[] = {
186 { "alpha", "alpha=yes", 1 },
187 { "alpha=no", "alpha", 0 },
188 { "alpha=1", "alpha=1", 1 },
189 { "alpha=2", "alpha=1", 0 },
190 { "alpha", "omega", 0 }
191 };
192
193 static int test_definition_compares(int n)
194 {
195 OSSL_METHOD_STORE *store;
196 OSSL_PROPERTY_LIST *d = NULL, *q = NULL;
197 int r;
198
199 r = TEST_ptr(store = ossl_method_store_new())
200 && add_property_names("alpha", "omega", NULL)
201 && TEST_ptr(d = ossl_parse_property(definition_tests[n].defn))
202 && TEST_ptr(q = ossl_parse_query(definition_tests[n].query))
203 && TEST_int_eq(ossl_property_match(q, d), definition_tests[n].e);
204
205 ossl_property_free(d);
206 ossl_property_free(q);
207 ossl_method_store_free(store);
208 return r;
209 }
210
211 static int test_register_deregister(void)
212 {
213 static const struct {
214 int nid;
215 const char *prop;
216 char *impl;
217 } impls[] = {
218 { 6, "position=1", "a" },
219 { 6, "position=2", "b" },
220 { 6, "position=3", "c" },
221 { 6, "position=4", "d" },
222 };
223 size_t i;
224 int ret = 0;
225 OSSL_METHOD_STORE *store;
226
227 if (!TEST_ptr(store = ossl_method_store_new())
228 || !add_property_names("position", NULL))
229 goto err;
230
231 for (i = 0; i < OSSL_NELEM(impls); i++)
232 if (!TEST_true(ossl_method_store_add(store, impls[i].nid, impls[i].prop,
233 impls[i].impl, NULL))) {
234 TEST_note("iteration %zd", i + 1);
235 goto err;
236 }
237
238 /* Deregister in a different order to registration */
239 for (i = 0; i < OSSL_NELEM(impls); i++) {
240 const size_t j = (1 + i * 3) % OSSL_NELEM(impls);
241 int nid = impls[j].nid;
242 void *impl = impls[j].impl;
243
244 if (!TEST_true(ossl_method_store_remove(store, nid, impl))
245 || !TEST_false(ossl_method_store_remove(store, nid, impl))) {
246 TEST_note("iteration %zd, position %zd", i + 1, j + 1);
247 goto err;
248 }
249 }
250
251 if (TEST_false(ossl_method_store_remove(store, impls[0].nid, impls[0].impl)))
252 ret = 1;
253 err:
254 ossl_method_store_free(store);
255 return ret;
256 }
257
258 static int test_property(void)
259 {
260 static const struct {
261 int nid;
262 const char *prop;
263 char *impl;
264 } impls[] = {
265 { 1, "fast=no, colour=green", "a" },
266 { 1, "fast, colour=blue", "b" },
267 { 1, "", "-" },
268 { 9, "sky=blue, furry", "c" },
269 { 3, NULL, "d" },
270 { 6, "sky.colour=blue, sky=green, old.data", "e" },
271 };
272 static struct {
273 int nid;
274 const char *prop;
275 char *expected;
276 } queries[] = {
277 { 1, "fast", "b" },
278 { 1, "fast=yes", "b" },
279 { 1, "fast=no, colour=green", "a" },
280 { 1, "colour=blue, fast", "b" },
281 { 1, "colour=blue", "b" },
282 { 9, "furry", "c" },
283 { 6, "sky.colour=blue", "e" },
284 { 6, "old.data", "e" },
285 { 9, "furry=yes, sky=blue", "c" },
286 { 1, "", "a" },
287 { 3, "", "d" },
288 };
289 OSSL_METHOD_STORE *store;
290 size_t i;
291 int ret = 0;
292 void *result;
293
294 if (!TEST_ptr(store = ossl_method_store_new())
295 || !add_property_names("fast", "colour", "sky", "furry", NULL))
296 goto err;
297
298 for (i = 0; i < OSSL_NELEM(impls); i++)
299 if (!TEST_true(ossl_method_store_add(store, impls[i].nid, impls[i].prop,
300 impls[i].impl, NULL))) {
301 TEST_note("iteration %zd", i + 1);
302 goto err;
303 }
304 for (i = 0; i < OSSL_NELEM(queries); i++) {
305 OSSL_PROPERTY_LIST *pq = NULL;
306
307 if (!TEST_true(ossl_property_read_lock(store))
308 || !TEST_true(ossl_method_store_fetch(store, queries[i].nid,
309 queries[i].prop, &result))
310 || !TEST_true(ossl_property_unlock(store))
311 || !TEST_str_eq((char *)result, queries[i].expected)) {
312 TEST_note("iteration %zd", i + 1);
313 ossl_property_free(pq);
314 goto err;
315 }
316 ossl_property_free(pq);
317 }
318 ret = 1;
319 err:
320 ossl_method_store_free(store);
321 return ret;
322 }
323
324 static int test_query_cache_stochastic(void)
325 {
326 const int max = 10000, tail = 10;
327 OSSL_METHOD_STORE *store;
328 int i, res = 0;
329 char buf[50];
330 void *result;
331 int errors = 0;
332 int v[10001];
333
334 if (!TEST_ptr(store = ossl_method_store_new())
335 || !add_property_names("n", NULL))
336 goto err;
337
338 for (i = 1; i <= max; i++) {
339 v[i] = 2 * i;
340 BIO_snprintf(buf, sizeof(buf), "n=%d\n", i);
341 if (!TEST_true(ossl_method_store_add(store, i, buf, "abc", NULL))
342 || !TEST_true(ossl_method_store_cache_set(store, i, buf, v + i))
343 || !TEST_true(ossl_method_store_cache_set(store, i, "n=1234",
344 "miss"))) {
345 TEST_note("iteration %d", i);
346 goto err;
347 }
348 }
349 for (i = 1; i <= max; i++) {
350 BIO_snprintf(buf, sizeof(buf), "n=%d\n", i);
351 if (!ossl_method_store_cache_get(store, i, buf, &result)
352 || result != v + i)
353 errors++;
354 }
355 /* There is a tiny probability that this will fail when it shouldn't */
356 res = TEST_int_gt(errors, tail) && TEST_int_lt(errors, max - tail);
357
358 err:
359 ossl_method_store_free(store);
360 return res;
361 }
362
363 int setup_tests(void)
364 {
365 ADD_TEST(test_property_string);
366 ADD_ALL_TESTS(test_property_parse, OSSL_NELEM(parser_tests));
367 ADD_ALL_TESTS(test_property_merge, OSSL_NELEM(merge_tests));
368 ADD_TEST(test_property_defn_cache);
369 ADD_ALL_TESTS(test_definition_compares, OSSL_NELEM(definition_tests));
370 ADD_TEST(test_register_deregister);
371 ADD_TEST(test_property);
372 ADD_TEST(test_query_cache_stochastic);
373 return 1;
374 }