blob: 8185508af7f345d12e33ffa60c1014395c981b3f [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 Hong537802d2018-08-15 13:15:42 -0700301 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), slot))
Yifan Hongd4db07e2018-10-18 17:46:27 -0700302 .Times(AnyNumber())
303 .WillRepeatedly(Invoke(
304 [metadata](auto, auto) { return NewFakeMetadata(metadata); }));
Yifan Hong537802d2018-08-15 13:15:42 -0700305 }
306
307 // Expect that MapPartitionOnDeviceMapper is called on target() metadata slot
308 // with each partition in |partitions|.
309 void ExpectMap(const std::set<std::string>& partitions) {
310 // Error when MapPartitionOnDeviceMapper is called on unknown arguments.
311 ON_CALL(dynamicControl(), MapPartitionOnDeviceMapper(_, _, _, _))
312 .WillByDefault(Return(false));
313
314 for (const auto& partition : partitions) {
315 EXPECT_CALL(
316 dynamicControl(),
317 MapPartitionOnDeviceMapper(GetSuperDevice(), partition, target(), _))
318 .WillOnce(Invoke([this](auto, auto partition, auto, auto path) {
319 auto it = mapped_devices_.find(partition);
320 if (it != mapped_devices_.end()) {
321 *path = it->second;
322 return true;
323 }
324 mapped_devices_[partition] = *path = kFakeMappedPath + partition;
325 return true;
326 }));
327 }
328 }
329
330 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
331 // slot with each partition in |partitions|.
332 void ExpectUnmap(const std::set<std::string>& partitions) {
333 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
334 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_, _))
335 .WillByDefault(Return(false));
336
337 for (const auto& partition : partitions) {
338 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition, _))
339 .WillOnce(Invoke([this](auto partition, auto) {
340 mapped_devices_.erase(partition);
341 return true;
342 }));
343 }
344 }
345
346 void ExpectRemap(const std::set<std::string>& partitions) {
347 ExpectUnmap(partitions);
348 ExpectMap(partitions);
349 }
350
351 void ExpectDevicesAreMapped(const std::set<std::string>& partitions) {
352 ASSERT_EQ(partitions.size(), mapped_devices_.size());
353 for (const auto& partition : partitions) {
354 EXPECT_THAT(mapped_devices_, Contains(Key(Eq(partition))))
355 << "Expect that " << partition << " is mapped, but it is not.";
356 }
357 }
358
Yifan Hongd4db07e2018-10-18 17:46:27 -0700359 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
Yifan Hong549eb362018-10-19 15:11:12 -0700360 ExpectStoreMetadataMatch(MetadataMatches(partition_sizes));
361 }
362
363 virtual void ExpectStoreMetadataMatch(
364 const Matcher<MetadataBuilder*>& matcher) {
365 EXPECT_CALL(dynamicControl(),
366 StoreMetadata(GetSuperDevice(), matcher, target()))
367 .WillOnce(Return(true));
368 }
369
Yifan Hong537802d2018-08-15 13:15:42 -0700370 uint32_t source() { return slots_.source; }
371
372 uint32_t target() { return slots_.target; }
373
374 // Return partition names with suffix of source().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700375 PartitionNameSuffix S(const std::string& name) {
376 return PartitionNameSuffix(name + std::string(kSlotSuffixes[source()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700377 }
378
379 // Return partition names with suffix of target().
Yifan Hongd4db07e2018-10-18 17:46:27 -0700380 PartitionNameSuffix T(const std::string& name) {
381 return PartitionNameSuffix(name + std::string(kSlotSuffixes[target()]));
Yifan Hong537802d2018-08-15 13:15:42 -0700382 }
383
384 // Set source and target slots to use before testing.
385 void SetSlots(const TestParam& slots) {
386 slots_ = slots;
387
388 ON_CALL(module(), getCurrentSlot()).WillByDefault(Invoke([this] {
389 return source();
390 }));
391 // Should not store metadata to source slot.
392 EXPECT_CALL(dynamicControl(), StoreMetadata(GetSuperDevice(), _, source()))
393 .Times(0);
Yifan Hongd4db07e2018-10-18 17:46:27 -0700394 // Should not load metadata from target slot.
395 EXPECT_CALL(dynamicControl(),
396 LoadMetadataBuilder(GetSuperDevice(), target()))
397 .Times(0);
398 }
399
400 bool InitPartitionMetadata(uint32_t slot, PartitionSizes partition_sizes) {
401 auto m = toMetadata(partition_sizes);
402 LOG(INFO) << m;
403 return bootctl_.InitPartitionMetadata(slot, m);
Yifan Hong537802d2018-08-15 13:15:42 -0700404 }
405
406 BootControlAndroid bootctl_; // BootControlAndroid under test.
407 TestParam slots_;
408 // mapped devices through MapPartitionOnDeviceMapper.
409 std::map<std::string, std::string> mapped_devices_;
410};
411
412class BootControlAndroidTestP
413 : public BootControlAndroidTest,
414 public ::testing::WithParamInterface<TestParam> {
415 public:
416 void SetUp() override {
417 BootControlAndroidTest::SetUp();
418 SetSlots(GetParam());
419 }
420};
421
Yifan Hong537802d2018-08-15 13:15:42 -0700422// Test resize case. Grow if target metadata contains a partition with a size
423// less than expected.
424TEST_P(BootControlAndroidTestP, NeedGrowIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700425 SetMetadata(source(),
426 {{S("system"), 2_GiB},
427 {S("vendor"), 1_GiB},
428 {T("system"), 2_GiB},
429 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700430 ExpectStoreMetadata({{S("system"), 2_GiB},
431 {S("vendor"), 1_GiB},
432 {T("system"), 3_GiB},
433 {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700434 ExpectRemap({T("system"), T("vendor")});
435
Yifan Hongd4db07e2018-10-18 17:46:27 -0700436 EXPECT_TRUE(
437 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700438 ExpectDevicesAreMapped({T("system"), T("vendor")});
439}
440
441// Test resize case. Shrink if target metadata contains a partition with a size
442// greater than expected.
443TEST_P(BootControlAndroidTestP, NeedShrinkIfSizeNotMatchWhenResizing) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700444 SetMetadata(source(),
445 {{S("system"), 2_GiB},
446 {S("vendor"), 1_GiB},
447 {T("system"), 2_GiB},
448 {T("vendor"), 1_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700449 ExpectStoreMetadata({{S("system"), 2_GiB},
450 {S("vendor"), 1_GiB},
451 {T("system"), 2_GiB},
452 {T("vendor"), 150_MiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700453 ExpectRemap({T("system"), T("vendor")});
454
Yifan Hongd4db07e2018-10-18 17:46:27 -0700455 EXPECT_TRUE(InitPartitionMetadata(target(),
456 {{"system", 2_GiB}, {"vendor", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700457 ExpectDevicesAreMapped({T("system"), T("vendor")});
458}
459
460// Test adding partitions on the first run.
461TEST_P(BootControlAndroidTestP, AddPartitionToEmptyMetadata) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700462 SetMetadata(source(), PartitionSuffixSizes{});
Yifan Hong549eb362018-10-19 15:11:12 -0700463 ExpectStoreMetadata({{T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700464 ExpectRemap({T("system"), T("vendor")});
465
Yifan Hongd4db07e2018-10-18 17:46:27 -0700466 EXPECT_TRUE(
467 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700468 ExpectDevicesAreMapped({T("system"), T("vendor")});
469}
470
471// Test subsequent add case.
472TEST_P(BootControlAndroidTestP, AddAdditionalPartition) {
473 SetMetadata(source(), {{S("system"), 2_GiB}, {T("system"), 2_GiB}});
Yifan Hong549eb362018-10-19 15:11:12 -0700474 ExpectStoreMetadata(
475 {{S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}});
Yifan Hong537802d2018-08-15 13:15:42 -0700476 ExpectRemap({T("system"), T("vendor")});
477
Yifan Hongd4db07e2018-10-18 17:46:27 -0700478 EXPECT_TRUE(
479 InitPartitionMetadata(target(), {{"system", 2_GiB}, {"vendor", 1_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700480 ExpectDevicesAreMapped({T("system"), T("vendor")});
481}
482
483// Test delete one partition.
484TEST_P(BootControlAndroidTestP, DeletePartition) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700485 SetMetadata(source(),
486 {{S("system"), 2_GiB},
487 {S("vendor"), 1_GiB},
488 {T("system"), 2_GiB},
489 {T("vendor"), 1_GiB}});
490 // No T("vendor")
491 ExpectStoreMetadata(
492 {{S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}});
493 ExpectRemap({T("system")});
Yifan Hong537802d2018-08-15 13:15:42 -0700494
Yifan Hongd4db07e2018-10-18 17:46:27 -0700495 EXPECT_TRUE(InitPartitionMetadata(target(), {{"system", 2_GiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700496 ExpectDevicesAreMapped({T("system")});
497}
498
499// Test delete all partitions.
500TEST_P(BootControlAndroidTestP, DeleteAll) {
Yifan Hong537802d2018-08-15 13:15:42 -0700501 SetMetadata(source(),
502 {{S("system"), 2_GiB},
503 {S("vendor"), 1_GiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700504 {T("system"), 2_GiB},
505 {T("vendor"), 1_GiB}});
506 ExpectStoreMetadata({{S("system"), 2_GiB}, {S("vendor"), 1_GiB}});
507
508 EXPECT_TRUE(InitPartitionMetadata(target(), {}));
509 ExpectDevicesAreMapped({});
510}
511
512// Test corrupt source metadata case.
513TEST_P(BootControlAndroidTestP, CorruptedSourceMetadata) {
514 EXPECT_CALL(dynamicControl(), LoadMetadataBuilder(GetSuperDevice(), source()))
Yifan Hong537802d2018-08-15 13:15:42 -0700515 .WillOnce(Invoke([](auto, auto) { return nullptr; }));
Yifan Hongd4db07e2018-10-18 17:46:27 -0700516 EXPECT_FALSE(InitPartitionMetadata(target(), {{"system", 1_GiB}}))
517 << "Should not be able to continue with corrupt source metadata";
Yifan Hong537802d2018-08-15 13:15:42 -0700518}
519
520// Test that InitPartitionMetadata fail if there is not enough space on the
521// device.
522TEST_P(BootControlAndroidTestP, NotEnoughSpace) {
Yifan Hongd4db07e2018-10-18 17:46:27 -0700523 SetMetadata(source(),
524 {{S("system"), 3_GiB},
525 {S("vendor"), 2_GiB},
526 {T("system"), 0},
527 {T("vendor"), 0}});
528 EXPECT_FALSE(
529 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
Yifan Hong537802d2018-08-15 13:15:42 -0700530 << "Should not be able to fit 11GiB data into 10GiB space";
531}
532
Yifan Hongd4db07e2018-10-18 17:46:27 -0700533TEST_P(BootControlAndroidTestP, NotEnoughSpaceForSlot) {
534 SetMetadata(source(),
535 {{S("system"), 1_GiB},
536 {S("vendor"), 1_GiB},
537 {T("system"), 0},
538 {T("vendor"), 0}});
539 EXPECT_FALSE(
540 InitPartitionMetadata(target(), {{"system", 3_GiB}, {"vendor", 3_GiB}}))
541 << "Should not be able to grow over size of super / 2";
542}
543
544INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
Yifan Hong537802d2018-08-15 13:15:42 -0700545 BootControlAndroidTestP,
546 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
547
Yifan Hongd4db07e2018-10-18 17:46:27 -0700548const PartitionSuffixSizes update_sizes_0() {
549 // Initial state is 0 for "other" slot.
Yifan Hong537802d2018-08-15 13:15:42 -0700550 return {
551 {"grown_a", 2_GiB},
552 {"shrunk_a", 1_GiB},
553 {"same_a", 100_MiB},
554 {"deleted_a", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700555 // no added_a
556 {"grown_b", 200_MiB},
557 // simulate system_other
558 {"shrunk_b", 0},
559 {"same_b", 0},
560 {"deleted_b", 0},
561 // no added_b
562 };
563}
564
565const PartitionSuffixSizes update_sizes_1() {
566 return {
567 {"grown_a", 2_GiB},
568 {"shrunk_a", 1_GiB},
569 {"same_a", 100_MiB},
570 {"deleted_a", 150_MiB},
571 // no added_a
Yifan Hong537802d2018-08-15 13:15:42 -0700572 {"grown_b", 3_GiB},
573 {"shrunk_b", 150_MiB},
574 {"same_b", 100_MiB},
575 {"added_b", 150_MiB},
Yifan Hongd4db07e2018-10-18 17:46:27 -0700576 // no deleted_b
Yifan Hong537802d2018-08-15 13:15:42 -0700577 };
578}
579
Yifan Hongd4db07e2018-10-18 17:46:27 -0700580const PartitionSuffixSizes update_sizes_2() {
581 return {
582 {"grown_a", 4_GiB},
583 {"shrunk_a", 100_MiB},
584 {"same_a", 100_MiB},
585 {"deleted_a", 64_MiB},
586 // no added_a
587 {"grown_b", 3_GiB},
588 {"shrunk_b", 150_MiB},
589 {"same_b", 100_MiB},
590 {"added_b", 150_MiB},
591 // no deleted_b
592 };
Yifan Hong537802d2018-08-15 13:15:42 -0700593}
594
595// Test case for first update after the device is manufactured, in which
596// case the "other" slot is likely of size "0" (except system, which is
597// non-zero because of system_other partition)
598TEST_F(BootControlAndroidTest, SimulatedFirstUpdate) {
599 SetSlots({0, 1});
600
601 SetMetadata(source(), update_sizes_0());
602 SetMetadata(target(), update_sizes_0());
Yifan Hong549eb362018-10-19 15:11:12 -0700603 ExpectStoreMetadata(update_sizes_1());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700604 ExpectRemap({"grown_b", "shrunk_b", "same_b", "added_b"});
Yifan Hong537802d2018-08-15 13:15:42 -0700605
Yifan Hongd4db07e2018-10-18 17:46:27 -0700606 EXPECT_TRUE(InitPartitionMetadata(target(),
607 {{"grown", 3_GiB},
608 {"shrunk", 150_MiB},
609 {"same", 100_MiB},
610 {"added", 150_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700611 ExpectDevicesAreMapped({"grown_b", "shrunk_b", "same_b", "added_b"});
612}
613
614// After first update, test for the second update. In the second update, the
615// "added" partition is deleted and "deleted" partition is re-added.
616TEST_F(BootControlAndroidTest, SimulatedSecondUpdate) {
617 SetSlots({1, 0});
618
619 SetMetadata(source(), update_sizes_1());
620 SetMetadata(target(), update_sizes_0());
621
Yifan Hong549eb362018-10-19 15:11:12 -0700622 ExpectStoreMetadata(update_sizes_2());
Yifan Hongd4db07e2018-10-18 17:46:27 -0700623 ExpectRemap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
Yifan Hong537802d2018-08-15 13:15:42 -0700624
Yifan Hongd4db07e2018-10-18 17:46:27 -0700625 EXPECT_TRUE(InitPartitionMetadata(target(),
626 {{"grown", 4_GiB},
627 {"shrunk", 100_MiB},
628 {"same", 100_MiB},
629 {"deleted", 64_MiB}}));
Yifan Hong537802d2018-08-15 13:15:42 -0700630 ExpectDevicesAreMapped({"grown_a", "shrunk_a", "same_a", "deleted_a"});
631}
632
633TEST_F(BootControlAndroidTest, ApplyingToCurrentSlot) {
634 SetSlots({1, 1});
Yifan Hongd4db07e2018-10-18 17:46:27 -0700635 EXPECT_FALSE(InitPartitionMetadata(target(), {}))
Yifan Hong537802d2018-08-15 13:15:42 -0700636 << "Should not be able to apply to current slot.";
637}
638
Yifan Hongd4db07e2018-10-18 17:46:27 -0700639class BootControlAndroidGroupTestP : public BootControlAndroidTestP {
640 public:
641 void SetUp() override {
642 BootControlAndroidTestP::SetUp();
643 SetMetadata(
644 source(),
645 {.groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
646 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB),
647 SimpleGroup(T("android"), 3_GiB, T("system"), 0),
648 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 0)}});
649 }
650
651 // Return a simple group with only one partition.
652 PartitionMetadata::Group SimpleGroup(const std::string& group,
653 uint64_t group_size,
654 const std::string& partition,
655 uint64_t partition_size) {
656 return {.name = group,
657 .size = group_size,
658 .partitions = {{.name = partition, .size = partition_size}}};
659 }
660
661 void ExpectStoreMetadata(const PartitionMetadata& partition_metadata) {
662 ExpectStoreMetadataMatch(MetadataMatches(partition_metadata));
663 }
664
665 // Expect that target slot is stored with target groups.
666 void ExpectStoreMetadataMatch(
667 const Matcher<MetadataBuilder*>& matcher) override {
668 BootControlAndroidTestP::ExpectStoreMetadataMatch(AllOf(
669 MetadataMatches(PartitionMetadata{
670 .groups = {SimpleGroup(S("android"), 3_GiB, S("system"), 2_GiB),
671 SimpleGroup(S("oem"), 2_GiB, S("vendor"), 1_GiB)}}),
672 matcher));
673 }
674};
675
676// Allow to resize within group.
677TEST_P(BootControlAndroidGroupTestP, ResizeWithinGroup) {
678 ExpectStoreMetadata(PartitionMetadata{
679 .groups = {SimpleGroup(T("android"), 3_GiB, T("system"), 3_GiB),
680 SimpleGroup(T("oem"), 2_GiB, T("vendor"), 2_GiB)}});
681 ExpectRemap({T("system"), T("vendor")});
682
683 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
684 target(),
685 PartitionMetadata{
686 .groups = {SimpleGroup("android", 3_GiB, "system", 3_GiB),
687 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
688 ExpectDevicesAreMapped({T("system"), T("vendor")});
689}
690
691TEST_P(BootControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
692 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
693 target(),
694 PartitionMetadata{
695 .groups = {SimpleGroup("android", 3_GiB, "system", 1_GiB),
696 SimpleGroup("oem", 2_GiB, "vendor", 3_GiB)}}))
697 << "Should not be able to grow over maximum size of group";
698}
699
700TEST_P(BootControlAndroidGroupTestP, GroupTooBig) {
701 EXPECT_FALSE(bootctl_.InitPartitionMetadata(
702 target(),
703 PartitionMetadata{.groups = {{.name = "android", .size = 3_GiB},
704 {.name = "oem", .size = 3_GiB}}}))
705 << "Should not be able to grow over size of super / 2";
706}
707
708TEST_P(BootControlAndroidGroupTestP, AddPartitionToGroup) {
709 ExpectStoreMetadata(PartitionMetadata{
710 .groups = {
711 {.name = T("android"),
712 .size = 3_GiB,
713 .partitions = {{.name = T("system"), .size = 2_GiB},
714 {.name = T("product_services"), .size = 1_GiB}}}}});
715 ExpectRemap({T("system"), T("vendor"), T("product_services")});
716
717 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
718 target(),
719 PartitionMetadata{
720 .groups = {
721 {.name = "android",
722 .size = 3_GiB,
723 .partitions = {{.name = "system", .size = 2_GiB},
724 {.name = "product_services", .size = 1_GiB}}},
725 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
726 ExpectDevicesAreMapped({T("system"), T("vendor"), T("product_services")});
727}
728
729TEST_P(BootControlAndroidGroupTestP, RemovePartitionFromGroup) {
730 ExpectStoreMetadata(PartitionMetadata{
731 .groups = {{.name = T("android"), .size = 3_GiB, .partitions = {}}}});
732 ExpectRemap({T("vendor")});
733
734 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
735 target(),
736 PartitionMetadata{
737 .groups = {{.name = "android", .size = 3_GiB, .partitions = {}},
738 SimpleGroup("oem", 2_GiB, "vendor", 2_GiB)}}));
739 ExpectDevicesAreMapped({T("vendor")});
740}
741
742TEST_P(BootControlAndroidGroupTestP, AddGroup) {
743 ExpectStoreMetadata(PartitionMetadata{
744 .groups = {
745 SimpleGroup(T("new_group"), 2_GiB, T("new_partition"), 2_GiB)}});
746 ExpectRemap({T("system"), T("vendor"), T("new_partition")});
747
748 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
749 target(),
750 PartitionMetadata{
751 .groups = {
752 SimpleGroup("android", 2_GiB, "system", 2_GiB),
753 SimpleGroup("oem", 1_GiB, "vendor", 1_GiB),
754 SimpleGroup("new_group", 2_GiB, "new_partition", 2_GiB)}}));
755 ExpectDevicesAreMapped({T("system"), T("vendor"), T("new_partition")});
756}
757
758TEST_P(BootControlAndroidGroupTestP, RemoveGroup) {
759 ExpectStoreMetadataMatch(Not(HasGroup(T("oem"))));
760 ExpectRemap({T("system")});
761 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
762 target(),
763 PartitionMetadata{
764 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB)}}));
765 ExpectDevicesAreMapped({T("system")});
766}
767
768TEST_P(BootControlAndroidGroupTestP, ResizeGroup) {
769 ExpectStoreMetadata(PartitionMetadata{
770 .groups = {SimpleGroup(T("android"), 2_GiB, T("system"), 2_GiB),
771 SimpleGroup(T("oem"), 3_GiB, T("vendor"), 3_GiB)}});
772 ExpectRemap({T("system"), T("vendor")});
773
774 EXPECT_TRUE(bootctl_.InitPartitionMetadata(
775 target(),
776 PartitionMetadata{
777 .groups = {SimpleGroup("android", 2_GiB, "system", 2_GiB),
778 SimpleGroup("oem", 3_GiB, "vendor", 3_GiB)}}));
779 ExpectDevicesAreMapped({T("system"), T("vendor")});
780}
781
782INSTANTIATE_TEST_CASE_P(BootControlAndroidTest,
783 BootControlAndroidGroupTestP,
784 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
785
Yifan Hong537802d2018-08-15 13:15:42 -0700786} // namespace chromeos_update_engine