xref: /aosp_15_r20/system/apex/apexd/apex_database_test.cpp (revision 33f3758387333dbd2962d7edbd98681940d895da)
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 "apex_database.h"
18 
19 #include <android-base/macros.h>
20 #include <android-base/result-gmock.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 
24 #include <string>
25 #include <tuple>
26 
27 using android::base::Error;
28 using android::base::Result;
29 using android::base::testing::HasError;
30 using android::base::testing::Ok;
31 using android::base::testing::WithMessage;
32 
33 namespace android {
34 namespace apex {
35 namespace {
36 
37 using MountedApexData = MountedApexDatabase::MountedApexData;
38 
CountPackages(const MountedApexDatabase & db)39 size_t CountPackages(const MountedApexDatabase& db) {
40   size_t ret = 0;
41   db.ForallMountedApexes([&ret](const std::string& a ATTRIBUTE_UNUSED,
42                                 const MountedApexData& b ATTRIBUTE_UNUSED,
43                                 bool c ATTRIBUTE_UNUSED) { ++ret; });
44   return ret;
45 }
46 
Contains(const MountedApexDatabase & db,const std::string & package,const MountedApexData & data)47 bool Contains(const MountedApexDatabase& db, const std::string& package,
48               const MountedApexData& data) {
49   bool found = false;
50   db.ForallMountedApexes([&](const std::string& p, const MountedApexData& d,
51                              bool b ATTRIBUTE_UNUSED) {
52     if (package == p && data == d) {
53       found = true;
54     }
55   });
56   return found;
57 }
58 
ContainsPackage(const MountedApexDatabase & db,const std::string & package,const MountedApexData & data)59 bool ContainsPackage(const MountedApexDatabase& db, const std::string& package,
60                      const MountedApexData& data) {
61   bool found = false;
62   db.ForallMountedApexes(
63       package, [&](const MountedApexData& d, bool b ATTRIBUTE_UNUSED) {
64         if (data == d) {
65           found = true;
66         }
67       });
68   return found;
69 }
70 
TEST(ApexDatabaseTest,AddRemovedMountedApex)71 TEST(ApexDatabaseTest, AddRemovedMountedApex) {
72   constexpr const char* kPackage = "package";
73   constexpr const char* kLoopName = "loop";
74   constexpr const char* kPath = "path";
75   constexpr const char* kMountPoint = "mount";
76   constexpr const char* kDeviceName = "dev";
77 
78   MountedApexDatabase db;
79   ASSERT_EQ(CountPackages(db), 0u);
80 
81   MountedApexData data(0, kLoopName, kPath, kMountPoint, kDeviceName);
82   db.AddMountedApex(kPackage, data);
83   ASSERT_TRUE(Contains(db, kPackage, data));
84   ASSERT_TRUE(ContainsPackage(db, kPackage, data));
85 
86   db.RemoveMountedApex(kPackage, kPath);
87   EXPECT_FALSE(Contains(db, kPackage, data));
88   EXPECT_FALSE(ContainsPackage(db, kPackage, data));
89 }
90 
TEST(ApexDatabaseTest,MountMultiple)91 TEST(ApexDatabaseTest, MountMultiple) {
92   constexpr const char* kPackage[] = {"package", "package", "package",
93                                       "package"};
94   constexpr const char* kLoopName[] = {"loop", "loop2", "loop3", "loop4"};
95   constexpr const char* kPath[] = {"path", "path2", "path", "path4"};
96   constexpr const char* kMountPoint[] = {"mount", "mount2", "mount", "mount4"};
97   constexpr const char* kDeviceName[] = {"dev", "dev2", "dev3", "dev4"};
98 
99   MountedApexDatabase db;
100   ASSERT_EQ(CountPackages(db), 0u);
101 
102   MountedApexData data[arraysize(kPackage)];
103   for (size_t i = 0; i < arraysize(kPackage); ++i) {
104     data[i] = MountedApexData(0, kLoopName[i], kPath[i], kMountPoint[i],
105                               kDeviceName[i]);
106     db.AddMountedApex(kPackage[i], data[i]);
107   }
108 
109   ASSERT_EQ(CountPackages(db), 4u);
110   for (size_t i = 0; i < arraysize(kPackage); ++i) {
111     ASSERT_TRUE(Contains(db, kPackage[i], data[i]));
112     ASSERT_TRUE(ContainsPackage(db, kPackage[i], data[i]));
113   }
114 
115   db.RemoveMountedApex(kPackage[0], kPath[0]);
116   EXPECT_FALSE(Contains(db, kPackage[0], data[0]));
117   EXPECT_FALSE(ContainsPackage(db, kPackage[0], data[0]));
118   EXPECT_TRUE(Contains(db, kPackage[1], data[1]));
119   EXPECT_TRUE(ContainsPackage(db, kPackage[1], data[1]));
120   EXPECT_TRUE(Contains(db, kPackage[2], data[2]));
121   EXPECT_TRUE(ContainsPackage(db, kPackage[2], data[2]));
122   EXPECT_TRUE(Contains(db, kPackage[3], data[3]));
123   EXPECT_TRUE(ContainsPackage(db, kPackage[3], data[3]));
124 }
125 
TEST(ApexDatabaseTest,DoIfLatest)126 TEST(ApexDatabaseTest, DoIfLatest) {
127   // Check by passing error-returning handler
128   // When handler is triggered, DoIfLatest() returns the expected error.
129   auto returnError = []() -> Result<void> { return Error() << "expected"; };
130 
131   MountedApexDatabase db;
132 
133   // With apex: [{version=0,path=path}]
134   db.AddMountedApex("package", 0, "loop", "path", "mount", "dev");
135   ASSERT_THAT(db.DoIfLatest("package", "path", returnError),
136               HasError(WithMessage("expected")));
137 
138   // With apexes: [{version=0,path=path}, {version=5,path=path5}]
139   db.AddMountedApex("package", 5, "loop5", "path5", "mount5", "dev5");
140   ASSERT_THAT(db.DoIfLatest("package", "path", returnError), Ok());
141   ASSERT_THAT(db.DoIfLatest("package", "path5", returnError),
142               HasError(WithMessage("expected")));
143 }
144 
TEST(ApexDatabaseTest,GetLatestMountedApex)145 TEST(ApexDatabaseTest, GetLatestMountedApex) {
146   constexpr const char* kPackage = "package";
147   constexpr const char* kLoopName = "loop";
148   constexpr const char* kPath = "path";
149   constexpr const char* kMountPoint = "mount";
150   constexpr const char* kDeviceName = "dev";
151 
152   MountedApexDatabase db;
153   ASSERT_EQ(CountPackages(db), 0u);
154 
155   MountedApexData data(0, kLoopName, kPath, kMountPoint, kDeviceName);
156   db.AddMountedApex(kPackage, data);
157 
158   auto ret = db.GetLatestMountedApex(kPackage);
159   ASSERT_TRUE(ret.has_value());
160   ASSERT_EQ(ret.value(), data);
161 }
162 
TEST(ApexDatabaseTest,GetLatestMountedApexReturnsNullopt)163 TEST(ApexDatabaseTest, GetLatestMountedApexReturnsNullopt) {
164   MountedApexDatabase db;
165   auto ret = db.GetLatestMountedApex("no-such-name");
166   ASSERT_FALSE(ret.has_value());
167 }
168 
169 #pragma clang diagnostic push
170 // error: 'ReturnSentinel' was marked unused but was used
171 // [-Werror,-Wused-but-marked-unused]
172 #pragma clang diagnostic ignored "-Wused-but-marked-unused"
173 
TEST(MountedApexDataTest,NoDuplicateLoopDataLoopDevices)174 TEST(MountedApexDataTest, NoDuplicateLoopDataLoopDevices) {
175   ASSERT_DEATH(
176       {
177         MountedApexDatabase db;
178         db.AddMountedApex("package", 0, "loop", "path", "mount", "dm");
179         db.AddMountedApex("package2", 0, "loop", "path2", "mount2", "dm2");
180       },
181       "Duplicate loop device: loop");
182 }
183 
TEST(MountedApexDataTest,NoDuplicateDm)184 TEST(MountedApexDataTest, NoDuplicateDm) {
185   ASSERT_DEATH(
186       {
187         MountedApexDatabase db;
188         db.AddMountedApex("package", 0, "loop", "path", "mount", "dm");
189         db.AddMountedApex("package2", 0, "loop2", "path2", "mount2", "dm");
190       },
191       "Duplicate dm device: dm");
192 }
193 
194 #pragma clang diagnostic pop
195 
196 }  // namespace
197 }  // namespace apex
198 }  // namespace android
199