1 // Copyright 2018 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 <stdint.h> 8 #include <stdio.h> 9 #include <unistd.h> 10 11 #include <fbl/function.h> 12 #include <fbl/string.h> 13 #include <fbl/vector.h> 14 #include <fs-management/mount.h> 15 #include <fvm/fvm.h> 16 #include <lib/zx/time.h> 17 #include <zircon/status.h> 18 #include <zircon/syscalls.h> 19 #include <zircon/types.h> 20 21 // Macro for printing more information in error logs. 22 // "[File:Line] Error(error_name): Message\n" 23 #define LOG_ERROR(error_code, msg_fmt, ...) \ 24 fprintf(stderr, "[%s:%d] Error(%s): " msg_fmt, \ 25 __FILE__, __LINE__, zx_status_get_string(error_code), ##__VA_ARGS__) 26 27 // Macro for printing more information in stdout. 28 // "[File:Line] Info: Message\n" 29 #define LOG_INFO(msg_fmt, ...) \ 30 fprintf(stdout, "[%s:%d] Info: " msg_fmt, \ 31 __FILE__, __LINE__, ##__VA_ARGS__) 32 33 namespace fs_test_utils { 34 35 constexpr size_t kPathSize = PATH_MAX; 36 37 constexpr size_t kFvmBlockSize = FVM_BLOCK_SIZE; 38 39 // TODO(gevalentno): when ZX-2013 is resolved, make MemFs setup and teardown 40 // part of the test fixture and remove RunWithMemFs. 41 // Workaround that provides a MemFs per process, since it cannot be unbinded 42 // from the process namespace yet. 43 int RunWithMemFs(const fbl::Function<int()>& main_fn); 44 45 // Available options for the test fixture. 46 // 47 // Note: use_ramdisk and block_device_path are mutually exclusive. 48 struct FixtureOptions { 49 DefaultFixtureOptions50 static FixtureOptions Default(disk_format_t format) { 51 FixtureOptions options; 52 options.use_ramdisk = true; 53 options.ramdisk_block_size = 512; 54 options.ramdisk_block_count = zx_system_get_physmem() / (2 * options.ramdisk_block_size); 55 options.use_fvm = false; 56 options.fvm_slice_size = kFvmBlockSize * (2 << 10); 57 options.fs_type = format; 58 options.seed = static_cast<unsigned int>(zx::ticks::now().get()); 59 return options; 60 } 61 62 // Returns true if the options are valid. 63 // When invalid |err_string| will be populated with a human readable error description. 64 bool IsValid(fbl::String* err_description) const; 65 66 // Path to the block device to use. 67 fbl::String block_device_path = ""; 68 69 // If true a ramdisk will be created and shared for the test. 70 bool use_ramdisk = false; 71 72 // Number of blocks the ramdisk will contain. 73 size_t ramdisk_block_count = 0; 74 75 // Size of the blocks the ramdisk will have. 76 size_t ramdisk_block_size = 0; 77 78 // If true an fvm will be mounted on the device, and the filesystem will be 79 // mounted on top of a fresh partition. 80 bool use_fvm = false; 81 82 // Size of each slice of the created fvm. 83 size_t fvm_slice_size = 0; 84 85 // Type of filesystem to mount. 86 disk_format_t fs_type; 87 88 // Format the device device with the given |fs_type|. This is useful 89 // when a test requires a block_device(and fvm) for tests. 90 bool fs_format = true; 91 92 // Mount the device in |Fixture::fs_path()|. Format is auto detected. 93 bool fs_mount = true; 94 95 // Seed for pseudo random number generator. 96 unsigned int seed = 0; 97 }; 98 99 // Provides a base fixture for File system tests. 100 // In main(a.k.a run_all_unittests): 101 // 102 // RunWithMemFs([argc, argv] () { // Sets up then cleans up Local MemFs. 103 // return run_all_unittests(argc, argv) ? 0: 1; 104 // } 105 class Fixture { 106 public: 107 Fixture() = delete; 108 explicit Fixture(const FixtureOptions& options); 109 Fixture(const Fixture&) = delete; 110 Fixture(Fixture&&) = delete; 111 Fixture& operator=(const Fixture&) = delete; 112 Fixture& operator=(Fixture&&) = delete; 113 ~Fixture(); 114 115 // Returns the options used by this fixture. options()116 const FixtureOptions& options() const { 117 return options_; 118 } 119 120 // Returns the path to the block device hosting the FS. block_device_path()121 const fbl::String& block_device_path() const { 122 return block_device_path_; 123 } 124 125 // Returns the path to the FVM partition created for the block device 126 // hosting the FS. Will return empty if !options_.use_fvm. partition_path()127 const fbl::String& partition_path() const { 128 return partition_path_; 129 } 130 131 // Returns either the block_device path or partition_path if using fvm. GetFsBlockDevice()132 const fbl::String& GetFsBlockDevice() const { 133 return (options_.use_fvm) ? partition_path_ : block_device_path_; 134 } 135 136 // Returns the path where the filesystem was mounted. fs_path()137 const fbl::String& fs_path() const { 138 return fs_path_; 139 } 140 141 // Returns a seed to be used along the test, for rand_r calls. mutable_seed()142 unsigned int* mutable_seed() { 143 return &seed_; 144 } 145 146 // Unmounts the FS from fs_path. 147 zx_status_t Umount(); 148 149 // Mounts the FsBlockDevice into fs_path. 150 zx_status_t Mount(); 151 152 // Umounts and then Mounts the device. Remount()153 zx_status_t Remount() { 154 zx_status_t res = Umount(); 155 if (res != ZX_OK) { 156 return res; 157 } 158 res = Mount(); 159 return res; 160 } 161 162 // Sets up MemFs and Ramdisk, allocating resources for the tests. 163 zx_status_t SetUpTestCase(); 164 165 // Formats the block device with the required type, creates a fvm, and mounts 166 // the fs. 167 zx_status_t SetUp(); 168 169 // Cleans up the block device by reformatting it, destroys the fvm and 170 // unmounts the fs. 171 zx_status_t TearDown(); 172 173 // Destroys the ramdisk, MemFs will die with the process. This should be 174 // called after all tests finished execution to free resources. 175 zx_status_t TearDownTestCase(); 176 177 private: 178 FixtureOptions options_; 179 180 // State of the resources allocated by the fixture. 181 enum class ResourceState { 182 kUnallocated, 183 kAllocated, 184 kFreed, 185 }; 186 187 // Path to the block device hosting the mounted FS. 188 fbl::String block_device_path_; 189 190 // When using fvm, the FS will be mounted here. 191 fbl::String partition_path_; 192 193 // The root path where FS is mounted. 194 fbl::String fs_path_; 195 196 unsigned int seed_; 197 198 // Keep track of the resource allocation during the setup teardown process, 199 // to avoid leaks, or unnecessary errors when trying to free resources, that 200 // may have never been allocated in first place. 201 ResourceState fs_state_ = ResourceState::kUnallocated; 202 ResourceState fvm_state_ = ResourceState::kUnallocated; 203 ResourceState ramdisk_state_ = ResourceState::kUnallocated; 204 }; 205 206 } // namespace fs_test_utils 207