diff options
Diffstat (limited to 'fs_mgr/libdm/dm_test.cpp')
-rw-r--r-- | fs_mgr/libdm/dm_test.cpp | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index adbe82088..67dc958d4 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp | |||
@@ -14,13 +14,29 @@ | |||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <fcntl.h> | ||
18 | #include <stdint.h> | ||
19 | #include <stdio.h> | ||
20 | #include <sys/ioctl.h> | ||
21 | #include <sys/types.h> | ||
22 | #include <time.h> | ||
23 | #include <unistd.h> | ||
24 | |||
25 | #include <chrono> | ||
26 | #include <ctime> | ||
17 | #include <map> | 27 | #include <map> |
28 | #include <thread> | ||
18 | 29 | ||
30 | #include <android-base/file.h> | ||
31 | #include <android-base/unique_fd.h> | ||
19 | #include <gtest/gtest.h> | 32 | #include <gtest/gtest.h> |
20 | #include <libdm/dm.h> | 33 | #include <libdm/dm.h> |
34 | #include <libdm/loop_control.h> | ||
35 | #include "test_util.h" | ||
21 | 36 | ||
22 | using namespace std; | 37 | using namespace std; |
23 | using namespace android::dm; | 38 | using namespace android::dm; |
39 | using unique_fd = android::base::unique_fd; | ||
24 | 40 | ||
25 | TEST(libdm, HasMinimumTargets) { | 41 | TEST(libdm, HasMinimumTargets) { |
26 | DeviceMapper& dm = DeviceMapper::Instance(); | 42 | DeviceMapper& dm = DeviceMapper::Instance(); |
@@ -35,3 +51,116 @@ TEST(libdm, HasMinimumTargets) { | |||
35 | auto iter = by_name.find("linear"); | 51 | auto iter = by_name.find("linear"); |
36 | EXPECT_NE(iter, by_name.end()); | 52 | EXPECT_NE(iter, by_name.end()); |
37 | } | 53 | } |
54 | |||
55 | // Helper to ensure that device mapper devices are released. | ||
56 | class TempDevice { | ||
57 | public: | ||
58 | TempDevice(const std::string& name, const DmTable& table) | ||
59 | : dm_(DeviceMapper::Instance()), name_(name), valid_(false) { | ||
60 | valid_ = dm_.CreateDevice(name, table); | ||
61 | } | ||
62 | TempDevice(TempDevice&& other) : dm_(other.dm_), name_(other.name_), valid_(other.valid_) { | ||
63 | other.valid_ = false; | ||
64 | } | ||
65 | ~TempDevice() { | ||
66 | if (valid_) { | ||
67 | dm_.DeleteDevice(name_); | ||
68 | } | ||
69 | } | ||
70 | bool Destroy() { | ||
71 | if (!valid_) { | ||
72 | return false; | ||
73 | } | ||
74 | valid_ = false; | ||
75 | return dm_.DeleteDevice(name_); | ||
76 | } | ||
77 | bool WaitForUdev() const { | ||
78 | auto start_time = std::chrono::steady_clock::now(); | ||
79 | while (true) { | ||
80 | if (!access(path().c_str(), F_OK)) { | ||
81 | return true; | ||
82 | } | ||
83 | if (errno != ENOENT) { | ||
84 | return false; | ||
85 | } | ||
86 | std::this_thread::sleep_for(50ms); | ||
87 | std::chrono::duration elapsed = std::chrono::steady_clock::now() - start_time; | ||
88 | if (elapsed >= 5s) { | ||
89 | return false; | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | std::string path() const { | ||
94 | std::string device_path; | ||
95 | if (!dm_.GetDmDevicePathByName(name_, &device_path)) { | ||
96 | return ""; | ||
97 | } | ||
98 | return device_path; | ||
99 | } | ||
100 | const std::string& name() const { return name_; } | ||
101 | bool valid() const { return valid_; } | ||
102 | |||
103 | TempDevice(const TempDevice&) = delete; | ||
104 | TempDevice& operator=(const TempDevice&) = delete; | ||
105 | |||
106 | TempDevice& operator=(TempDevice&& other) { | ||
107 | name_ = other.name_; | ||
108 | valid_ = other.valid_; | ||
109 | other.valid_ = false; | ||
110 | return *this; | ||
111 | } | ||
112 | |||
113 | private: | ||
114 | DeviceMapper& dm_; | ||
115 | std::string name_; | ||
116 | bool valid_; | ||
117 | }; | ||
118 | |||
119 | TEST(libdm, DmLinear) { | ||
120 | unique_fd tmp1(CreateTempFile("file_1", 4096)); | ||
121 | ASSERT_GE(tmp1, 0); | ||
122 | unique_fd tmp2(CreateTempFile("file_2", 4096)); | ||
123 | ASSERT_GE(tmp2, 0); | ||
124 | |||
125 | // Create two different files. These will back two separate loop devices. | ||
126 | const char message1[] = "Hello! This is sector 1."; | ||
127 | const char message2[] = "Goodbye. This is sector 2."; | ||
128 | ASSERT_TRUE(android::base::WriteFully(tmp1, message1, sizeof(message1))); | ||
129 | ASSERT_TRUE(android::base::WriteFully(tmp2, message2, sizeof(message2))); | ||
130 | |||
131 | LoopDevice loop_a(tmp1); | ||
132 | ASSERT_TRUE(loop_a.valid()); | ||
133 | LoopDevice loop_b(tmp2); | ||
134 | ASSERT_TRUE(loop_b.valid()); | ||
135 | |||
136 | // Define a 2-sector device, with each sector mapping to the first sector | ||
137 | // of one of our loop devices. | ||
138 | DmTable table; | ||
139 | ASSERT_TRUE(table.AddTarget(make_unique<DmTargetLinear>(0, 1, loop_a.device(), 0))); | ||
140 | ASSERT_TRUE(table.AddTarget(make_unique<DmTargetLinear>(1, 1, loop_b.device(), 0))); | ||
141 | ASSERT_TRUE(table.valid()); | ||
142 | |||
143 | TempDevice dev("libdm-test-dm-linear", table); | ||
144 | ASSERT_TRUE(dev.valid()); | ||
145 | ASSERT_FALSE(dev.path().empty()); | ||
146 | ASSERT_TRUE(dev.WaitForUdev()); | ||
147 | |||
148 | // Note: a scope is needed to ensure that there are no open descriptors | ||
149 | // when we go to close the device. | ||
150 | { | ||
151 | unique_fd dev_fd(open(dev.path().c_str(), O_RDWR)); | ||
152 | ASSERT_GE(dev_fd, 0); | ||
153 | |||
154 | // Test that each sector of our device is correctly mapped to each loop | ||
155 | // device. | ||
156 | char sector[512]; | ||
157 | ASSERT_TRUE(android::base::ReadFully(dev_fd, sector, sizeof(sector))); | ||
158 | ASSERT_EQ(strncmp(sector, message1, sizeof(message1)), 0); | ||
159 | ASSERT_TRUE(android::base::ReadFully(dev_fd, sector, sizeof(sector))); | ||
160 | ASSERT_EQ(strncmp(sector, message2, sizeof(message2)), 0); | ||
161 | } | ||
162 | |||
163 | // Normally the TestDevice destructor would delete this, but at least one | ||
164 | // test should ensure that device deletion works. | ||
165 | ASSERT_TRUE(dev.Destroy()); | ||
166 | } | ||