1 /*
2  * Copyright (c) 2018 Laczen
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /** @file
8  *  @brief Settings functional test suite
9  *
10  */
11 
12 #include <zephyr.h>
13 #include <ztest.h>
14 #include <errno.h>
15 #include <settings/settings.h>
16 #include <logging/log.h>
17 LOG_MODULE_REGISTER(settings_basic_test);
18 
19 #if defined(CONFIG_SETTINGS_FCB) || defined(CONFIG_SETTINGS_NVS)
20 #include <storage/flash_map.h>
21 #endif
22 #if IS_ENABLED(CONFIG_SETTINGS_FS)
23 #include <fs/fs.h>
24 #include <fs/littlefs.h>
25 #endif
26 
27 /* The standard test expects a cleared flash area.  Make sure it has
28  * one.
29  */
test_clear_settings(void)30 static void test_clear_settings(void)
31 {
32 #if IS_ENABLED(CONFIG_SETTINGS_FCB) || IS_ENABLED(CONFIG_SETTINGS_NVS)
33 	const struct flash_area *fap;
34 	int rc = flash_area_open(FLASH_AREA_ID(storage), &fap);
35 
36 	if (rc == 0) {
37 		rc = flash_area_erase(fap, 0, fap->fa_size);
38 		flash_area_close(fap);
39 	}
40 	zassert_true(rc == 0, "clear settings failed");
41 #endif
42 #if IS_ENABLED(CONFIG_SETTINGS_FS)
43 	FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(cstorage);
44 
45 	/* mounting info */
46 	static struct fs_mount_t littlefs_mnt = {
47 	.type = FS_LITTLEFS,
48 	.fs_data = &cstorage,
49 	.storage_dev = (void *)FLASH_AREA_ID(storage),
50 	.mnt_point = "/ff"
51 };
52 
53 	int rc;
54 
55 	rc = fs_mount(&littlefs_mnt);
56 	zassert_true(rc == 0, "mounting littlefs [%d]\n", rc);
57 
58 	rc = fs_unlink(CONFIG_SETTINGS_FS_FILE);
59 	zassert_true(rc == 0 || rc == -ENOENT,
60 		     "can't delete config file%d\n", rc);
61 #endif
62 }
63 
64 /*
65  * Test the two support routines that settings provides:
66  *
67  *   settings_name_steq(name, key, next): compares the start of name with key
68  *   settings_name_next(name, next): returns the location of the first
69  *                                   separator
70  */
71 
test_support_rtn(void)72 static void test_support_rtn(void)
73 {
74 	const char test1[] = "bt/a/b/c/d";
75 	const char test2[] = "bt/a/b/c/d=";
76 	const char *next1, *next2;
77 	int rc;
78 
79 	/* complete match: return 1, next = NULL */
80 	rc = settings_name_steq(test1, "bt/a/b/c/d", &next1);
81 	zassert_true(rc == 1, "_steq comparison failure");
82 	zassert_is_null(next1, "_steq comparison next error");
83 	rc = settings_name_steq(test2, "bt/a/b/c/d", &next2);
84 	zassert_true(rc == 1, "_steq comparison failure");
85 	zassert_is_null(next2, "_steq comparison next error");
86 
87 	/* partial match: return 1, next <> NULL */
88 	rc = settings_name_steq(test1, "bt/a/b/c", &next1);
89 	zassert_true(rc == 1, "_steq comparison failure");
90 	zassert_not_null(next1, "_steq comparison next error");
91 	zassert_equal_ptr(next1, test1+9, "next points to wrong location");
92 	rc = settings_name_steq(test2, "bt/a/b/c", &next2);
93 	zassert_true(rc == 1, "_steq comparison failure");
94 	zassert_not_null(next2, "_steq comparison next error");
95 	zassert_equal_ptr(next2, test2+9, "next points to wrong location");
96 
97 	/* no match: return 0, next = NULL */
98 	rc = settings_name_steq(test1, "bta", &next1);
99 	zassert_true(rc == 0, "_steq comparison failure");
100 	zassert_is_null(next1, "_steq comparison next error");
101 	rc = settings_name_steq(test2, "bta", &next2);
102 	zassert_true(rc == 0, "_steq comparison failure");
103 	zassert_is_null(next2, "_steq comparison next error");
104 
105 	/* no match: return 0, next = NULL */
106 	rc = settings_name_steq(test1, "b", &next1);
107 	zassert_true(rc == 0, "_steq comparison failure");
108 	zassert_is_null(next1, "_steq comparison next error");
109 	rc = settings_name_steq(test2, "b", &next2);
110 	zassert_true(rc == 0, "_steq comparison failure");
111 	zassert_is_null(next2, "_steq comparison next error");
112 
113 	/* first separator: return 2, next <> NULL */
114 	rc = settings_name_next(test1, &next1);
115 	zassert_true(rc == 2, "_next wrong return value");
116 	zassert_not_null(next1, "_next wrong next");
117 	zassert_equal_ptr(next1, test1+3, "next points to wrong location");
118 	rc = settings_name_next(test2, &next2);
119 	zassert_true(rc == 2, "_next wrong return value");
120 	zassert_not_null(next2, "_next wrong next");
121 	zassert_equal_ptr(next2, test2+3, "next points to wrong location");
122 
123 	/* second separator: return 1, next <> NULL */
124 	rc = settings_name_next(next1, &next1);
125 	zassert_true(rc == 1, "_next wrong return value");
126 	zassert_not_null(next1, "_next wrong next");
127 	zassert_equal_ptr(next1, test1+5, "next points to wrong location");
128 	rc = settings_name_next(next2, &next2);
129 	zassert_true(rc == 1, "_next wrong return value");
130 	zassert_not_null(next2, "_next wrong next");
131 	zassert_equal_ptr(next2, test2+5, "next points to wrong location");
132 
133 	/* third separator: return 1, next <> NULL */
134 	rc = settings_name_next(next1, &next1);
135 	zassert_true(rc == 1, "_next wrong return value");
136 	zassert_not_null(next1, "_next wrong next");
137 	rc = settings_name_next(next2, &next2);
138 	zassert_true(rc == 1, "_next wrong return value");
139 	zassert_not_null(next2, "_next wrong next");
140 
141 	/* fourth separator: return 1, next <> NULL */
142 	rc = settings_name_next(next1, &next1);
143 	zassert_true(rc == 1, "_next wrong return value");
144 	zassert_not_null(next1, "_next wrong next");
145 	rc = settings_name_next(next2, &next2);
146 	zassert_true(rc == 1, "_next wrong return value");
147 	zassert_not_null(next2, "_next wrong next");
148 
149 	/* fifth separator: return 1, next == NULL */
150 	rc = settings_name_next(next1, &next1);
151 	zassert_true(rc == 1, "_next wrong return value");
152 	zassert_is_null(next1, "_next wrong next");
153 	rc = settings_name_next(next2, &next2);
154 	zassert_true(rc == 1, "_next wrong return value");
155 	zassert_is_null(next2, "_next wrong next");
156 
157 }
158 
159 struct stored_data {
160 	uint8_t val1;
161 	uint8_t val2;
162 	uint8_t val3;
163 	bool en1;
164 	bool en2;
165 	bool en3;
166 };
167 
168 struct stored_data data;
169 
val1_set(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg)170 int val1_set(const char *key, size_t len, settings_read_cb read_cb,
171 	     void *cb_arg)
172 {
173 	data.val1 = 1;
174 	return 0;
175 }
val1_commit(void)176 int val1_commit(void)
177 {
178 	data.en1 = true;
179 	return 0;
180 }
181 static struct settings_handler val1_settings = {
182 	.name = "ps",
183 	.h_set = val1_set,
184 	.h_commit = val1_commit,
185 };
186 
val2_set(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg)187 int val2_set(const char *key, size_t len, settings_read_cb read_cb,
188 	     void *cb_arg)
189 {
190 	data.val2 = 2;
191 	return 0;
192 }
val2_commit(void)193 int val2_commit(void)
194 {
195 	data.en2 = true;
196 	return 0;
197 }
198 static struct settings_handler val2_settings = {
199 	.name = "ps/ss/ss",
200 	.h_set = val2_set,
201 	.h_commit = val2_commit,
202 };
203 
val3_set(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg)204 int val3_set(const char *key, size_t len, settings_read_cb read_cb,
205 	     void *cb_arg)
206 {
207 	data.val3 = 3;
208 	return 0;
209 }
val3_commit(void)210 int val3_commit(void)
211 {
212 	data.en3 = true;
213 	return 0;
214 }
215 static struct settings_handler val3_settings = {
216 	.name = "ps/ss",
217 	.h_set = val3_set,
218 	.h_commit = val3_commit,
219 };
220 
221 /* helper routine to remove a handler from settings */
settings_deregister(struct settings_handler * handler)222 int settings_deregister(struct settings_handler *handler)
223 {
224 	extern sys_slist_t settings_handlers;
225 
226 	return sys_slist_find_and_remove(&settings_handlers, &handler->node);
227 }
228 
test_register_and_loading(void)229 static void test_register_and_loading(void)
230 {
231 	int rc, err;
232 	uint8_t val = 0;
233 
234 	rc = settings_subsys_init();
235 	zassert_true(rc == 0, "subsys init failed");
236 
237 
238 	settings_save_one("ps/ss/ss/val2", &val, sizeof(uint8_t));
239 
240 	memset(&data, 0, sizeof(struct stored_data));
241 
242 	rc = settings_register(&val1_settings);
243 	zassert_true(rc == 0, "register of val1 settings failed");
244 
245 	/* when we load settings now data.val1 should receive the value*/
246 	rc = settings_load();
247 	zassert_true(rc == 0, "settings_load failed");
248 	err = (data.val1 == 1) && (data.val2 == 0) && (data.val3 == 0);
249 	zassert_true(err, "wrong data value found");
250 	/* commit is only called for val1_settings */
251 	err = (data.en1) && (!data.en2) && (!data.en3);
252 	zassert_true(err, "wrong data enable found");
253 
254 	/* Next register should be ok */
255 	rc = settings_register(&val2_settings);
256 	zassert_true(rc == 0, "register of val2 settings failed");
257 
258 	/* Next register should fail (same name) */
259 	rc = settings_register(&val2_settings);
260 	zassert_true(rc == -EEXIST, "double register of val2 settings allowed");
261 
262 	memset(&data, 0, sizeof(struct stored_data));
263 	/* when we load settings now data.val2 should receive the value*/
264 	rc = settings_load();
265 	zassert_true(rc == 0, "settings_load failed");
266 	err = (data.val1 == 0) && (data.val2 == 2) && (data.val3 == 0);
267 	zassert_true(err, "wrong data value found");
268 	/* commit is called for val1_settings and val2_settings*/
269 	err = (data.en1) && (data.en2) && (!data.en3);
270 	zassert_true(err, "wrong data enable found");
271 
272 	settings_save_one("ps/ss/val3", &val, sizeof(uint8_t));
273 	memset(&data, 0, sizeof(struct stored_data));
274 	/* when we load settings now data.val2 and data.val1 should receive a
275 	 * value
276 	 */
277 	rc = settings_load();
278 	zassert_true(rc == 0, "settings_load failed");
279 	err = (data.val1 == 1) && (data.val2 == 2) && (data.val3 == 0);
280 	zassert_true(err, "wrong data value found");
281 	/* commit is called for val1_settings and val2_settings*/
282 	err = (data.en1) && (data.en2) && (!data.en3);
283 	zassert_true(err, "wrong data enable found");
284 
285 	/* val3 settings should be inserted in between val1_settings and
286 	 * val2_settings
287 	 */
288 	rc = settings_register(&val3_settings);
289 	zassert_true(rc == 0, "register of val3 settings failed");
290 	memset(&data, 0, sizeof(struct stored_data));
291 	/* when we load settings now data.val2 and data.val3 should receive a
292 	 * value
293 	 */
294 	rc = settings_load();
295 	zassert_true(rc == 0, "settings_load failed");
296 	err = (data.val1 == 0) && (data.val2 == 2) && (data.val3 == 3);
297 	zassert_true(err, "wrong data value found");
298 	/* commit is called for val1_settings, val2_settings and val3_settings
299 	 */
300 	err = (data.en1) && (data.en2) && (data.en3);
301 	zassert_true(err, "wrong data enable found");
302 
303 	settings_save_one("ps/val1", &val, sizeof(uint8_t));
304 	memset(&data, 0, sizeof(struct stored_data));
305 	/* when we load settings all data should receive a value loaded */
306 	rc = settings_load();
307 	zassert_true(rc == 0, "settings_load failed");
308 	err = (data.val1 == 1) && (data.val2 == 2) && (data.val3 == 3);
309 	zassert_true(err, "wrong data value found");
310 	/* commit is called for all settings*/
311 	err = (data.en1) && (data.en2) && (data.en3);
312 	zassert_true(err, "wrong data enable found");
313 
314 	memset(&data, 0, sizeof(struct stored_data));
315 	/* test subtree loading: subtree "ps/ss" data.val2 and data.val3 should
316 	 * receive a value
317 	 */
318 	rc = settings_load_subtree("ps/ss");
319 	zassert_true(rc == 0, "settings_load failed");
320 	err = (data.val1 == 0) && (data.val2 == 2) && (data.val3 == 3);
321 	zassert_true(err, "wrong data value found");
322 	/* commit is called for val2_settings and val3_settings */
323 	err = (!data.en1) && (data.en2) && (data.en3);
324 	zassert_true(err, "wrong data enable found");
325 
326 	memset(&data, 0, sizeof(struct stored_data));
327 	/* test subtree loading: subtree "ps/ss/ss" only data.val2 should
328 	 * receive a value
329 	 */
330 	rc = settings_load_subtree("ps/ss/ss");
331 	zassert_true(rc == 0, "settings_load failed");
332 	err = (data.val1 == 0) && (data.val2 == 2) && (data.val3 == 0);
333 	zassert_true(err, "wrong data value found");
334 	/* commit is called only for val2_settings */
335 	err = (!data.en1) && (data.en2) && (!data.en3);
336 	zassert_true(err, "wrong data enable found");
337 
338 	/* clean up by deregisterring settings_handler */
339 	rc = settings_deregister(&val1_settings);
340 	zassert_true(rc, "deregistering val1_settings failed");
341 
342 	rc = settings_deregister(&val2_settings);
343 	zassert_true(rc, "deregistering val1_settings failed");
344 
345 	rc = settings_deregister(&val3_settings);
346 	zassert_true(rc, "deregistering val1_settings failed");
347 }
348 
val123_set(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg)349 int val123_set(const char *key, size_t len,
350 	       settings_read_cb read_cb, void *cb_arg)
351 {
352 	int rc;
353 	uint8_t val;
354 
355 	zassert_equal(1, len, "Unexpected size");
356 
357 	rc = read_cb(cb_arg, &val, sizeof(val));
358 	zassert_equal(sizeof(val), rc, "read_cb failed");
359 
360 	if (!strcmp("1", key)) {
361 		data.val1 = val;
362 		data.en1 = true;
363 		return 0;
364 	}
365 	if (!strcmp("2", key)) {
366 		data.val2 = val;
367 		data.en2 = true;
368 		return 0;
369 	}
370 	if (!strcmp("3", key)) {
371 		data.val3 = val;
372 		data.en3 = true;
373 		return 0;
374 	}
375 
376 	zassert_unreachable("Unexpected key value: %s", key);
377 
378 	return 0;
379 }
380 
381 static struct settings_handler val123_settings = {
382 	.name = "val",
383 	.h_set = val123_set,
384 };
385 
386 unsigned int direct_load_cnt;
387 uint8_t val_directly_loaded;
388 
direct_loader(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)389 int direct_loader(
390 	const char *key,
391 	size_t len,
392 	settings_read_cb read_cb,
393 	void *cb_arg,
394 	void *param)
395 {
396 	int rc;
397 	uint8_t val;
398 
399 	zassert_equal(0x1234, (size_t)param, NULL);
400 
401 	zassert_equal(1, len, NULL);
402 	zassert_is_null(key, "Unexpected key: %s", key);
403 
404 
405 	zassert_not_null(cb_arg, NULL);
406 	rc = read_cb(cb_arg, &val, sizeof(val));
407 	zassert_equal(sizeof(val), rc, NULL);
408 
409 	val_directly_loaded = val;
410 	direct_load_cnt += 1;
411 	return 0;
412 }
413 
414 
test_direct_loading(void)415 static void test_direct_loading(void)
416 {
417 	int rc;
418 	uint8_t val;
419 
420 	val = 11;
421 	settings_save_one("val/1", &val, sizeof(uint8_t));
422 	val = 23;
423 	settings_save_one("val/2", &val, sizeof(uint8_t));
424 	val = 35;
425 	settings_save_one("val/3", &val, sizeof(uint8_t));
426 
427 	rc = settings_register(&val123_settings);
428 	zassert_true(rc == 0, NULL);
429 	memset(&data, 0, sizeof(data));
430 
431 	rc = settings_load();
432 	zassert_true(rc == 0, NULL);
433 
434 	zassert_equal(11, data.val1, NULL);
435 	zassert_equal(23, data.val2, NULL);
436 	zassert_equal(35, data.val3, NULL);
437 
438 	/* Load subtree */
439 	memset(&data, 0, sizeof(data));
440 
441 	rc = settings_load_subtree("val/2");
442 	zassert_true(rc == 0, NULL);
443 
444 	zassert_equal(0,  data.val1, NULL);
445 	zassert_equal(23, data.val2, NULL);
446 	zassert_equal(0,  data.val3, NULL);
447 
448 	/* Direct loading now */
449 	memset(&data, 0, sizeof(data));
450 	val_directly_loaded = 0;
451 	direct_load_cnt = 0;
452 	rc = settings_load_subtree_direct(
453 		"val/2",
454 		direct_loader,
455 		(void *)0x1234);
456 	zassert_true(rc == 0, NULL);
457 	zassert_equal(0, data.val1, NULL);
458 	zassert_equal(0, data.val2, NULL);
459 	zassert_equal(0, data.val3, NULL);
460 
461 	zassert_equal(1, direct_load_cnt, NULL);
462 	zassert_equal(23, val_directly_loaded, NULL);
463 }
464 
465 struct test_loading_data {
466 	const char *n;
467 	const char *v;
468 };
469 
470 /* Final data */
471 static const struct test_loading_data data_final[] = {
472 	{ .n = "val/1", .v = "final 1" },
473 	{ .n = "val/2", .v = "final 2" },
474 	{ .n = "val/3", .v = "final 3" },
475 	{ .n = "val/4", .v = "final 4" },
476 	{ .n = NULL }
477 };
478 
479 /* The counter of the callback called */
480 static unsigned int data_final_called[ARRAY_SIZE(data_final)];
481 
482 
filtered_loader(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg)483 static int filtered_loader(
484 	const char *key,
485 	size_t len,
486 	settings_read_cb read_cb,
487 	void *cb_arg)
488 {
489 	int rc;
490 	const char *next;
491 	char buf[32];
492 	const struct test_loading_data *ldata;
493 
494 	printk("-- Called: %s\n", key);
495 
496 	/* Searching for a element in an array */
497 	for (ldata = data_final; ldata->n; ldata += 1) {
498 		if (settings_name_steq(key, ldata->n, &next)) {
499 			break;
500 		}
501 	}
502 	zassert_not_null(ldata->n, "Unexpected data name: %s", key);
503 	zassert_is_null(next, NULL);
504 	zassert_equal(strlen(ldata->v) + 1, len, "e: \"%s\", a:\"%s\"", ldata->v, buf);
505 	zassert_true(len <= sizeof(buf), NULL);
506 
507 	rc = read_cb(cb_arg, buf, len);
508 	zassert_equal(len, rc, NULL);
509 
510 	zassert_false(strcmp(ldata->v, buf), "e: \"%s\", a:\"%s\"", ldata->v, buf);
511 
512 	/* Count an element that was properly loaded */
513 	data_final_called[ldata - data_final] += 1;
514 
515 	return 0;
516 }
517 
518 static struct settings_handler filtered_loader_settings = {
519 	.name = "filtered_test",
520 	.h_set = filtered_loader,
521 };
522 
523 
direct_filtered_loader(const char * key,size_t len,settings_read_cb read_cb,void * cb_arg,void * param)524 static int direct_filtered_loader(
525 	const char *key,
526 	size_t len,
527 	settings_read_cb read_cb,
528 	void *cb_arg,
529 	void *param)
530 {
531 	zassert_equal(0x3456, (size_t)param, NULL);
532 	return filtered_loader(key, len, read_cb, cb_arg);
533 }
534 
535 
test_direct_loading_filter(void)536 static void test_direct_loading_filter(void)
537 {
538 	int rc;
539 	const struct test_loading_data *ldata;
540 	const char *prefix = filtered_loader_settings.name;
541 	char buffer[48];
542 	size_t n;
543 
544 	/* Duplicated data */
545 	static const struct test_loading_data data_duplicates[] = {
546 		{ .n = "val/1", .v = "dup abc" },
547 		{ .n = "val/2", .v = "dup 123" },
548 		{ .n = "val/3", .v = "dup 11" },
549 		{ .n = "val/4", .v = "dup 34" },
550 		{ .n = "val/1", .v = "dup 56" },
551 		{ .n = "val/2", .v = "dup 7890" },
552 		{ .n = "val/4", .v = "dup niety" },
553 		{ .n = "val/3", .v = "dup er" },
554 		{ .n = "val/3", .v = "dup super" },
555 		{ .n = "val/3", .v = "dup xxx" },
556 		{ .n = NULL }
557 	};
558 
559 	/* Data that is going to be deleted */
560 	strcpy(buffer, prefix);
561 	strcat(buffer, "/to_delete");
562 	settings_save_one(buffer, "1", 2);
563 	(void) settings_delete(buffer);
564 
565 	/* Saving all the data */
566 	for (ldata = data_duplicates; ldata->n; ++ldata) {
567 		strcpy(buffer, prefix);
568 		strcat(buffer, "/");
569 		strcat(buffer, ldata->n);
570 		settings_save_one(buffer, ldata->v, strlen(ldata->v) + 1);
571 	}
572 	for (ldata = data_final; ldata->n; ++ldata) {
573 		strcpy(buffer, prefix);
574 		strcat(buffer, "/");
575 		strcat(buffer, ldata->n);
576 		settings_save_one(buffer, ldata->v, strlen(ldata->v) + 1);
577 	}
578 
579 
580 	memset(data_final_called, 0, sizeof(data_final_called));
581 
582 	rc = settings_load_subtree_direct(
583 		prefix,
584 		direct_filtered_loader,
585 		(void *)0x3456);
586 	zassert_equal(0, rc, NULL);
587 
588 	/* Check if all the data was called */
589 	for (n = 0; data_final[n].n; ++n) {
590 		zassert_equal(1, data_final_called[n],
591 			"Unexpected number of calls (%u) of (%s) element",
592 			n, data_final[n].n);
593 	}
594 
595 	rc = settings_register(&filtered_loader_settings);
596 	zassert_true(rc == 0, NULL);
597 
598 	rc = settings_load_subtree(prefix);
599 	zassert_equal(0, rc, NULL);
600 
601 	/* Check if all the data was called */
602 	for (n = 0; data_final[n].n; ++n) {
603 		zassert_equal(2, data_final_called[n],
604 			"Unexpected number of calls (%u) of (%s) element",
605 			n, data_final[n].n);
606 	}
607 }
608 
609 
test_main(void)610 void test_main(void)
611 {
612 	ztest_test_suite(settings_test_suite,
613 			 ztest_unit_test(test_clear_settings),
614 			 ztest_unit_test(test_support_rtn),
615 			 ztest_unit_test(test_register_and_loading),
616 			 ztest_unit_test(test_direct_loading),
617 			 ztest_unit_test(test_direct_loading_filter)
618 			);
619 
620 	ztest_run_test_suite(settings_test_suite);
621 }
622