• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 <string>
18 #include <tuple>
19 
20 #include <android-base/macros.h>
21 #include <gtest/gtest.h>
22 
23 #include "apex_database.h"
24 
25 namespace android {
26 namespace apex {
27 namespace {
28 
29 using MountedApexData = MountedApexDatabase::MountedApexData;
30 
TEST(MountedApexDataTest,LinearOrder)31 TEST(MountedApexDataTest, LinearOrder) {
32   constexpr const char* kLoopName[] = {"loop1", "loop2", "loop3"};
33   constexpr const char* kPath[] = {"path1", "path2", "path3"};
34   constexpr const char* kMount[] = {"mount1", "mount2", "mount3"};
35   constexpr const char* kDm[] = {"dm1", "dm2", "dm3"};
36   constexpr const char* kHashtreeLoopName[] = {"hash-loop1", "hash-loop2",
37                                                "hash-loop3"};
38   // NOLINTNEXTLINE(bugprone-sizeof-expression)
39   constexpr size_t kCount = arraysize(kLoopName) * arraysize(kPath) *
40                             arraysize(kMount) * arraysize(kDm);
41 
42   auto index_fn = [&](size_t i) {
43     const size_t loop_index = i % arraysize(kLoopName);
44     const size_t loop_rest = i / arraysize(kLoopName);
45     const size_t path_index = loop_rest % arraysize(kPath);
46     const size_t path_rest = loop_rest / arraysize(kPath);
47     const size_t mount_index = path_rest % arraysize(kMount);
48     const size_t mount_rest = path_rest / arraysize(kMount);
49     const size_t dm_index = mount_rest % arraysize(kDm);
50     const size_t dm_rest = mount_rest / arraysize(kHashtreeLoopName);
51     const size_t hashtree_loop_index = dm_rest % arraysize(kHashtreeLoopName);
52     CHECK_EQ(dm_rest / arraysize(kHashtreeLoopName), 0u);
53     return std::make_tuple(loop_index, path_index, mount_index, dm_index,
54                            hashtree_loop_index);
55   };
56 
57   MountedApexData data[kCount];
58   for (size_t i = 0; i < kCount; ++i) {
59     size_t loop_idx, path_idx, mount_idx, dm_idx, hash_loop_idx;
60     std::tie(loop_idx, path_idx, mount_idx, dm_idx, hash_loop_idx) =
61         index_fn(i);
62     data[i] =
63         MountedApexData(kLoopName[loop_idx], kPath[path_idx], kMount[mount_idx],
64                         kDm[dm_idx], kHashtreeLoopName[hash_loop_idx]);
65   }
66 
67   for (size_t i = 0; i < kCount; ++i) {
68     size_t loop_idx_i, path_idx_i, mount_idx_i, dm_idx_i, hash_loop_idx_i;
69     std::tie(loop_idx_i, path_idx_i, mount_idx_i, dm_idx_i, hash_loop_idx_i) =
70         index_fn(i);
71     for (size_t j = i; j < kCount; ++j) {
72       size_t loop_idx_j, path_idx_j, mount_idx_j, dm_idx_j, hash_loop_idx_j;
73       std::tie(loop_idx_j, path_idx_j, mount_idx_j, dm_idx_j, hash_loop_idx_j) =
74           index_fn(j);
75       if (loop_idx_i != loop_idx_j) {
76         EXPECT_EQ(loop_idx_i < loop_idx_j, data[i] < data[j]);
77         continue;
78       }
79       if (path_idx_i != path_idx_j) {
80         EXPECT_EQ(path_idx_i < path_idx_j, data[i] < data[j]);
81         continue;
82       }
83       if (mount_idx_i != mount_idx_j) {
84         EXPECT_EQ(mount_idx_i < mount_idx_j, data[i] < data[j]);
85         continue;
86       }
87       if (dm_idx_i != dm_idx_j) {
88         EXPECT_EQ(dm_idx_i < dm_idx_j, data[i] < data[j]);
89         continue;
90       }
91       EXPECT_EQ(hash_loop_idx_i < hash_loop_idx_j, data[i] < data[j]);
92     }
93   }
94 }
95 
CountPackages(const MountedApexDatabase & db)96 size_t CountPackages(const MountedApexDatabase& db) {
97   size_t ret = 0;
98   db.ForallMountedApexes([&ret](const std::string& a ATTRIBUTE_UNUSED,
99                                 const MountedApexData& b ATTRIBUTE_UNUSED,
100                                 bool c ATTRIBUTE_UNUSED) { ++ret; });
101   return ret;
102 }
103 
Contains(const MountedApexDatabase & db,const std::string & package,const std::string & loop_name,const std::string & full_path,const std::string & mount_point,const std::string & device_name,const std::string & hashtree_loop_name)104 bool Contains(const MountedApexDatabase& db, const std::string& package,
105               const std::string& loop_name, const std::string& full_path,
106               const std::string& mount_point, const std::string& device_name,
107               const std::string& hashtree_loop_name) {
108   bool found = false;
109   db.ForallMountedApexes([&](const std::string& p, const MountedApexData& d,
110                              bool b ATTRIBUTE_UNUSED) {
111     if (package == p && loop_name == d.loop_name && full_path == d.full_path &&
112         mount_point == d.mount_point && device_name == d.device_name &&
113         hashtree_loop_name == d.hashtree_loop_name) {
114       found = true;
115     }
116   });
117   return found;
118 }
119 
ContainsPackage(const MountedApexDatabase & db,const std::string & package,const std::string & loop_name,const std::string & full_path,const std::string & dm,const std::string & hashtree_loop_name)120 bool ContainsPackage(const MountedApexDatabase& db, const std::string& package,
121                      const std::string& loop_name, const std::string& full_path,
122                      const std::string& dm,
123                      const std::string& hashtree_loop_name) {
124   bool found = false;
125   db.ForallMountedApexes(
126       package, [&](const MountedApexData& d, bool b ATTRIBUTE_UNUSED) {
127         if (loop_name == d.loop_name && full_path == d.full_path &&
128             dm == d.device_name && hashtree_loop_name == d.hashtree_loop_name) {
129           found = true;
130         }
131       });
132   return found;
133 }
134 
TEST(ApexDatabaseTest,AddRemovedMountedApex)135 TEST(ApexDatabaseTest, AddRemovedMountedApex) {
136   constexpr const char* kPackage = "package";
137   constexpr const char* kLoopName = "loop";
138   constexpr const char* kPath = "path";
139   constexpr const char* kMountPoint = "mount";
140   constexpr const char* kDeviceName = "dev";
141   constexpr const char* kHashtreeLoopName = "hash-loop";
142 
143   MountedApexDatabase db;
144   ASSERT_EQ(CountPackages(db), 0u);
145 
146   db.AddMountedApex(kPackage, false, kLoopName, kPath, kMountPoint, kDeviceName,
147                     kHashtreeLoopName);
148   ASSERT_TRUE(Contains(db, kPackage, kLoopName, kPath, kMountPoint, kDeviceName,
149                        kHashtreeLoopName));
150   ASSERT_TRUE(ContainsPackage(db, kPackage, kLoopName, kPath, kDeviceName,
151                               kHashtreeLoopName));
152 
153   db.RemoveMountedApex(kPackage, kPath);
154   EXPECT_FALSE(Contains(db, kPackage, kLoopName, kPath, kMountPoint,
155                         kDeviceName, kHashtreeLoopName));
156   EXPECT_FALSE(ContainsPackage(db, kPackage, kLoopName, kPath, kDeviceName,
157                                kHashtreeLoopName));
158 }
159 
TEST(ApexDatabaseTest,MountMultiple)160 TEST(ApexDatabaseTest, MountMultiple) {
161   constexpr const char* kPackage[] = {"package", "package", "package",
162                                       "package"};
163   constexpr const char* kLoopName[] = {"loop", "loop2", "loop3", "loop4"};
164   constexpr const char* kPath[] = {"path", "path2", "path", "path4"};
165   constexpr const char* kMountPoint[] = {"mount", "mount2", "mount", "mount4"};
166   constexpr const char* kDeviceName[] = {"dev", "dev2", "dev3", "dev4"};
167   constexpr const char* kHashtreeLoopName[] = {"hash-loop", "hash-loop2",
168                                                "hash-loop3", "hash-loop4"};
169   MountedApexDatabase db;
170   ASSERT_EQ(CountPackages(db), 0u);
171 
172   for (size_t i = 0; i < arraysize(kPackage); ++i) {
173     db.AddMountedApex(kPackage[i], false, kLoopName[i], kPath[i],
174                       kMountPoint[i], kDeviceName[i], kHashtreeLoopName[i]);
175   }
176 
177   ASSERT_EQ(CountPackages(db), 4u);
178   for (size_t i = 0; i < arraysize(kPackage); ++i) {
179     ASSERT_TRUE(Contains(db, kPackage[i], kLoopName[i], kPath[i],
180                          kMountPoint[i], kDeviceName[i], kHashtreeLoopName[i]));
181     ASSERT_TRUE(ContainsPackage(db, kPackage[i], kLoopName[i], kPath[i],
182                                 kDeviceName[i], kHashtreeLoopName[i]));
183   }
184 
185   db.RemoveMountedApex(kPackage[0], kPath[0]);
186   EXPECT_FALSE(Contains(db, kPackage[0], kLoopName[0], kPath[0], kMountPoint[0],
187                         kDeviceName[0], kHashtreeLoopName[0]));
188   EXPECT_FALSE(ContainsPackage(db, kPackage[0], kLoopName[0], kPath[0],
189                                kDeviceName[0], kHashtreeLoopName[0]));
190   EXPECT_TRUE(Contains(db, kPackage[1], kLoopName[1], kPath[1], kMountPoint[1],
191                        kDeviceName[1], kHashtreeLoopName[1]));
192   EXPECT_TRUE(ContainsPackage(db, kPackage[1], kLoopName[1], kPath[1],
193                               kDeviceName[1], kHashtreeLoopName[1]));
194   EXPECT_TRUE(Contains(db, kPackage[2], kLoopName[2], kPath[2], kMountPoint[2],
195                        kDeviceName[2], kHashtreeLoopName[2]));
196   EXPECT_TRUE(ContainsPackage(db, kPackage[2], kLoopName[2], kPath[2],
197                               kDeviceName[2], kHashtreeLoopName[2]));
198   EXPECT_TRUE(Contains(db, kPackage[3], kLoopName[3], kPath[3], kMountPoint[3],
199                        kDeviceName[3], kHashtreeLoopName[3]));
200   EXPECT_TRUE(ContainsPackage(db, kPackage[3], kLoopName[3], kPath[3],
201                               kDeviceName[3], kHashtreeLoopName[3]));
202 }
203 
TEST(ApexDatabaseTest,GetLatestMountedApex)204 TEST(ApexDatabaseTest, GetLatestMountedApex) {
205   constexpr const char* kPackage = "package";
206   constexpr const char* kLoopName = "loop";
207   constexpr const char* kPath = "path";
208   constexpr const char* kMountPoint = "mount";
209   constexpr const char* kDeviceName = "dev";
210   constexpr const char* kHashtreeLoopName = "hash-loop";
211 
212   MountedApexDatabase db;
213   ASSERT_EQ(CountPackages(db), 0u);
214 
215   db.AddMountedApex(kPackage, true, kLoopName, kPath, kMountPoint, kDeviceName,
216                     kHashtreeLoopName);
217 
218   auto ret = db.GetLatestMountedApex(kPackage);
219   MountedApexData expected(kLoopName, kPath, kMountPoint, kDeviceName,
220                            kHashtreeLoopName);
221   ASSERT_TRUE(ret.has_value());
222   ASSERT_EQ(ret->loop_name, std::string(kLoopName));
223   ASSERT_EQ(ret->full_path, std::string(kPath));
224   ASSERT_EQ(ret->mount_point, std::string(kMountPoint));
225   ASSERT_EQ(ret->device_name, std::string(kDeviceName));
226   ASSERT_EQ(ret->hashtree_loop_name, std::string(kHashtreeLoopName));
227 }
228 
TEST(ApexDatabaseTest,GetLatestMountedApexReturnsNullopt)229 TEST(ApexDatabaseTest, GetLatestMountedApexReturnsNullopt) {
230   MountedApexDatabase db;
231   auto ret = db.GetLatestMountedApex("no-such-name");
232   ASSERT_FALSE(ret.has_value());
233 }
234 
235 #pragma clang diagnostic push
236 // error: 'ReturnSentinel' was marked unused but was used
237 // [-Werror,-Wused-but-marked-unused]
238 #pragma clang diagnostic ignored "-Wused-but-marked-unused"
239 
TEST(MountedApexDataTest,NoDuplicateLoopDataLoopDevices)240 TEST(MountedApexDataTest, NoDuplicateLoopDataLoopDevices) {
241   ASSERT_DEATH(
242       {
243         MountedApexDatabase db;
244         db.AddMountedApex("package", false, "loop", "path", "mount", "dm",
245                           "hashtree-loop1");
246         db.AddMountedApex("package2", false, "loop", "path2", "mount2", "dm2",
247                           "hashtree-loop2");
248       },
249       "Duplicate loop device: loop");
250 }
251 
TEST(MountedApexDataTest,NoDuplicateLoopHashtreeLoopDevices)252 TEST(MountedApexDataTest, NoDuplicateLoopHashtreeLoopDevices) {
253   ASSERT_DEATH(
254       {
255         MountedApexDatabase db;
256         db.AddMountedApex("package", false, "loop1", "path", "mount", "dm",
257                           "hashtree-loop");
258         db.AddMountedApex("package2", false, "loop2", "path2", "mount2", "dm2",
259                           "hashtree-loop");
260       },
261       "Duplicate loop device: hashtree-loop");
262 }
263 
TEST(MountedApexDataTest,NoDuplicateLoopHashtreeAndDataLoopDevices)264 TEST(MountedApexDataTest, NoDuplicateLoopHashtreeAndDataLoopDevices) {
265   ASSERT_DEATH(
266       {
267         MountedApexDatabase db;
268         db.AddMountedApex("package", false, "loop", "path", "mount", "dm",
269                           "hashtree-loop1");
270         db.AddMountedApex("package2", false, "loop2", "path2", "mount2", "dm2",
271                           "loop");
272       },
273       "Duplicate loop device: loop");
274 }
275 
TEST(MountedApexDataTest,NoDuplicateDm)276 TEST(MountedApexDataTest, NoDuplicateDm) {
277   ASSERT_DEATH(
278       {
279         MountedApexDatabase db;
280         db.AddMountedApex("package", false, "loop", "path", "mount", "dm",
281                           /* hashtree_loop_name= */ "");
282         db.AddMountedApex("package2", false, "loop2", "path2", "mount2", "dm",
283                           /* hashtree_loop_name= */ "");
284       },
285       "Duplicate dm device: dm");
286 }
287 
288 #pragma clang diagnostic pop
289 
290 }  // namespace
291 }  // namespace apex
292 }  // namespace android
293