1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #pragma once
6
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include <fs-management/mount.h>
13 #include <unittest/unittest.h>
14 #include <zircon/compiler.h>
15 #include <zircon/device/block.h>
16
17 __BEGIN_CDECLS;
18
19 typedef struct fs_info {
20 const char* name;
21 bool (*should_test)(void);
22 int (*mkfs)(const char* disk_path);
23 int (*mount)(const char* disk_path, const char* mount_path);
24 int (*unmount)(const char* mount_path);
25 int (*fsck)(const char* mount_path);
26 bool can_be_mounted;
27 bool can_mount_sub_filesystems;
28 bool supports_hardlinks;
29 bool supports_watchers;
30 bool supports_create_by_vmo;
31 bool supports_mmap;
32 bool supports_resize;
33 int64_t nsec_granularity;
34 } fs_info_t;
35
36 // Path to mounted filesystem currently being tested
37 extern const char* kTmpfsPath;
38 extern const char* kMountPath;
39
40 // Path to the mounted filesystem's backing store (if it exists)
41 extern char test_disk_path[];
42
43 // Path to the mounted filesystems's backing ramdisk (if it exists).
44 extern char* ramdisk_path;
45
46 // Identify if a real disk is being tested instead of a ramdisk.
47 extern bool use_real_disk;
48
49 // The disk's cached info.
50 extern block_info_t test_disk_info;
51
52 // A filter of the filesystems; indicates which one should be tested.
53 extern const char* filesystem_name_filter;
54
55 // Current filesystem's info
56 extern fs_info_t* test_info;
57
58 extern const fsck_options_t test_fsck_options;
59
60 #define NUM_FILESYSTEMS 3
61 extern fs_info_t FILESYSTEMS[NUM_FILESYSTEMS];
62
63 typedef enum fs_test_type {
64 // The partition may appear as any generic block device
65 FS_TEST_NORMAL,
66 // The partition should appear on top of a resizable
67 // FVM device
68 FS_TEST_FVM,
69 } fs_test_type_t;
70
71 #define TEST_BLOCK_COUNT_DEFAULT (1LLU << 17)
72 #define TEST_BLOCK_SIZE_DEFAULT (1LLU << 9)
73 #define TEST_FVM_SLICE_SIZE_DEFAULT (8 * (1 << 20))
74
75 typedef struct test_disk {
76 uint64_t block_count;
77 uint64_t block_size;
78 // Only applicable for FVM tests.
79 uint64_t slice_size;
80 } test_disk_t;
81
82 extern const test_disk_t default_test_disk;
83
84 void setup_fs_test(test_disk_t disk, fs_test_type_t test_class);
85 void teardown_fs_test(fs_test_type_t test_class);
86
can_execute_test(const fs_info_t * info,const test_disk_t * requested_disk,fs_test_type_t t)87 inline bool can_execute_test(const fs_info_t* info, const test_disk_t* requested_disk,
88 fs_test_type_t t) {
89
90 uint64_t requested_size = requested_disk->block_count * requested_disk->block_size;
91 uint64_t real_size = test_disk_info.block_count * test_disk_info.block_size;
92
93 if (use_real_disk && (real_size < requested_size)) {
94 printf("Disk too small (is %zu bytes, must be %zu bytes): \n",
95 real_size, requested_size);
96 return false;
97 }
98
99 switch (t) {
100 case FS_TEST_NORMAL:
101 return info->should_test();
102 case FS_TEST_FVM:
103 return info->should_test() && info->supports_resize;
104 default:
105 printf("Unknown filesystem type: ");
106 return false;
107 }
108 }
109
110 // As a small optimization, avoid even creating a ramdisk
111 // for filesystem tests when "utest_test_type" is not at
112 // LEAST size "medium". This avoids the overhead of creating
113 // a ramdisk when running small tests.
114 #define BEGIN_FS_TEST_CASE(case_name, disk, fs_type, fs_name, info) \
115 BEGIN_TEST_CASE(case_name##_##fs_name) \
116 if (utest_test_type & ~TEST_SMALL) { \
117 test_info = info; \
118 if (can_execute_test(test_info, &disk, fs_type)) { \
119 setup_fs_test(disk, fs_type);
120
121 #define END_FS_TEST_CASE(case_name, fs_type, fs_name) \
122 teardown_fs_test(fs_type); \
123 } else { \
124 printf("Filesystem not tested\n"); \
125 } \
126 } \
127 END_TEST_CASE(case_name##_##fs_name)
128
129 #define FS_TEST_CASE(case_name, disk, CASE_TESTS, test_type, fs_type, index) \
130 BEGIN_FS_TEST_CASE(case_name, disk, test_type, fs_type, &FILESYSTEMS[index]) \
131 CASE_TESTS \
132 END_FS_TEST_CASE(case_name, test_type, fs_type)
133
134 #define RUN_FOR_ALL_FILESYSTEMS_TYPE(case_name, disk, test_type, CASE_TESTS) \
135 FS_TEST_CASE(case_name, disk, CASE_TESTS, test_type, memfs, 0) \
136 FS_TEST_CASE(case_name, disk, CASE_TESTS, test_type, minfs, 1) \
137 FS_TEST_CASE(case_name, disk, CASE_TESTS, test_type, thinfs, 2)
138
139 #define RUN_FOR_ALL_FILESYSTEMS_SIZE(case_name, disk, CASE_TESTS) \
140 FS_TEST_CASE(case_name, disk, CASE_TESTS, FS_TEST_NORMAL, memfs, 0) \
141 FS_TEST_CASE(case_name, disk, CASE_TESTS, FS_TEST_NORMAL, minfs, 1) \
142 FS_TEST_CASE(case_name##_fvm, disk, CASE_TESTS, FS_TEST_FVM, minfs, 1) \
143 FS_TEST_CASE(case_name, disk, CASE_TESTS, FS_TEST_NORMAL, thinfs, 2)
144
145 #define RUN_FOR_ALL_FILESYSTEMS(case_name, CASE_TESTS) \
146 RUN_FOR_ALL_FILESYSTEMS_SIZE(case_name, default_test_disk, CASE_TESTS)
147
148 __END_CDECLS;
149