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