1 /*
2 * Copyright (c) 2020 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Test logging to file system
10 *
11 */
12
13 #include <stdbool.h>
14 #include <stdlib.h>
15 #include <zephyr/kernel.h>
16 #include <zephyr/ztest.h>
17 #include <zephyr/fs/fs.h>
18 #include <zephyr/fff.h>
19 #include <zephyr/logging/log_backend.h>
20
21 #define DT_DRV_COMPAT zephyr_fstab_littlefs
22 #define TEST_AUTOMOUNT DT_PROP(DT_DRV_INST(0), automount)
23 #if !TEST_AUTOMOUNT
24 #include <zephyr/fs/littlefs.h>
25 #define PARTITION_NODE DT_NODELABEL(lfs1)
26 FS_FSTAB_DECLARE_ENTRY(PARTITION_NODE);
27 #endif
28
29 #define MAX_PATH_LEN (256 + 7)
30
31 static const char *log_prefix = CONFIG_LOG_BACKEND_FS_FILE_PREFIX;
32 static const struct log_backend *backend;
33
34 DEFINE_FFF_GLOBALS;
35 FAKE_VOID_FUNC(log_output_dropped_process, const struct log_output *, uint32_t);
36 FAKE_VALUE_FUNC(log_format_func_t, log_format_func_t_get, uint32_t);
37
38 int write_log_to_file(uint8_t *data, size_t length, void *ctx);
39
40
ZTEST(test_log_backend_fs,test_fs_nonexist)41 ZTEST(test_log_backend_fs, test_fs_nonexist)
42 {
43 #if TEST_AUTOMOUNT
44 ztest_test_skip();
45 #else
46 uint8_t to_log[] = "Log to left behind";
47 int rc;
48
49 rc = write_log_to_file(to_log, sizeof(to_log), NULL);
50 zassert_equal(rc, sizeof(to_log), "Unexpected rteval.");
51 struct fs_mount_t *mp = &FS_FSTAB_ENTRY(PARTITION_NODE);
52
53 rc = fs_mount(mp);
54 zassert_equal(rc, 0, "Can not mount FS.");
55 #endif
56 }
57
ZTEST(test_log_backend_fs,test_wipe_fs_logs)58 ZTEST(test_log_backend_fs, test_wipe_fs_logs)
59 {
60 int rc;
61 struct fs_dir_t dir;
62 struct fs_file_t file;
63 char fname[MAX_PATH_LEN];
64
65 fs_dir_t_init(&dir);
66 fs_file_t_init(&file);
67
68 rc = fs_opendir(&dir, CONFIG_LOG_BACKEND_FS_DIR);
69 if (rc) {
70 /* log directory might not exist jet */
71 return;
72 }
73
74 /* Iterate over logging directory. */
75 while (1) {
76 struct fs_dirent ent = { 0 };
77
78 rc = fs_readdir(&dir, &ent);
79 zassert_equal(rc, 0, "Can not read directory.");
80 if ((rc < 0) || (ent.name[0] == 0)) {
81 break;
82 }
83 if (ent.type == FS_DIR_ENTRY_FILE &&
84 strncmp(ent.name, log_prefix, strlen(log_prefix)) == 0) {
85 sprintf(fname, "%s/%s", CONFIG_LOG_BACKEND_FS_DIR,
86 ent.name);
87 rc = fs_unlink(fname);
88 zassert_equal(rc, 0, "Can not remove file %s.", fname);
89 TC_PRINT("removed: %s\n", fname);
90 }
91 }
92
93 (void)fs_closedir(&dir);
94 }
95
ZTEST(test_log_backend_fs,test_log_fs_file_content)96 ZTEST(test_log_backend_fs, test_log_fs_file_content)
97 {
98 int rc;
99 struct fs_file_t file;
100 char log_read[MAX_PATH_LEN];
101 uint8_t to_log[] = "Correct Log 1";
102 static char fname[MAX_PATH_LEN];
103
104 fs_file_t_init(&file);
105
106 rc = write_log_to_file(to_log, sizeof(to_log), NULL);
107 backend->api->notify(backend, LOG_BACKEND_EVT_PROCESS_THREAD_DONE, NULL);
108
109 sprintf(fname, "%s/%s0000", CONFIG_LOG_BACKEND_FS_DIR, log_prefix);
110
111 zassert_equal(fs_open(&file, fname, FS_O_READ), 0,
112 "Can not open log file.");
113
114 zassert_true(fs_read(&file, log_read, MAX_PATH_LEN) >= 0,
115 "Can not read log file.");
116
117 rc = strncmp(log_read, to_log, sizeof(log_read));
118 zassert_equal(rc, 0, "Text inside log file is not correct.");
119
120 zassert_equal(fs_close(&file), 0, "Can not close log file.");
121
122 to_log[sizeof(to_log)-2] = '2';
123
124 rc = write_log_to_file(to_log, sizeof(to_log), NULL);
125 backend->api->notify(backend, LOG_BACKEND_EVT_PROCESS_THREAD_DONE, NULL);
126
127 zassert_equal(fs_open(&file, fname, FS_O_READ), 0,
128 "Can not open log file.");
129
130 zassert_equal(fs_seek(&file, sizeof(to_log), FS_SEEK_SET), 0,
131 "Bad file size");
132
133 zassert_true(fs_read(&file, log_read, MAX_PATH_LEN) >= 0,
134 "Can not read log file.");
135
136 rc = strncmp(log_read, to_log, sizeof(log_read));
137 zassert_equal(rc, 0, "Text inside log file is not correct.");
138
139 zassert_equal(fs_close(&file), 0, "Can not close log file.");
140 }
141
ZTEST(test_log_backend_fs,test_log_fs_file_size)142 ZTEST(test_log_backend_fs, test_log_fs_file_size)
143 {
144 int rc;
145 int i;
146 struct fs_dir_t dir;
147 int file_ctr = 0;
148 static char fname[MAX_PATH_LEN];
149 uint8_t to_log[] = "Text Log";
150 struct fs_dirent entry;
151
152 fs_dir_t_init(&dir);
153
154 sprintf(fname, "%s/%s0000", CONFIG_LOG_BACKEND_FS_DIR, log_prefix);
155 zassert_equal(fs_stat(fname, &entry), 0, "Can not get file info.");
156
157 /* Fill in log file over size limit. */
158 for (i = 0;
159 i <= (CONFIG_LOG_BACKEND_FS_FILE_SIZE - entry.size) /
160 sizeof(to_log);
161 i++) {
162 rc = write_log_to_file(to_log, sizeof(to_log), NULL);
163 /* Written length not tracked here. */
164 ARG_UNUSED(rc);
165 }
166
167 backend->api->notify(backend, LOG_BACKEND_EVT_PROCESS_THREAD_DONE, NULL);
168
169 zassert_equal(fs_stat(fname, &entry), 0, "Can not get file info.");
170 size_t exp_size = CONFIG_LOG_BACKEND_FS_FILE_SIZE -
171 (CONFIG_LOG_BACKEND_FS_FILE_SIZE - entry.size) %
172 sizeof(to_log);
173 zassert_equal(entry.size, exp_size, "Unexpected %s file size (%d B)",
174 fname, entry.size);
175
176 sprintf(fname, "%s/%s0001", CONFIG_LOG_BACKEND_FS_DIR, log_prefix);
177 zassert_equal(fs_stat(fname, &entry), 0, "Can not get file info.");
178
179 zassert_equal(entry.size, sizeof(to_log),
180 "Unexpected %s file size (%d B)",
181 fname, entry.size);
182
183 rc = fs_opendir(&dir, CONFIG_LOG_BACKEND_FS_DIR);
184 zassert_equal(rc, 0, "Can not open directory.");
185 /* Count number of log files. */
186 while (rc >= 0) {
187 struct fs_dirent ent = { 0 };
188
189 rc = fs_readdir(&dir, &ent);
190 if ((rc < 0) || (ent.name[0] == 0)) {
191 break;
192 }
193 if (strstr(ent.name, log_prefix) != NULL) {
194 ++file_ctr;
195 }
196 }
197 (void)fs_closedir(&dir);
198 zassert_equal(file_ctr, 2, "File changing failed");
199 }
200
ZTEST(test_log_backend_fs,test_log_fs_files_max)201 ZTEST(test_log_backend_fs, test_log_fs_files_max)
202 {
203 int rc;
204 int i;
205 struct fs_dir_t dir;
206 int file_ctr = 0;
207 uint8_t to_log[] = "Text Log";
208 struct fs_dirent ent;
209 uint32_t test_mask = 0;
210
211 fs_dir_t_init(&dir);
212
213 /* Fill in log files over files count limit. */
214 for (i = 0;
215 i <= CONFIG_LOG_BACKEND_FS_FILE_SIZE /
216 sizeof(to_log) * (CONFIG_LOG_BACKEND_FS_FILES_LIMIT - 1);
217 i++) {
218 rc = write_log_to_file(to_log, sizeof(to_log), NULL);
219 /* Written length not tracked here. */
220 ARG_UNUSED(rc);
221 }
222
223 backend->api->notify(backend, LOG_BACKEND_EVT_PROCESS_THREAD_DONE, NULL);
224
225 rc = fs_opendir(&dir, CONFIG_LOG_BACKEND_FS_DIR);
226 zassert_equal(rc, 0, "Can not open directory.");
227 /* Count log files. */
228 while (rc >= 0) {
229
230 rc = fs_readdir(&dir, &ent);
231 if ((rc < 0) || (ent.name[0] == 0)) {
232 break;
233 }
234 if (strstr(ent.name, log_prefix) != NULL) {
235 ++file_ctr;
236 test_mask |= 1 << atoi(&ent.name[strlen(log_prefix)]);
237 }
238 }
239 (void)fs_closedir(&dir);
240 zassert_equal(file_ctr, CONFIG_LOG_BACKEND_FS_FILES_LIMIT,
241 "Bad files count: expected %d, got %d ",
242 CONFIG_LOG_BACKEND_FS_FILES_LIMIT, file_ctr);
243 /*expected files: log.0001, log.0002, log.0003, log.0004 */
244 zassert_equal(test_mask, 0b11110, "Unexpected file numeration");
245 }
246
backend_find(char const * name)247 static const struct log_backend *backend_find(char const *name)
248 {
249 size_t slen = strlen(name);
250
251 STRUCT_SECTION_FOREACH(log_backend, backend) {
252 if (strncmp(name, backend->name, slen) == 0) {
253 return backend;
254 }
255 }
256
257 return NULL;
258 }
259
260
suite_setup(void)261 void *suite_setup(void)
262 {
263 backend = backend_find("log_backend_fs");
264 zassert_not_null(backend);
265
266 return NULL;
267 }
268
269 ZTEST_SUITE(test_log_backend_fs, NULL, suite_setup, NULL, NULL, NULL);
270