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