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 "snapshot_metadata_updater.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include <android-base/properties.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <liblp/builder.h>
26 #include <storage_literals/storage_literals.h>
27 
28 #include <libsnapshot/test_helpers.h>
29 
30 using namespace android::storage_literals;
31 using android::fs_mgr::LpMetadata;
32 using android::fs_mgr::MetadataBuilder;
33 using android::fs_mgr::SlotSuffixForSlotNumber;
34 using chromeos_update_engine::DeltaArchiveManifest;
35 using chromeos_update_engine::DynamicPartitionGroup;
36 using chromeos_update_engine::PartitionUpdate;
37 using testing::AssertionFailure;
38 using testing::AssertionResult;
39 using testing::AssertionSuccess;
40 
41 namespace android {
42 namespace snapshot {
43 
44 class SnapshotMetadataUpdaterTest : public ::testing::TestWithParam<uint32_t> {
45   public:
46     SnapshotMetadataUpdaterTest() = default;
47 
SetUp()48     void SetUp() override {
49         SKIP_IF_NON_VIRTUAL_AB();
50 
51         target_slot_ = GetParam();
52         target_suffix_ = SlotSuffixForSlotNumber(target_slot_);
53         SnapshotTestPropertyFetcher::SetUp(SlotSuffixForSlotNumber(1 - target_slot_));
54         builder_ = MetadataBuilder::New(4_GiB + 1_MiB, 4_KiB, 2);
55 
56         group_ = manifest_.mutable_dynamic_partition_metadata()->add_groups();
57         group_->set_name("group");
58         group_->set_size(4_GiB);
59         group_->add_partition_names("system");
60         group_->add_partition_names("vendor");
61         system_ = manifest_.add_partitions();
62         system_->set_partition_name("system");
63         SetSize(system_, 2_GiB);
64         vendor_ = manifest_.add_partitions();
65         vendor_->set_partition_name("vendor");
66         SetSize(vendor_, 1_GiB);
67 
68         ASSERT_TRUE(FillFakeMetadata(builder_.get(), manifest_, target_suffix_));
69     }
70 
TearDown()71     void TearDown() override {
72         RETURN_IF_NON_VIRTUAL_AB();
73 
74         SnapshotTestPropertyFetcher::TearDown();
75     }
76 
77     // Append suffix to name.
T(std::string_view name)78     std::string T(std::string_view name) { return std::string(name) + target_suffix_; }
79 
UpdateAndExport()80     AssertionResult UpdateAndExport() {
81         SnapshotMetadataUpdater updater(builder_.get(), target_slot_, manifest_);
82         if (!updater.Update()) {
83             return AssertionFailure() << "Update failed.";
84         }
85 
86         exported_ = builder_->Export();
87         if (exported_ == nullptr) {
88             return AssertionFailure() << "Export failed.";
89         }
90         return AssertionSuccess();
91     }
92 
93     // Check that in |builder_|, partition |name| + |target_suffix_| has the given |size|.
CheckSize(std::string_view name,uint64_t size)94     AssertionResult CheckSize(std::string_view name, uint64_t size) {
95         auto p = builder_->FindPartition(T(name));
96         if (p == nullptr) {
97             return AssertionFailure() << "Cannot find partition " << T(name);
98         }
99         if (p->size() != size) {
100             return AssertionFailure() << "Partition " << T(name) << " should be " << size
101                                       << " bytes, but is " << p->size() << " bytes.";
102         }
103         return AssertionSuccess() << "Partition" << T(name) << " is " << size << " bytes.";
104     }
105 
106     // Check that in |builder_|, group |name| + |target_suffix_| has the given |size|.
CheckGroupSize(std::string_view name,uint64_t size)107     AssertionResult CheckGroupSize(std::string_view name, uint64_t size) {
108         auto g = builder_->FindGroup(T(name));
109         if (g == nullptr) {
110             return AssertionFailure() << "Cannot find group " << T(name);
111         }
112         if (g->maximum_size() != size) {
113             return AssertionFailure() << "Group " << T(name) << " should be " << size
114                                       << " bytes, but is " << g->maximum_size() << " bytes.";
115         }
116         return AssertionSuccess() << "Group" << T(name) << " is " << size << " bytes.";
117     }
118 
119     // Check that in |builder_|, partition |partition_name| + |target_suffix_| is in group
120     // |group_name| + |target_suffix_|;
CheckGroupName(std::string_view partition_name,std::string_view group_name)121     AssertionResult CheckGroupName(std::string_view partition_name, std::string_view group_name) {
122         auto p = builder_->FindPartition(T(partition_name));
123         if (p == nullptr) {
124             return AssertionFailure() << "Cannot find partition " << T(partition_name);
125         }
126         if (p->group_name() != T(group_name)) {
127             return AssertionFailure() << "Partition " << T(partition_name) << " should be in "
128                                       << T(group_name) << ", but is in " << p->group_name() << ".";
129         }
130         return AssertionSuccess() << "Partition" << T(partition_name) << " is in " << T(group_name)
131                                   << ".";
132     }
133 
134     std::unique_ptr<MetadataBuilder> builder_;
135     uint32_t target_slot_;
136     std::string target_suffix_;
137     DeltaArchiveManifest manifest_;
138     std::unique_ptr<LpMetadata> exported_;
139     DynamicPartitionGroup* group_ = nullptr;
140     PartitionUpdate* system_ = nullptr;
141     PartitionUpdate* vendor_ = nullptr;
142 };
143 
TEST_P(SnapshotMetadataUpdaterTest,NoChange)144 TEST_P(SnapshotMetadataUpdaterTest, NoChange) {
145     EXPECT_TRUE(UpdateAndExport());
146 
147     EXPECT_TRUE(CheckGroupSize("group", 4_GiB));
148     EXPECT_TRUE(CheckSize("system", 2_GiB));
149     EXPECT_TRUE(CheckGroupName("system", "group"));
150     EXPECT_TRUE(CheckSize("vendor", 1_GiB));
151     EXPECT_TRUE(CheckGroupName("vendor", "group"));
152 }
153 
TEST_P(SnapshotMetadataUpdaterTest,GrowWithinBounds)154 TEST_P(SnapshotMetadataUpdaterTest, GrowWithinBounds) {
155     SetSize(system_, 2_GiB + 512_MiB);
156     SetSize(vendor_, 1_GiB + 512_MiB);
157 
158     ASSERT_TRUE(UpdateAndExport());
159 
160     EXPECT_TRUE(CheckSize("system", 2_GiB + 512_MiB));
161     EXPECT_TRUE(CheckSize("vendor", 1_GiB + 512_MiB));
162 }
163 
TEST_P(SnapshotMetadataUpdaterTest,GrowOverSuper)164 TEST_P(SnapshotMetadataUpdaterTest, GrowOverSuper) {
165     SetSize(system_, 3_GiB);
166     SetSize(vendor_, 1_GiB + 512_MiB);
167 
168     EXPECT_FALSE(UpdateAndExport());
169 }
170 
TEST_P(SnapshotMetadataUpdaterTest,GrowOverGroup)171 TEST_P(SnapshotMetadataUpdaterTest, GrowOverGroup) {
172     SetSize(system_, 3_GiB);
173     SetSize(vendor_, 1_GiB + 4_KiB);
174 
175     EXPECT_FALSE(UpdateAndExport());
176 }
177 
TEST_P(SnapshotMetadataUpdaterTest,Add)178 TEST_P(SnapshotMetadataUpdaterTest, Add) {
179     group_->add_partition_names("product");
180     auto product = manifest_.add_partitions();
181     product->set_partition_name("product");
182     SetSize(product, 1_GiB);
183 
184     EXPECT_TRUE(UpdateAndExport());
185 
186     EXPECT_TRUE(CheckSize("system", 2_GiB));
187     EXPECT_TRUE(CheckSize("vendor", 1_GiB));
188     EXPECT_TRUE(CheckSize("product", 1_GiB));
189 }
190 
TEST_P(SnapshotMetadataUpdaterTest,AddTooBig)191 TEST_P(SnapshotMetadataUpdaterTest, AddTooBig) {
192     group_->add_partition_names("product");
193     auto product = manifest_.add_partitions();
194     product->set_partition_name("product");
195     SetSize(product, 1_GiB + 4_KiB);
196 
197     EXPECT_FALSE(UpdateAndExport());
198 }
199 
TEST_P(SnapshotMetadataUpdaterTest,ShrinkAll)200 TEST_P(SnapshotMetadataUpdaterTest, ShrinkAll) {
201     SetSize(system_, 1_GiB);
202     SetSize(vendor_, 512_MiB);
203 
204     ASSERT_TRUE(UpdateAndExport());
205 
206     EXPECT_TRUE(CheckSize("system", 1_GiB));
207     EXPECT_TRUE(CheckSize("vendor", 512_MiB));
208 }
209 
TEST_P(SnapshotMetadataUpdaterTest,ShrinkAndGrow)210 TEST_P(SnapshotMetadataUpdaterTest, ShrinkAndGrow) {
211     SetSize(system_, 3_GiB + 512_MiB);
212     SetSize(vendor_, 512_MiB);
213 
214     ASSERT_TRUE(UpdateAndExport());
215 
216     EXPECT_TRUE(CheckSize("system", 3_GiB + 512_MiB));
217     EXPECT_TRUE(CheckSize("vendor", 512_MiB));
218 }
219 
TEST_P(SnapshotMetadataUpdaterTest,ShrinkAndAdd)220 TEST_P(SnapshotMetadataUpdaterTest, ShrinkAndAdd) {
221     SetSize(system_, 2_GiB);
222     SetSize(vendor_, 512_MiB);
223     group_->add_partition_names("product");
224     auto product = manifest_.add_partitions();
225     product->set_partition_name("product");
226     SetSize(product, 1_GiB + 512_MiB);
227 
228     ASSERT_TRUE(UpdateAndExport());
229 
230     EXPECT_TRUE(CheckSize("system", 2_GiB));
231     EXPECT_TRUE(CheckSize("vendor", 512_MiB));
232     EXPECT_TRUE(CheckSize("product", 1_GiB + 512_MiB));
233 }
234 
TEST_P(SnapshotMetadataUpdaterTest,Delete)235 TEST_P(SnapshotMetadataUpdaterTest, Delete) {
236     group_->mutable_partition_names()->RemoveLast();
237     // No need to delete it from manifest.partitions as SnapshotMetadataUpdater
238     // should ignore them (treat them as static partitions).
239 
240     EXPECT_TRUE(UpdateAndExport());
241 
242     EXPECT_TRUE(CheckSize("system", 2_GiB));
243     EXPECT_EQ(nullptr, builder_->FindPartition(T("vendor")));
244 }
245 
TEST_P(SnapshotMetadataUpdaterTest,DeleteAndGrow)246 TEST_P(SnapshotMetadataUpdaterTest, DeleteAndGrow) {
247     group_->mutable_partition_names()->RemoveLast();
248     SetSize(system_, 4_GiB);
249 
250     EXPECT_TRUE(UpdateAndExport());
251 
252     EXPECT_TRUE(CheckSize("system", 4_GiB));
253 }
254 
TEST_P(SnapshotMetadataUpdaterTest,DeleteAndAdd)255 TEST_P(SnapshotMetadataUpdaterTest, DeleteAndAdd) {
256     group_->mutable_partition_names()->RemoveLast();
257     group_->add_partition_names("product");
258     auto product = manifest_.add_partitions();
259     product->set_partition_name("product");
260     SetSize(product, 2_GiB);
261 
262     EXPECT_TRUE(UpdateAndExport());
263 
264     EXPECT_TRUE(CheckSize("system", 2_GiB));
265     EXPECT_EQ(nullptr, builder_->FindPartition(T("vendor")));
266     EXPECT_TRUE(CheckSize("product", 2_GiB));
267 }
268 
TEST_P(SnapshotMetadataUpdaterTest,GrowGroup)269 TEST_P(SnapshotMetadataUpdaterTest, GrowGroup) {
270     group_->set_size(4_GiB + 512_KiB);
271     SetSize(system_, 2_GiB + 256_KiB);
272     SetSize(vendor_, 2_GiB + 256_KiB);
273 
274     EXPECT_TRUE(UpdateAndExport());
275 
276     EXPECT_TRUE(CheckSize("system", 2_GiB + 256_KiB));
277     EXPECT_TRUE(CheckSize("vendor", 2_GiB + 256_KiB));
278 }
279 
TEST_P(SnapshotMetadataUpdaterTest,ShrinkGroup)280 TEST_P(SnapshotMetadataUpdaterTest, ShrinkGroup) {
281     group_->set_size(1_GiB);
282     SetSize(system_, 512_MiB);
283     SetSize(vendor_, 512_MiB);
284 
285     EXPECT_TRUE(UpdateAndExport());
286 
287     EXPECT_TRUE(CheckSize("system", 512_MiB));
288     EXPECT_TRUE(CheckSize("vendor", 512_MiB));
289 }
290 
TEST_P(SnapshotMetadataUpdaterTest,MoveToNewGroup)291 TEST_P(SnapshotMetadataUpdaterTest, MoveToNewGroup) {
292     group_->mutable_partition_names()->RemoveLast();
293     group_->set_size(2_GiB);
294 
295     auto another_group = manifest_.mutable_dynamic_partition_metadata()->add_groups();
296     another_group->set_name("another_group");
297     another_group->set_size(2_GiB);
298     another_group->add_partition_names("vendor");
299     SetSize(vendor_, 2_GiB);
300 
301     EXPECT_TRUE(UpdateAndExport());
302 
303     EXPECT_TRUE(CheckGroupSize("group", 2_GiB));
304     EXPECT_TRUE(CheckGroupSize("another_group", 2_GiB));
305     EXPECT_TRUE(CheckSize("system", 2_GiB));
306     EXPECT_TRUE(CheckGroupName("system", "group"));
307     EXPECT_TRUE(CheckSize("vendor", 2_GiB));
308     EXPECT_TRUE(CheckGroupName("vendor", "another_group"));
309 }
310 
TEST_P(SnapshotMetadataUpdaterTest,DeleteAndAddGroup)311 TEST_P(SnapshotMetadataUpdaterTest, DeleteAndAddGroup) {
312     manifest_.mutable_dynamic_partition_metadata()->mutable_groups()->RemoveLast();
313     group_ = nullptr;
314 
315     auto another_group = manifest_.mutable_dynamic_partition_metadata()->add_groups();
316     another_group->set_name("another_group");
317     another_group->set_size(4_GiB);
318     another_group->add_partition_names("system");
319     another_group->add_partition_names("vendor");
320     another_group->add_partition_names("product");
321     auto product = manifest_.add_partitions();
322     product->set_partition_name("product");
323     SetSize(product, 1_GiB);
324 
325     EXPECT_TRUE(UpdateAndExport());
326 
327     EXPECT_EQ(nullptr, builder_->FindGroup(T("group")));
328     EXPECT_TRUE(CheckGroupSize("another_group", 4_GiB));
329     EXPECT_TRUE(CheckSize("system", 2_GiB));
330     EXPECT_TRUE(CheckGroupName("system", "another_group"));
331     EXPECT_TRUE(CheckSize("vendor", 1_GiB));
332     EXPECT_TRUE(CheckGroupName("vendor", "another_group"));
333     EXPECT_TRUE(CheckSize("product", 1_GiB));
334     EXPECT_TRUE(CheckGroupName("product", "another_group"));
335 }
336 
337 INSTANTIATE_TEST_SUITE_P(Snapshot, SnapshotMetadataUpdaterTest, testing::Values(0, 1));
338 
339 }  // namespace snapshot
340 }  // namespace android
341