summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs_mgr/libdm/Android.bp1
-rw-r--r--fs_mgr/libdm/dm_test.cpp129
-rw-r--r--fs_mgr/libdm/loop_control_test.cpp5
-rw-r--r--fs_mgr/libdm/test_util.cpp52
-rw-r--r--fs_mgr/libdm/test_util.h35
5 files changed, 219 insertions, 3 deletions
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 21a4cb5bd..22af1238e 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -49,5 +49,6 @@ cc_test {
49 srcs: [ 49 srcs: [
50 "dm_test.cpp", 50 "dm_test.cpp",
51 "loop_control_test.cpp", 51 "loop_control_test.cpp",
52 "test_util.cpp",
52 ] 53 ]
53} 54}
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
22using namespace std; 37using namespace std;
23using namespace android::dm; 38using namespace android::dm;
39using unique_fd = android::base::unique_fd;
24 40
25TEST(libdm, HasMinimumTargets) { 41TEST(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.
56class 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
119TEST(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}
diff --git a/fs_mgr/libdm/loop_control_test.cpp b/fs_mgr/libdm/loop_control_test.cpp
index cd1d015ff..08bdc00a3 100644
--- a/fs_mgr/libdm/loop_control_test.cpp
+++ b/fs_mgr/libdm/loop_control_test.cpp
@@ -17,17 +17,16 @@
17#include "libdm/loop_control.h" 17#include "libdm/loop_control.h"
18 18
19#include <fcntl.h> 19#include <fcntl.h>
20#include <linux/memfd.h>
21#include <stdio.h> 20#include <stdio.h>
22#include <stdlib.h> 21#include <stdlib.h>
23#include <sys/stat.h> 22#include <sys/stat.h>
24#include <sys/syscall.h>
25#include <sys/types.h> 23#include <sys/types.h>
26#include <unistd.h> 24#include <unistd.h>
27 25
28#include <android-base/file.h> 26#include <android-base/file.h>
29#include <android-base/unique_fd.h> 27#include <android-base/unique_fd.h>
30#include <gtest/gtest.h> 28#include <gtest/gtest.h>
29#include "test_util.h"
31 30
32using namespace std; 31using namespace std;
33using namespace android::dm; 32using namespace android::dm;
@@ -36,7 +35,7 @@ using unique_fd = android::base::unique_fd;
36static unique_fd TempFile() { 35static unique_fd TempFile() {
37 // A loop device needs to be at least one sector to actually work, so fill 36 // A loop device needs to be at least one sector to actually work, so fill
38 // up the file with a message. 37 // up the file with a message.
39 unique_fd fd(syscall(__NR_memfd_create, "fake_disk", 0)); 38 unique_fd fd(CreateTempFile("temp", 0));
40 if (fd < 0) { 39 if (fd < 0) {
41 return {}; 40 return {};
42 } 41 }
diff --git a/fs_mgr/libdm/test_util.cpp b/fs_mgr/libdm/test_util.cpp
new file mode 100644
index 000000000..307251cda
--- /dev/null
+++ b/fs_mgr/libdm/test_util.cpp
@@ -0,0 +1,52 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <fcntl.h>
18#include <linux/memfd.h>
19#include <stdio.h>
20#include <sys/syscall.h>
21#include <sys/types.h>
22#include <unistd.h>
23
24#include "test_util.h"
25
26namespace android {
27namespace dm {
28
29using unique_fd = android::base::unique_fd;
30
31// Create a temporary in-memory file. If size is non-zero, the file will be
32// created with a fixed size.
33unique_fd CreateTempFile(const std::string& name, size_t size) {
34 unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING));
35 if (fd < 0) {
36 return {};
37 }
38 if (size) {
39 if (ftruncate(fd, size) < 0) {
40 perror("ftruncate");
41 return {};
42 }
43 if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
44 perror("fcntl");
45 return {};
46 }
47 }
48 return fd;
49}
50
51} // namespace dm
52} // namespace android
diff --git a/fs_mgr/libdm/test_util.h b/fs_mgr/libdm/test_util.h
new file mode 100644
index 000000000..96b051ca2
--- /dev/null
+++ b/fs_mgr/libdm/test_util.h
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef _LIBDM_TEST_UTILS_H_
18#define _LIBDM_TEST_UTILS_H_
19
20#include <android-base/unique_fd.h>
21#include <stddef.h>
22
23#include <string>
24
25namespace android {
26namespace dm {
27
28// Create a temporary in-memory file. If size is non-zero, the file will be
29// created with a fixed size.
30android::base::unique_fd CreateTempFile(const std::string& name, size_t size);
31
32} // namespace dm
33} // namespace android
34
35#endif // _LIBDM_TEST_UTILS_H_