1 /*
2 * Copyright (c) 2019 Peter Bigot Consulting, LLC
3 * Copyright (c) 2023 Antmicro
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/kernel.h>
9 #include <zephyr/ztest.h>
10 #include <zephyr/fs/fs.h>
11
12 #include "test_fs_util.h"
13
14 #define HELLO "hello"
15 #define GOODBYE "goodbye"
16
17 /* Mount point for the tests should be provided by test runner.
18 * File system should be mounted before tests are started.
19 */
20 extern struct fs_mount_t *fs_basic_test_mp;
21
create_write_hello(const struct fs_mount_t * mp)22 static int create_write_hello(const struct fs_mount_t *mp)
23 {
24 struct testfs_path path;
25 struct fs_file_t file;
26
27 fs_file_t_init(&file);
28 TC_PRINT("creating and writing file\n");
29
30 zassert_equal(fs_open(&file,
31 testfs_path_init(&path, mp,
32 HELLO,
33 TESTFS_PATH_END),
34 FS_O_CREATE | FS_O_RDWR),
35 0,
36 "open hello failed");
37
38 struct fs_dirent stat;
39
40 zassert_equal(fs_stat(path.path, &stat),
41 0,
42 "stat new hello failed");
43
44 zassert_equal(stat.type, FS_DIR_ENTRY_FILE,
45 "stat new hello not file");
46 zassert_str_equal(stat.name, HELLO, "stat new hello not hello");
47 zassert_equal(stat.size, 0,
48 "stat new hello not empty");
49
50 zassert_equal(testfs_write_incrementing(&file, 0, TESTFS_BUFFER_SIZE),
51 TESTFS_BUFFER_SIZE,
52 "write constant failed");
53
54 zassert_equal(fs_stat(path.path, &stat),
55 0,
56 "stat written hello failed");
57
58 zassert_equal(stat.type, FS_DIR_ENTRY_FILE,
59 "stat written hello not file");
60 zassert_str_equal(stat.name, HELLO, "stat written hello not hello");
61
62 /* Anomalous behavior requiring upstream response */
63 if (mp->type == FS_LITTLEFS) {
64 /* VARIATION POINT: littlefs does not update the file size of
65 * an open file. See upstream issue #250.
66 */
67 zassert_equal(stat.size, 0,
68 "stat written hello bad size");
69 }
70
71 zassert_equal(fs_close(&file), 0,
72 "close hello failed");
73
74 zassert_equal(fs_stat(path.path, &stat),
75 0,
76 "stat closed hello failed");
77
78 zassert_equal(stat.type, FS_DIR_ENTRY_FILE,
79 "stat closed hello not file");
80 zassert_str_equal(stat.name, HELLO, "stat closed hello not hello");
81 zassert_equal(stat.size, TESTFS_BUFFER_SIZE,
82 "stat closed hello badsize");
83
84 return TC_PASS;
85 }
86
verify_hello(const struct fs_mount_t * mp)87 static int verify_hello(const struct fs_mount_t *mp)
88 {
89 struct testfs_path path;
90 struct fs_file_t file;
91
92 fs_file_t_init(&file);
93 TC_PRINT("opening and verifying file\n");
94
95 zassert_equal(fs_open(&file,
96 testfs_path_init(&path, mp,
97 HELLO,
98 TESTFS_PATH_END),
99 FS_O_CREATE | FS_O_RDWR),
100 0,
101 "verify hello open failed");
102
103 zassert_equal(fs_tell(&file), 0U,
104 "verify hello open tell failed");
105
106 zassert_equal(testfs_verify_incrementing(&file, 0, TESTFS_BUFFER_SIZE),
107 TESTFS_BUFFER_SIZE,
108 "verify hello at start failed");
109
110 zassert_equal(fs_tell(&file), TESTFS_BUFFER_SIZE,
111 "verify hello read tell failed");
112
113 zassert_equal(fs_close(&file), 0,
114 "verify close hello failed");
115
116 return TC_PASS;
117 }
118
seek_within_hello(const struct fs_mount_t * mp)119 static int seek_within_hello(const struct fs_mount_t *mp)
120 {
121 struct testfs_path path;
122 struct fs_file_t file;
123
124 fs_file_t_init(&file);
125 TC_PRINT("seek and tell in file\n");
126
127 zassert_equal(fs_open(&file,
128 testfs_path_init(&path, mp,
129 HELLO,
130 TESTFS_PATH_END),
131 FS_O_CREATE | FS_O_RDWR),
132 0,
133 "verify hello open failed");
134
135 zassert_equal(fs_tell(&file), 0U,
136 "verify hello open tell failed");
137
138 struct fs_dirent stat;
139
140 zassert_equal(fs_stat(path.path, &stat),
141 0,
142 "stat old hello failed");
143 zassert_equal(stat.size, TESTFS_BUFFER_SIZE,
144 "stat old hello bad size");
145
146 off_t pos = stat.size / 4;
147
148 zassert_equal(fs_seek(&file, pos, FS_SEEK_SET),
149 0,
150 "verify hello seek near mid failed");
151
152 zassert_equal(fs_tell(&file), pos,
153 "verify hello tell near mid failed");
154
155 zassert_equal(testfs_verify_incrementing(&file, pos, TESTFS_BUFFER_SIZE),
156 TESTFS_BUFFER_SIZE - pos,
157 "verify hello at middle failed");
158
159 zassert_equal(fs_tell(&file), stat.size,
160 "verify hello read middle tell failed");
161
162 zassert_equal(fs_seek(&file, -stat.size, FS_SEEK_CUR),
163 0,
164 "verify hello seek back from cur failed");
165
166 zassert_equal(fs_tell(&file), 0U,
167 "verify hello tell back from cur failed");
168
169 zassert_equal(fs_seek(&file, -pos, FS_SEEK_END),
170 0,
171 "verify hello seek from end failed");
172
173 zassert_equal(fs_tell(&file), stat.size - pos,
174 "verify hello tell from end failed");
175
176 zassert_equal(testfs_verify_incrementing(&file, stat.size - pos,
177 TESTFS_BUFFER_SIZE),
178 pos,
179 "verify hello at post middle failed");
180
181 zassert_equal(fs_close(&file), 0,
182 "verify close hello failed");
183
184 return TC_PASS;
185 }
186
truncate_hello(const struct fs_mount_t * mp)187 static int truncate_hello(const struct fs_mount_t *mp)
188 {
189 struct testfs_path path;
190 struct fs_file_t file;
191
192 fs_file_t_init(&file);
193 TC_PRINT("truncate in file\n");
194
195 zassert_equal(fs_open(&file,
196 testfs_path_init(&path, mp,
197 HELLO,
198 TESTFS_PATH_END),
199 FS_O_CREATE | FS_O_RDWR),
200 0,
201 "verify hello open failed");
202
203 struct fs_dirent stat;
204
205 zassert_equal(fs_stat(path.path, &stat),
206 0,
207 "stat old hello failed");
208 zassert_equal(stat.size, TESTFS_BUFFER_SIZE,
209 "stat old hello bad size");
210
211 off_t pos = 3 * stat.size / 4;
212
213 zassert_equal(fs_tell(&file), 0U,
214 "truncate initial tell failed");
215
216 zassert_equal(fs_truncate(&file, pos),
217 0,
218 "truncate 3/4 failed");
219
220 zassert_equal(fs_tell(&file), 0U,
221 "truncate post tell failed");
222
223 zassert_equal(fs_stat(path.path, &stat),
224 0,
225 "stat open 3/4 failed");
226
227 /* Anomalous behavior requiring upstream response */
228 if (mp->type == FS_LITTLEFS) {
229 /* VARIATION POINT: littlefs does not update the file size of
230 * an open file. See upstream issue #250.
231 */
232 zassert_equal(stat.size, TESTFS_BUFFER_SIZE,
233 "stat open 3/4 bad size");
234 }
235
236 zassert_equal(testfs_verify_incrementing(&file, 0, 64),
237 48,
238 "post truncate content unexpected");
239
240 zassert_equal(fs_close(&file), 0,
241 "post truncate close failed");
242
243 /* After close size is correct. */
244 zassert_equal(fs_stat(path.path, &stat),
245 0,
246 "stat closed truncated failed");
247 zassert_equal(stat.size, pos,
248 "stat closed truncated bad size");
249
250 return TC_PASS;
251 }
252
unlink_hello(const struct fs_mount_t * mp)253 static int unlink_hello(const struct fs_mount_t *mp)
254 {
255 struct testfs_path path;
256
257 TC_PRINT("unlink hello\n");
258
259 testfs_path_init(&path, mp,
260 HELLO,
261 TESTFS_PATH_END);
262
263 struct fs_dirent stat;
264
265 zassert_equal(fs_stat(path.path, &stat),
266 0,
267 "stat existing hello failed");
268 zassert_equal(fs_unlink(path.path),
269 0,
270 "unlink hello failed");
271 zassert_equal(fs_stat(path.path, &stat),
272 -ENOENT,
273 "stat existing hello failed");
274
275 return TC_PASS;
276 }
277
sync_goodbye(const struct fs_mount_t * mp)278 static int sync_goodbye(const struct fs_mount_t *mp)
279 {
280 struct testfs_path path;
281 struct fs_file_t file;
282
283 fs_file_t_init(&file);
284 TC_PRINT("sync goodbye\n");
285
286 zassert_equal(fs_open(&file,
287 testfs_path_init(&path, mp,
288 GOODBYE,
289 TESTFS_PATH_END),
290 FS_O_CREATE | FS_O_RDWR),
291 0,
292 "sync goodbye failed");
293
294 struct fs_dirent stat;
295
296 zassert_equal(fs_stat(path.path, &stat),
297 0,
298 "stat existing hello failed");
299 zassert_equal(stat.size, 0,
300 "stat new goodbye not empty");
301
302 zassert_equal(testfs_write_incrementing(&file, 0, TESTFS_BUFFER_SIZE),
303 TESTFS_BUFFER_SIZE,
304 "write goodbye failed");
305
306 zassert_equal(fs_tell(&file), TESTFS_BUFFER_SIZE,
307 "tell goodbye failed");
308
309 if (true && mp->type == FS_LITTLEFS) {
310 /* Upstream issue #250 */
311 zassert_equal(stat.size, 0,
312 "stat new goodbye not empty");
313 }
314
315 zassert_equal(fs_sync(&file), 0,
316 "sync goodbye failed");
317
318 zassert_equal(fs_tell(&file), TESTFS_BUFFER_SIZE,
319 "tell synced moved");
320
321 zassert_equal(fs_stat(path.path, &stat),
322 0,
323 "stat existing hello failed");
324 printk("sync size %u\n", (uint32_t)stat.size);
325
326 zassert_equal(stat.size, TESTFS_BUFFER_SIZE,
327 "stat synced goodbye not correct");
328
329 zassert_equal(fs_close(&file), 0,
330 "post sync close failed");
331
332 /* After close size is correct. */
333 zassert_equal(fs_stat(path.path, &stat),
334 0,
335 "stat sync failed");
336 zassert_equal(stat.size, TESTFS_BUFFER_SIZE,
337 "stat sync bad size");
338
339 return TC_PASS;
340 }
341
verify_goodbye(const struct fs_mount_t * mp)342 static int verify_goodbye(const struct fs_mount_t *mp)
343 {
344 struct testfs_path path;
345 struct fs_file_t file;
346
347 fs_file_t_init(&file);
348 TC_PRINT("verify goodbye\n");
349
350 zassert_equal(fs_open(&file,
351 testfs_path_init(&path, mp,
352 GOODBYE,
353 TESTFS_PATH_END),
354 FS_O_CREATE | FS_O_RDWR),
355 0,
356 "verify goodbye failed");
357
358 zassert_equal(testfs_verify_incrementing(&file, 0, TESTFS_BUFFER_SIZE),
359 TESTFS_BUFFER_SIZE,
360 "write goodbye failed");
361
362 zassert_equal(fs_close(&file), 0,
363 "post sync close failed");
364
365 return TC_PASS;
366 }
367
test_fs_basic(void)368 void test_fs_basic(void)
369 {
370
371 zassert_equal(fs_mount(fs_basic_test_mp), 0,
372 "mount failed");
373
374 zassert_equal(create_write_hello(fs_basic_test_mp), TC_PASS,
375 "write hello failed");
376
377 zassert_equal(verify_hello(fs_basic_test_mp), TC_PASS,
378 "verify hello failed");
379
380 zassert_equal(seek_within_hello(fs_basic_test_mp), TC_PASS,
381 "seek within hello failed");
382
383 zassert_equal(truncate_hello(fs_basic_test_mp), TC_PASS,
384 "truncate hello failed");
385
386 zassert_equal(unlink_hello(fs_basic_test_mp), TC_PASS,
387 "unlink hello failed");
388
389 zassert_equal(sync_goodbye(fs_basic_test_mp), TC_PASS,
390 "sync goodbye failed");
391
392 TC_PRINT("unmounting %s\n", fs_basic_test_mp->mnt_point);
393 zassert_equal(fs_unmount(fs_basic_test_mp), 0,
394 "unmount small failed");
395
396 k_sleep(K_MSEC(100)); /* flush log messages */
397 TC_PRINT("checking double unmount diagnoses\n");
398
399 zassert_equal(fs_unmount(fs_basic_test_mp), -EINVAL,
400 "unmount unmounted failed");
401
402 zassert_equal(fs_mount(fs_basic_test_mp), 0,
403 "mount failed");
404
405 zassert_equal(verify_goodbye(fs_basic_test_mp), TC_PASS,
406 "verify goodbye failed");
407
408 zassert_equal(fs_unmount(fs_basic_test_mp), 0,
409 "unmount2 small failed");
410 }
411