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