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