blob: 6460ffec31f5c204acd77d6f549512cedc6d7d8b [file] [log] [blame]
Yifan Hong537802d2018-08-15 13:15:42 -07001//
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 "update_engine/boot_control_android.h"
18
19#include <set>
Yifan Hongd4db07e2018-10-18 17:46:27 -070020#include <vector>
Yifan Hong537802d2018-08-15 13:15:42 -070021
Yifan Hongd4db07e2018-10-18 17:46:27 -070022#include <base/logging.h>
23#include <base/strings/string_util.h>
David Andersond63cb3c2018-10-01 14:15:00 -070024#include <fs_mgr.h>
Yifan Hong537802d2018-08-15 13:15:42 -070025#include <gmock/gmock.h>
26#include <gtest/gtest.h>
27
28#include "update_engine/mock_boot_control_hal.h"
29#include "update_engine/mock_dynamic_partition_control.h"
30
Yifan Hong537802d2018-08-15 13:15:42 -070031using android::fs_mgr::MetadataBuilder;
32using android::hardware::Void;
33using testing::_;
34using testing::AnyNumber;
35using testing::Contains;
36using testing::Eq;
37using testing::Invoke;
38using testing::Key;
39using testing::MakeMatcher;
40using testing::Matcher;
41using testing::MatcherInterface;
42using testing::MatchResultListener;
43using testing::NiceMock;
Yifan Hongd4db07e2018-10-18 17:46:27 -070044using testing::Not;
Yifan Hong537802d2018-08-15 13:15:42 -070045using testing::Return;
46
47namespace chromeos_update_engine {
48
49constexpr const uint32_t kMaxNumSlots = 2;
50constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
51constexpr const char* kFakeDevicePath = "/fake/dev/path/";
52constexpr const char* kFakeMappedPath = "/fake/mapped/path/";
53constexpr const uint32_t kFakeMetadataSize = 65536;
Yifan Hongd4db07e2018-10-18 17:46:27 -070054constexpr const char* kDefaultGroup = "foo";
55
56// "vendor"
57struct PartitionName : std::string {
58 using std::string::string;
59};
60
61// "vendor_a"
62struct PartitionNameSuffix : std::string {
63 using std::string::string;
64};
Yifan Hong537802d2018-08-15 13:15:42 -070065
66// A map describing the size of each partition.
Yifan Hongd4db07e2018-10-18 17:46:27 -070067using PartitionSizes = std::map<PartitionName, uint64_t>;
68using PartitionSuffixSizes = std::map<PartitionNameSuffix, uint64_t>;
69
70using PartitionMetadata = BootControlInterface::PartitionMetadata;
Yifan Hong537802d2018-08-15 13:15:42 -070071
72// C++ standards do not allow uint64_t (aka unsigned long) to be the parameter
73// of user-defined literal operators.
Yifan Hongd4db07e2018-10-18 17:46:27 -070074constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
Yifan Hong537802d2018-08-15 13:15:42 -070075 return x << 20;
76}
Yifan Hongd4db07e2018-10-18 17:46:27 -070077constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
Yifan Hong537802d2018-08-15 13:15:42 -070078 return x << 30;
79}
80
Yifan Hongd4db07e2018-10-18 17:46:27 -070081constexpr uint64_t kDefaultGroupSize = 5_GiB;
82// Super device size. 1 MiB for metadata.
83constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
84
Yifan Hong537802d2018-08-15 13:15:42 -070085template <typename U, typename V>
86std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
87 os << "{";
88 bool first = true;
89 for (const auto& pair : param) {
90 if (!first)
91 os << ", ";
92 os << pair.first << ":" << pair.second;
93 first = false;
94 }
95 return os << "}";
96}
97
Yifan Hongd4db07e2018-10-18 17:46:27 -070098template <typename T>
99std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
100 os << "[";
101 bool first = true;
102 for (const auto& e : param) {
103 if (!first)
104 os << ", ";
105 os << e;
106 first = false;
107 }
108 return os << "]";
109}
110
111std::ostream& operator<<(std::ostream& os,
112 const PartitionMetadata::Partition& p) {
113 return os << "{" << p.name << ", " << p.size << "}";
114}
115
116std::ostream& operator<<(std::ostream& os, const PartitionMetadata::Group& g) {
117 return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
118}
119
120std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
121 return os << m.groups;
122}
123
Yifan Hong537802d2018-08-15 13:15:42 -0700124inline std::string GetDevice(const std::string& name) {
125 return kFakeDevicePath + name;
126}
127inline std::string GetSuperDevice() {
David Andersond63cb3c2018-10-01 14:15:00 -0700128 return GetDevice(fs_mgr_get_super_partition_name());
Yifan Hong537802d2018-08-15 13:15:42 -0700129}
130
131struct TestParam {
132 uint32_t source;
133 uint32_t target;
134};
135std::ostream& operator<<(std::ostream& os, const TestParam& param) {
136 return os << "{source: " << param.source << ", target:" << param.target
137 << "}";
138}
139
Yifan Hongd4db07e2018-10-18 17:46:27 -0700140// To support legacy tests, auto-convert {name_a: size} map to
141// PartitionMetadata.
142PartitionMetadata toMetadata(const PartitionSuffixSizes& partition_sizes) {
143 PartitionMetadata metadata;
144 for (const char* suffix : kSlotSuffixes) {
145 metadata.groups.push_back(
146 {std::string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
147 }
148 for (const auto& pair : partition_sizes) {
149 for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
150 if (base::EndsWith(pair.first,
151 kSlotSuffixes[suffix_idx],
152 base::CompareCase::SENSITIVE)) {
153 metadata.groups[suffix_idx].partitions.push_back(
154 {pair.first, pair.second});
155 }
156 }
157 }
158 return metadata;
159}
160
161// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
162PartitionMetadata toMetadata(const PartitionSizes& partition_sizes) {
163 PartitionMetadata metadata;
164 metadata.groups.push_back(
165 {std::string{kDefaultGroup}, kDefaultGroupSize, {}});
166 for (const auto& pair : partition_sizes) {
167 metadata.groups[0].partitions.push_back({pair.first, pair.second});
168 }
169 return metadata;
170}
171
172std::unique_ptr<MetadataBuilder> NewFakeMetadata(
173 const PartitionMetadata& metadata) {
174 auto builder =
175 MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
176 EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
Yifan Hong537802d2018-08-15 13:15:42 -0700177 EXPECT_NE(nullptr, builder);
178 if (builder == nullptr)
179 return nullptr;
Yifan Hongd4db07e2018-10-18 17:46:27 -0700180 for (const auto& group : metadata.groups) {
181 EXPECT_TRUE(builder->AddGroup(group.name, group.size));
182 for (const auto& partition : group.partitions) {
183 auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
184 EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
185 }
Yifan Hong537802d2018-08-15 13:15:42 -0700186 }
187 return builder;
188}
189
190class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
191 public:
Yifan Hongd4db07e2018-10-18 17:46:27 -0700192 explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
193 : partition_metadata_(toMetadata(partition_sizes)) {}
194 explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
195 : partition_metadata_(partition_metadata) {}
196
Yifan Hong537802d2018-08-15 13:15:42 -0700197 bool MatchAndExplain(MetadataBuilder* metadata,
198 MatchResultListener* listener) const override {
199 bool success = true;
Yifan Hongd4db07e2018-10-18 17:46:27 -0700200 for (const auto& group : partition_metadata_.groups) {
201 for (const auto& partition : group.partitions) {
202 auto p = metadata->FindPartition(partition.name);
203 if (p == nullptr) {
204 if (!success)
205 *listener << "; ";
206 *listener << "No partition " << partition.name;
207 success = false;
208 continue;
209 }
210 if (p->size() != partition.size) {
211 if (!success)
212 *listener << "; ";
213 *listener << "Partition " << partition.name << " has size "
214 << p->size() << ", expected " << partition.size;
215 success = false;
216 }
217 if (p->group_name() != group.name) {
218 if (!success)
219 *listener << "; ";
220 *listener << "Partition " << partition.name << " has group "
221 << p->group_name() << ", expected " << group.name;
222 success = false;
223 }
Yifan Hong537802d2018-08-15 13:15:42 -0700224 }
225 }
226 return success;
227 }
228
229 void DescribeTo(std::ostream* os) const override {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700230 *os << "expect: " << partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700231 }
232
233 void DescribeNegationTo(std::ostream* os) const override {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700234 *os << "expect not: " << partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700235 }
236
237 private:
Yifan Hongd4db07e2018-10-18 17:46:27 -0700238 PartitionMetadata partition_metadata_;
Yifan Hong537802d2018-08-15 13:15:42 -0700239};
240
241inline Matcher<MetadataBuilder*> MetadataMatches(
Yifan Hongd4db07e2018-10-18 17:46:27 -0700242 const PartitionSuffixSizes& partition_sizes) {
Yifan Hong537802d2018-08-15 13:15:42 -0700243 return MakeMatcher(new MetadataMatcher(partition_sizes));
244}
245
Yifan Hongd4db07e2018-10-18 17:46:27 -0700246inline Matcher<MetadataBuilder*> MetadataMatches(
247 const PartitionMetadata& partition_metadata) {
248 return MakeMatcher(new MetadataMatcher(partition_metadata));
249}
250
251MATCHER_P(HasGroup, group, " has group " + group) {
252 auto groups = arg->ListGroups();
253 return std::find(groups.begin(), groups.end(), group) != groups.end();
254}
255
Yifan Hong537802d2018-08-15 13:15:42 -0700256class BootControlAndroidTest : public ::testing::Test {
257 protected:
258 void SetUp() override {
259 // Fake init bootctl_
260 bootctl_.module_ = new NiceMock<MockBootControlHal>();
261 bootctl_.dynamic_control_ =
262 std::make_unique<NiceMock<MockDynamicPartitionControl>>();
263
264 ON_CALL(module(), getNumberSlots()).WillByDefault(Invoke([] {
265 return kMaxNumSlots;
266 }));
267 ON_CALL(module(), getSuffix(_, _))
268 .WillByDefault(Invoke([](auto slot, auto cb) {
269 EXPECT_LE(slot, kMaxNumSlots);
270 cb(slot < kMaxNumSlots ? kSlotSuffixes[slot] : "");
271 return Void();
272 }));
273
274 ON_CALL(dynamicControl(), IsDynamicPartitionsEnabled())
275 .WillByDefault(Return(true));
276 ON_CALL(dynamicControl(), GetDeviceDir(_))
277 .WillByDefault(Invoke([](auto path) {
278 *path = kFakeDevicePath;
279 return true;
280 }));
281 }
282
283 // Return the mocked HAL module.
284 NiceMock<MockBootControlHal>& module() {
285 return static_cast<NiceMock<MockBootControlHal>&>(*bootctl_.module_);
286 }
287
288 // Return the mocked DynamicPartitionControlInterface.
289 NiceMock<MockDynamicPartitionControl>& dynamicControl() {
290 return static_cast<NiceMock<MockDynamicPartitionControl>&>(
291 *bootctl_.dynamic_control_);
292 }
293
294 // Set the fake metadata to return when LoadMetadataBuilder is called on
295 // |slot|.
Yifan Hongd4db07e2018-10-18 17:46:27 -0700296 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
297 SetMetadata(slot, toMetadata(sizes));
298 }
299
300 void SetMetadata(uint32_t slot, const PartitionMetadata& metadata) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800301 EXPECT_CALL(dynamicControl(),
302 LoadMetadataBuilder(GetSuperDevice(), slot, _))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700303 .Times(AnyNumber())
Yifan Hong6e706b12018-11-09 16:50:51 -0800304 .WillRepeatedly(Invoke([metadata](auto, auto, auto) {
305 return NewFakeMetadata(metadata);
306 }));
Yifan Hong537802d2018-08-15 13:15:42 -0700307 }
308
309 // Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
310 // with each partition in |partitions|.
Yifan Hongaf65ef12018-10-29 11:09:06 -0700311 void ExpectMap(const std::set<std::string>& partitions,
312 bool force_writable = true) {
Yifan Hong537802d2018-08-15 13:15:42 -0700313 // Error when MapPartitionOnDeviceMapper is called on unknown arguments.
Yifan Hongaf65ef12018-10-29 11:09:06 -0700314 ON_CALL(dynamicControl(), MapPartitionOnDeviceMapper(_, _, _, _, _))
Yifan Hong537802d2018-08-15 13:15:42 -0700315 .WillByDefault(Return(false));
316
317 for (const auto& partition : partitions) {
Yifan Hongaf65ef12018-10-29 11:09:06 -0700318 EXPECT_CALL(dynamicControl(),
319 MapPartitionOnDeviceMapper(
320 GetSuperDevice(), partition, target(), force_writable, _))
321 .WillOnce(Invoke([this](auto, auto partition, auto, auto, auto path) {
Yifan Hong537802d2018-08-15 13:15:42 -0700322 auto it = mapped_devices_.find(partition);
323 if (it != mapped_devices_.end()) {
324 *path = it->second;
325 return true;
326 }
327 mapped_devices_[partition] = *path = kFakeMappedPath + partition;
328 return true;
329 }));
330 }
331 }
332
333 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
334 // slot with each partition in |partitions|.
335 void ExpectUnmap(const std::set<std::string>& partitions) {
336 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
337 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
338 .WillByDefault(Return(false));
339
340 for (const auto& partition : partitions) {
341 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
342 .WillOnce(Invoke([this](auto partition, auto) {
343 mapped_devices_.erase(partition);
344 return true;
345 }));
346 }
347 }
348
349 void ExpectRemap(const std::set<std::string>& partitions) {
350 ExpectUnmap(partitions);
351 ExpectMap(partitions);
352 }
353
354 void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
355 ASSERT_EQ(partitions.size(), mapped_devices_.size());
356 for (const auto& partition : partitions) {
357 EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
358 << "Expect that " << partition << " is mapped, but it is not.";
359 }
360 }
361
Yifan Hongd4db07e2018-10-18 17:46:27 -0700362 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
Yifan Hong549eb362018-10-19 15:11:12 -0700363 ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
364 }
365
366 virtual void ExpectStoreMetadataMatch(
367 const Matcher<MetadataBuilder*>& matcher) {
368 EXPECT_CALL(dynamicControl(),
369 StoreMetadata(GetSuperDevice(), matcher, target()))
370 .WillOnce(Return(true));
371 }
372
Yifan Hong537802d2018-08-15 13:15:42 -0700373 uint32_t source() { return slots_.source; }
374
375 uint32_t target() { return slots_.target; }
376
377 // Return partition names with suffix of source().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700378 PartitionNameSuffix S(const std::string& name) {
379 return PartitionNameSuffix(name + std::string(kSlotSuffixes[source()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700380 }
381
382 // Return partition names with suffix of target().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700383 PartitionNameSuffix T(const std::string& name) {
384 return PartitionNameSuffix(name + std::string(kSlotSuffixes[target()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700385 }
386
387 // Set source and target slots to use before testing.
388 void SetSlots(const TestParam& slots) {
389 slots_ = slots;
390
391 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
392 return source();
393 }));
394 // Should not store metadata to source slot.
395 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, source()))
396 .Times(0);
Yifan Hongd4db07e2018-10-18 17:46:27 -0700397 // Should not load metadata from target slot.
398 EXPECT_CALL(dynamicControl(),
Yifan Hong6e706b12018-11-09 16:50:51 -0800399 LoadMetadataBuilder(GetSuperDevice(), target(), _))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700400 .Times(0);
401 }
402
403 bool InitPartitionMetadata(uint32_t slot, PartitionSizes partition_sizes) {
404 auto m = toMetadata(partition_sizes);
405 LOG(INFO) << m;
406 return bootctl_.InitPartitionMetadata(slot, m);
Yifan Hong537802d2018-08-15 13:15:42 -0700407 }
408
409 BootControlAndroid bootctl_; // BootControlAndroid under test.
410 TestParam slots_;
411 // mapped devices through MapPartitionOnDeviceMapper.
412 std::map<std::string, std::string> mapped_devices_;
413};
414
415class BootControlAndroidTestP
416 : public BootControlAndroidTest,
417 public ::testing::WithParamInterface<TestParam> {
418 public:
419 void SetUp() override {
420 BootControlAndroidTest::SetUp();
421 SetSlots(GetParam());
422 }
423};
424
Yifan Hong537802d2018-08-15 13:15:42 -0700425// Test resize case. Grow if target metadata contains a partition with a size
426// less than expected.
427TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700428 SetMetadata(source(),
429 {{S("system"), 2_GiB},
430 {S("vendor"), 1_GiB},
431 {T("system"), 2_GiB},
432 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700433 ExpectStoreMetadata({{S("system"), 2_GiB},
434 {S("vendor"), 1_GiB},
435 {T("system"), 3_GiB},
436 {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700437 ExpectRemap({T("system"), T("vendor")});
438
Yifan Hongd4db07e2018-10-18 17:46:27 -0700439 EXPECT_TRUE(
440 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700441 ExpectDevicesAreMapped({T("system"), T("vendor")});
442}
443
444// Test resize case. Shrink if target metadata contains a partition with a size
445// greater than expected.
446TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700447 SetMetadata(source(),
448 {{S("system"), 2_GiB},
449 {S("vendor"), 1_GiB},
450 {T("system"), 2_GiB},
451 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700452 ExpectStoreMetadata({{S("system"), 2_GiB},
453 {S("vendor"), 1_GiB},
454 {T("system"), 2_GiB},
455 {T("vendor"), 150_MiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700456 ExpectRemap({T("system"), T("vendor")});
457
Yifan Hongd4db07e2018-10-18 17:46:27 -0700458 EXPECT_TRUE(InitPartitionMetadata(target(),
459 {{"system", 2_GiB}, {"vendor", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700460 ExpectDevicesAreMapped({T("system"), T("vendor")});
461}
462
463// Test adding partitions on the first run.
464TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700465 SetMetadata(source(), PartitionSuffixSizes{});
Yifan Hong549eb362018-10-19 15:11:12 -0700466 ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700467 ExpectRemap({T("system"), T("vendor")});
468
Yifan Hongd4db07e2018-10-18 17:46:27 -0700469 EXPECT_TRUE(
470 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700471 ExpectDevicesAreMapped({T("system"), T("vendor")});
472}
473
474// Test subsequent add case.
475TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
476 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700477 ExpectStoreMetadata(
478 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700479 ExpectRemap({T("system"), T("vendor")});
480
Yifan Hongd4db07e2018-10-18 17:46:27 -0700481 EXPECT_TRUE(
482 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700483 ExpectDevicesAreMapped({T("system"), T("vendor")});
484}
485
486// Test delete one partition.
487TEST_P(BootControlAndroidTestP, DeletePartition) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700488 SetMetadata(source(),
489 {{S("system"), 2_GiB},
490 {S("vendor"), 1_GiB},
491 {T("system"), 2_GiB},
492 {T("vendor"), 1_GiB}});
493 // No T("vendor")
494 ExpectStoreMetadata(
495 {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
496 ExpectRemap({T("system")});
Yifan Hong537802d2018-08-15 13:15:42 -0700497
Yifan Hongd4db07e2018-10-18 17:46:27 -0700498 EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700499 ExpectDevicesAreMapped({T("system")});
500}
501
502// Test delete all partitions.
503TEST_P(BootControlAndroidTestP, DeleteAll) {
Yifan Hong537802d2018-08-15 13:15:42 -0700504 SetMetadata(source(),
505 {{S("system"), 2_GiB},
506 {S("vendor"), 1_GiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700507 {T("system"), 2_GiB},
508 {T("vendor"), 1_GiB}});
509 ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
510
511 EXPECT_TRUE(InitPartitionMetadata(target(), {}));
512 ExpectDevicesAreMapped({});
513}
514
515// Test corrupt source metadata case.
516TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
Yifan Hong6e706b12018-11-09 16:50:51 -0800517 EXPECT_CALL(dynamicControl(),
518 LoadMetadataBuilder(GetSuperDevice(), source(), _))
519 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700520 EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
521 << "Should not be able to continue with corrupt source metadata";
Yifan Hong537802d2018-08-15 13:15:42 -0700522}
523
524// Test that InitPartitionMetadata fail if there is not enough space on the
525// device.
526TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700527 SetMetadata(source(),
528 {{S("system"), 3_GiB},
529 {S("vendor"), 2_GiB},
530 {T("system"), 0},
531 {T("vendor"), 0}});
532 EXPECT_FALSE(
533 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
Yifan Hong537802d2018-08-15 13:15:42 -0700534 << "Should not be able to fit 11GiB data into 10GiB space";
535}
536
Yifan Hongd4db07e2018-10-18 17:46:27 -0700537TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
538 SetMetadata(source(),
539 {{S("system"), 1_GiB},
540 {S("vendor"), 1_GiB},
541 {T("system"), 0},
542 {T("vendor"), 0}});
543 EXPECT_FALSE(
544 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
545 << "Should not be able to grow over size of super / 2";
546}
547
548INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
Yifan Hong537802d2018-08-15 13:15:42 -0700549 BootControlAndroidTestP,
550 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
551
Yifan Hongd4db07e2018-10-18 17:46:27 -0700552const PartitionSuffixSizes update_sizes_0() {
553 // Initial state is 0 for "other" slot.
Yifan Hong537802d2018-08-15 13:15:42 -0700554 return {
555 {"grown_a", 2_GiB},
556 {"shrunk_a", 1_GiB},
557 {"same_a", 100_MiB},
558 {"deleted_a", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700559 // no added_a
560 {"grown_b", 200_MiB},
561 // simulate system_other
562 {"shrunk_b", 0},
563 {"same_b", 0},
564 {"deleted_b", 0},
565 // no added_b
566 };
567}
568
569const PartitionSuffixSizes update_sizes_1() {
570 return {
571 {"grown_a", 2_GiB},
572 {"shrunk_a", 1_GiB},
573 {"same_a", 100_MiB},
574 {"deleted_a", 150_MiB},
575 // no added_a
Yifan Hong537802d2018-08-15 13:15:42 -0700576 {"grown_b", 3_GiB},
577 {"shrunk_b", 150_MiB},
578 {"same_b", 100_MiB},
579 {"added_b", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700580 // no deleted_b
Yifan Hong537802d2018-08-15 13:15:42 -0700581 };
582}
583
Yifan Hongd4db07e2018-10-18 17:46:27 -0700584const PartitionSuffixSizes update_sizes_2() {
585 return {
586 {"grown_a", 4_GiB},
587 {"shrunk_a", 100_MiB},
588 {"same_a", 100_MiB},
589 {"deleted_a", 64_MiB},
590 // no added_a
591 {"grown_b", 3_GiB},
592 {"shrunk_b", 150_MiB},
593 {"same_b", 100_MiB},
594 {"added_b", 150_MiB},
595 // no deleted_b
596 };
Yifan Hong537802d2018-08-15 13:15:42 -0700597}
598
599// Test case for first update after the device is manufactured, in which
600// case the "other" slot is likely of size "0" (except system, which is
601// non-zero because of system_other partition)
602TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
603 SetSlots({0, 1});
604
605 SetMetadata(source(), update_sizes_0());
606 SetMetadata(target(), update_sizes_0());
Yifan Hong549eb362018-10-19 15:11:12 -0700607 ExpectStoreMetadata(update_sizes_1());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700608 ExpectRemap({"grown_b", "shrunk_b", "same_b", "added_b"});
Yifan Hong537802d2018-08-15 13:15:42 -0700609
Yifan Hongd4db07e2018-10-18 17:46:27 -0700610 EXPECT_TRUE(InitPartitionMetadata(target(),
611 {{"grown", 3_GiB},
612 {"shrunk", 150_MiB},
613 {"same", 100_MiB},
614 {"added", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700615 ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
616}
617
618// After first update, test for the second update. In the second update, the
619// "added" partition is deleted and "deleted" partition is re-added.
620TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
621 SetSlots({1, 0});
622
623 SetMetadata(source(), update_sizes_1());
624 SetMetadata(target(), update_sizes_0());
625
Yifan Hong549eb362018-10-19 15:11:12 -0700626 ExpectStoreMetadata(update_sizes_2());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700627 ExpectRemap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
Yifan Hong537802d2018-08-15 13:15:42 -0700628
Yifan Hongd4db07e2018-10-18 17:46:27 -0700629 EXPECT_TRUE(InitPartitionMetadata(target(),
630 {{"grown", 4_GiB},
631 {"shrunk", 100_MiB},
632 {"same", 100_MiB},
633 {"deleted", 64_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700634 ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
635}
636
637TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
638 SetSlots({1, 1});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700639 EXPECT_FALSE(InitPartitionMetadata(target(), {}))
Yifan Hong537802d2018-08-15 13:15:42 -0700640 << "Should not be able to apply to current slot.";
641}
642
Yifan Hongd4db07e2018-10-18 17:46:27 -0700643class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
644 public:
645 void SetUp() override {
646 BootControlAndroidTestP::SetUp();
647 SetMetadata(
648 source(),
649 {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
650 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
651 SimpleGroup(T("android"), 3_GiB, T("system"), 0),
652 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
653 }
654
655 // Return a simple group with only one partition.
656 PartitionMetadata::Group SimpleGroup(const std::string& group,
657 uint64_t group_size,
658 const std::string& partition,
659 uint64_t partition_size) {
660 return {.name = group,
661 .size = group_size,
662 .partitions = {{.name = partition, .size = partition_size}}};
663 }
664
665 void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
666 ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
667 }
668
669 // Expect that target slot is stored with target groups.
670 void ExpectStoreMetadataMatch(
671 const Matcher<MetadataBuilder*>& matcher) override {
672 BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
673 MetadataMatches(PartitionMetadata{
674 .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
675 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
676 matcher));
677 }
678};
679
680// Allow to resize within group.
681TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
682 ExpectStoreMetadata(PartitionMetadata{
683 .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
684 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
685 ExpectRemap({T("system"), T("vendor")});
686
687 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
688 target(),
689 PartitionMetadata{
690 .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
691 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
692 ExpectDevicesAreMapped({T("system"), T("vendor")});
693}
694
695TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
696 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
697 target(),
698 PartitionMetadata{
699 .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
700 SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}))
701 << "Should not be able to grow over maximum size of group";
702}
703
704TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
705 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
706 target(),
707 PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
708 {.name = "oem", .size = 3_GiB}}}))
709 << "Should not be able to grow over size of super / 2";
710}
711
712TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
713 ExpectStoreMetadata(PartitionMetadata{
714 .groups = {
715 {.name = T("android"),
716 .size = 3_GiB,
717 .partitions = {{.name = T("system"), .size = 2_GiB},
718 {.name = T("product_services"), .size = 1_GiB}}}}});
719 ExpectRemap({T("system"), T("vendor"), T("product_services")});
720
721 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
722 target(),
723 PartitionMetadata{
724 .groups = {
725 {.name = "android",
726 .size = 3_GiB,
727 .partitions = {{.name = "system", .size = 2_GiB},
728 {.name = "product_services", .size = 1_GiB}}},
729 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
730 ExpectDevicesAreMapped({T("system"), T("vendor"), T("product_services")});
731}
732
733TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
734 ExpectStoreMetadata(PartitionMetadata{
735 .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
736 ExpectRemap({T("vendor")});
737
738 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
739 target(),
740 PartitionMetadata{
741 .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
742 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
743 ExpectDevicesAreMapped({T("vendor")});
744}
745
746TEST_P(BootControlAndroidGroupTestP, AddGroup) {
747 ExpectStoreMetadata(PartitionMetadata{
748 .groups = {
749 SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
750 ExpectRemap({T("system"), T("vendor"), T("new_partition")});
751
752 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
753 target(),
754 PartitionMetadata{
755 .groups = {
756 SimpleGroup("android", 2_GiB, "system", 2_GiB),
757 SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
758 SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
759 ExpectDevicesAreMapped({T("system"), T("vendor"), T("new_partition")});
760}
761
762TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
763 ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
764 ExpectRemap({T("system")});
765 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
766 target(),
767 PartitionMetadata{
768 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
769 ExpectDevicesAreMapped({T("system")});
770}
771
772TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
773 ExpectStoreMetadata(PartitionMetadata{
774 .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
775 SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
776 ExpectRemap({T("system"), T("vendor")});
777
778 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
779 target(),
780 PartitionMetadata{
781 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
782 SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
783 ExpectDevicesAreMapped({T("system"), T("vendor")});
784}
785
786INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
787 BootControlAndroidGroupTestP,
788 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
789
Yifan Hong537802d2018-08-15 13:15:42 -0700790} // namespace chromeos_update_engine