blob: 10075ed4b0cc528c6e652f87042ed3b04eba8426 [file] [log] [blame]
Yifan Hongc049f932019-07-23 15:06:05 -07001//
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 "update_engine/dynamic_partition_control_android.h"
18
19#include <set>
20#include <vector>
21
22#include <base/logging.h>
23#include <base/strings/string_util.h>
24#include <gmock/gmock.h>
25#include <gtest/gtest.h>
26
27#include "update_engine/dynamic_partition_test_utils.h"
28#include "update_engine/mock_dynamic_partition_control.h"
29
Yifan Hong3a1a5612019-11-05 16:34:32 -080030using android::dm::DmDeviceState;
Yifan Hongc049f932019-07-23 15:06:05 -070031using std::string;
32using testing::_;
33using testing::AnyNumber;
Yifan Hong3a1a5612019-11-05 16:34:32 -080034using testing::AnyOf;
Yifan Hongc049f932019-07-23 15:06:05 -070035using testing::Invoke;
36using testing::NiceMock;
37using testing::Not;
38using testing::Return;
39
40namespace chromeos_update_engine {
41
42class DynamicPartitionControlAndroidTest : public ::testing::Test {
43 public:
44 void SetUp() override {
45 module_ = std::make_unique<NiceMock<MockDynamicPartitionControlAndroid>>();
46
47 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
48 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
Yifan Hong413d5722019-07-23 14:21:09 -070049 ON_CALL(dynamicControl(), GetVirtualAbFeatureFlag())
50 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
Yifan Hongc049f932019-07-23 15:06:05 -070051
52 ON_CALL(dynamicControl(), GetDeviceDir(_))
53 .WillByDefault(Invoke([](auto path) {
54 *path = kFakeDevicePath;
55 return true;
56 }));
Yifan Hong700d7c12019-07-23 20:49:16 -070057
58 ON_CALL(dynamicControl(), GetSuperPartitionName(_))
59 .WillByDefault(Return(kFakeSuper));
Yifan Hong3a1a5612019-11-05 16:34:32 -080060
61 ON_CALL(dynamicControl(), GetDmDevicePathByName(_, _))
62 .WillByDefault(Invoke([](auto partition_name_suffix, auto device) {
63 *device = GetDmDevice(partition_name_suffix);
64 return true;
65 }));
Yifan Hongc049f932019-07-23 15:06:05 -070066 }
67
68 // Return the mocked DynamicPartitionControlInterface.
69 NiceMock<MockDynamicPartitionControlAndroid>& dynamicControl() {
70 return static_cast<NiceMock<MockDynamicPartitionControlAndroid>&>(*module_);
71 }
72
Yifan Hong700d7c12019-07-23 20:49:16 -070073 std::string GetSuperDevice(uint32_t slot) {
74 return GetDevice(dynamicControl().GetSuperPartitionName(slot));
75 }
76
Yifan Hongc049f932019-07-23 15:06:05 -070077 uint32_t source() { return slots_.source; }
78 uint32_t target() { return slots_.target; }
79
80 // Return partition names with suffix of source().
81 std::string S(const std::string& name) {
82 return name + kSlotSuffixes[source()];
83 }
84
85 // Return partition names with suffix of target().
86 std::string T(const std::string& name) {
87 return name + kSlotSuffixes[target()];
88 }
89
90 // Set the fake metadata to return when LoadMetadataBuilder is called on
91 // |slot|.
92 void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
93 EXPECT_CALL(dynamicControl(),
94 LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
95 .Times(AnyNumber())
96 .WillRepeatedly(Invoke([sizes](auto, auto, auto) {
Yifan Hong13d41cb2019-09-16 13:18:22 -070097 return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
Yifan Hongc049f932019-07-23 15:06:05 -070098 }));
99 }
100
101 void ExpectStoreMetadata(const PartitionSuffixSizes& partition_sizes) {
102 EXPECT_CALL(dynamicControl(),
103 StoreMetadata(GetSuperDevice(target()),
104 MetadataMatches(partition_sizes),
105 target()))
106 .WillOnce(Return(true));
107 }
108
109 // Expect that UnmapPartitionOnDeviceMapper is called on target() metadata
110 // slot with each partition in |partitions|.
111 void ExpectUnmap(const std::set<std::string>& partitions) {
112 // Error when UnmapPartitionOnDeviceMapper is called on unknown arguments.
113 ON_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(_))
114 .WillByDefault(Return(false));
115
116 for (const auto& partition : partitions) {
117 EXPECT_CALL(dynamicControl(), UnmapPartitionOnDeviceMapper(partition))
118 .WillOnce(Return(true));
119 }
120 }
121 bool PreparePartitionsForUpdate(const PartitionSizes& partition_sizes) {
122 return dynamicControl().PreparePartitionsForUpdate(
Yifan Hongf0f4a912019-09-26 17:51:33 -0700123 source(), target(), PartitionSizesToManifest(partition_sizes), true);
Yifan Hongc049f932019-07-23 15:06:05 -0700124 }
125 void SetSlots(const TestParam& slots) { slots_ = slots; }
126
127 struct Listener : public ::testing::MatchResultListener {
128 explicit Listener(std::ostream* os) : MatchResultListener(os) {}
129 };
130
131 testing::AssertionResult UpdatePartitionMetadata(
132 const PartitionSuffixSizes& source_metadata,
133 const PartitionSizes& update_metadata,
134 const PartitionSuffixSizes& expected) {
135 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700136 PartitionSuffixSizesToManifest(source_metadata),
137 PartitionSizesToManifest(update_metadata),
138 PartitionSuffixSizesToManifest(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700139 }
140 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700141 const DeltaArchiveManifest& source_manifest,
142 const DeltaArchiveManifest& update_manifest,
143 const DeltaArchiveManifest& expected) {
Yifan Hongc049f932019-07-23 15:06:05 -0700144 return UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700145 source_manifest, update_manifest, MetadataMatches(expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700146 }
147 testing::AssertionResult UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700148 const DeltaArchiveManifest& source_manifest,
149 const DeltaArchiveManifest& update_manifest,
Yifan Hongc049f932019-07-23 15:06:05 -0700150 const Matcher<MetadataBuilder*>& matcher) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700151 auto super_metadata = NewFakeMetadata(source_manifest);
Yifan Hongc049f932019-07-23 15:06:05 -0700152 if (!module_->UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700153 super_metadata.get(), target(), update_manifest)) {
Yifan Hongc049f932019-07-23 15:06:05 -0700154 return testing::AssertionFailure()
155 << "UpdatePartitionMetadataInternal failed";
156 }
157 std::stringstream ss;
158 Listener listener(&ss);
159 if (matcher.MatchAndExplain(super_metadata.get(), &listener)) {
160 return testing::AssertionSuccess() << ss.str();
161 } else {
162 return testing::AssertionFailure() << ss.str();
163 }
164 }
165
166 std::unique_ptr<DynamicPartitionControlAndroid> module_;
167 TestParam slots_;
168};
169
170class DynamicPartitionControlAndroidTestP
171 : public DynamicPartitionControlAndroidTest,
172 public ::testing::WithParamInterface<TestParam> {
173 public:
174 void SetUp() override {
175 DynamicPartitionControlAndroidTest::SetUp();
176 SetSlots(GetParam());
177 }
178};
179
180// Test resize case. Grow if target metadata contains a partition with a size
181// less than expected.
182TEST_P(DynamicPartitionControlAndroidTestP,
183 NeedGrowIfSizeNotMatchWhenResizing) {
184 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
185 {S("vendor"), 1_GiB},
186 {T("system"), 2_GiB},
187 {T("vendor"), 1_GiB}};
188 PartitionSuffixSizes expected{{S("system"), 2_GiB},
189 {S("vendor"), 1_GiB},
190 {T("system"), 3_GiB},
191 {T("vendor"), 1_GiB}};
192 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 1_GiB}};
193 EXPECT_TRUE(
194 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
195}
196
197// Test resize case. Shrink if target metadata contains a partition with a size
198// greater than expected.
199TEST_P(DynamicPartitionControlAndroidTestP,
200 NeedShrinkIfSizeNotMatchWhenResizing) {
201 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
202 {S("vendor"), 1_GiB},
203 {T("system"), 2_GiB},
204 {T("vendor"), 1_GiB}};
205 PartitionSuffixSizes expected{{S("system"), 2_GiB},
206 {S("vendor"), 1_GiB},
207 {T("system"), 2_GiB},
208 {T("vendor"), 150_MiB}};
209 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 150_MiB}};
210 EXPECT_TRUE(
211 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
212}
213
214// Test adding partitions on the first run.
215TEST_P(DynamicPartitionControlAndroidTestP, AddPartitionToEmptyMetadata) {
216 PartitionSuffixSizes source_metadata{};
217 PartitionSuffixSizes expected{{T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
218 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
219 EXPECT_TRUE(
220 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
221}
222
223// Test subsequent add case.
224TEST_P(DynamicPartitionControlAndroidTestP, AddAdditionalPartition) {
225 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
226 {T("system"), 2_GiB}};
227 PartitionSuffixSizes expected{
228 {S("system"), 2_GiB}, {T("system"), 2_GiB}, {T("vendor"), 1_GiB}};
229 PartitionSizes update_metadata{{"system", 2_GiB}, {"vendor", 1_GiB}};
230 EXPECT_TRUE(
231 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
232}
233
234// Test delete one partition.
235TEST_P(DynamicPartitionControlAndroidTestP, DeletePartition) {
236 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
237 {S("vendor"), 1_GiB},
238 {T("system"), 2_GiB},
239 {T("vendor"), 1_GiB}};
240 // No T("vendor")
241 PartitionSuffixSizes expected{
242 {S("system"), 2_GiB}, {S("vendor"), 1_GiB}, {T("system"), 2_GiB}};
243 PartitionSizes update_metadata{{"system", 2_GiB}};
244 EXPECT_TRUE(
245 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
246}
247
248// Test delete all partitions.
249TEST_P(DynamicPartitionControlAndroidTestP, DeleteAll) {
250 PartitionSuffixSizes source_metadata{{S("system"), 2_GiB},
251 {S("vendor"), 1_GiB},
252 {T("system"), 2_GiB},
253 {T("vendor"), 1_GiB}};
254 PartitionSuffixSizes expected{{S("system"), 2_GiB}, {S("vendor"), 1_GiB}};
255 PartitionSizes update_metadata{};
256 EXPECT_TRUE(
257 UpdatePartitionMetadata(source_metadata, update_metadata, expected));
258}
259
260// Test corrupt source metadata case.
261TEST_P(DynamicPartitionControlAndroidTestP, CorruptedSourceMetadata) {
262 EXPECT_CALL(dynamicControl(),
263 LoadMetadataBuilder(GetSuperDevice(source()), source(), _))
264 .WillOnce(Invoke([](auto, auto, auto) { return nullptr; }));
265 ExpectUnmap({T("system")});
266
267 EXPECT_FALSE(PreparePartitionsForUpdate({{"system", 1_GiB}}))
268 << "Should not be able to continue with corrupt source metadata";
269}
270
271// Test that UpdatePartitionMetadata fails if there is not enough space on the
272// device.
273TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpace) {
274 PartitionSuffixSizes source_metadata{{S("system"), 3_GiB},
275 {S("vendor"), 2_GiB},
276 {T("system"), 0},
277 {T("vendor"), 0}};
278 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
279
280 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
281 << "Should not be able to fit 11GiB data into 10GiB space";
282}
283
284TEST_P(DynamicPartitionControlAndroidTestP, NotEnoughSpaceForSlot) {
285 PartitionSuffixSizes source_metadata{{S("system"), 1_GiB},
286 {S("vendor"), 1_GiB},
287 {T("system"), 0},
288 {T("vendor"), 0}};
289 PartitionSizes update_metadata{{"system", 3_GiB}, {"vendor", 3_GiB}};
290 EXPECT_FALSE(UpdatePartitionMetadata(source_metadata, update_metadata, {}))
291 << "Should not be able to grow over size of super / 2";
292}
293
Yifan Hong3a1a5612019-11-05 16:34:32 -0800294TEST_P(DynamicPartitionControlAndroidTestP,
295 ApplyRetrofitUpdateOnDynamicPartitionsEnabledBuild) {
296 ON_CALL(dynamicControl(), GetDynamicPartitionsFeatureFlag())
297 .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::RETROFIT)));
298 // Static partition {system,bar}_{a,b} exists.
299 EXPECT_CALL(dynamicControl(),
300 DeviceExists(AnyOf(GetDevice(S("bar")),
301 GetDevice(T("bar")),
302 GetDevice(S("system")),
303 GetDevice(T("system")))))
304 .WillRepeatedly(Return(true));
305
306 SetMetadata(source(),
307 {{S("system"), 2_GiB},
308 {S("vendor"), 1_GiB},
309 {T("system"), 2_GiB},
310 {T("vendor"), 1_GiB}});
311
312 // Not calling through
313 // DynamicPartitionControlAndroidTest::PreparePartitionsForUpdate(), since we
314 // don't want any default group in the PartitionMetadata.
315 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
316 source(), target(), {}, true));
317
318 // Should use dynamic source partitions.
319 EXPECT_CALL(dynamicControl(), GetState(S("system")))
320 .Times(1)
321 .WillOnce(Return(DmDeviceState::ACTIVE));
322 string system_device;
323 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
324 "system", source(), source(), &system_device));
325 EXPECT_EQ(GetDmDevice(S("system")), system_device);
326
327 // Should use static target partitions without querying dynamic control.
328 EXPECT_CALL(dynamicControl(), GetState(T("system"))).Times(0);
329 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
330 "system", target(), source(), &system_device));
331 EXPECT_EQ(GetDevice(T("system")), system_device);
332
333 // Static partition "bar".
334 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
335 std::string bar_device;
336 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
337 "bar", source(), source(), &bar_device));
338 EXPECT_EQ(GetDevice(S("bar")), bar_device);
339
340 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
341 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
342 "bar", target(), source(), &bar_device));
343 EXPECT_EQ(GetDevice(T("bar")), bar_device);
344}
345
346TEST_P(DynamicPartitionControlAndroidTestP,
347 GetPartitionDeviceWhenResumingUpdate) {
348 // Static partition bar_{a,b} exists.
349 EXPECT_CALL(dynamicControl(),
350 DeviceExists(AnyOf(GetDevice(S("bar")), GetDevice(T("bar")))))
351 .WillRepeatedly(Return(true));
352
353 // Both of the two slots contain valid partition metadata, since this is
354 // resuming an update.
355 SetMetadata(source(),
356 {{S("system"), 2_GiB},
357 {S("vendor"), 1_GiB},
358 {T("system"), 2_GiB},
359 {T("vendor"), 1_GiB}});
360 SetMetadata(target(),
361 {{S("system"), 2_GiB},
362 {S("vendor"), 1_GiB},
363 {T("system"), 2_GiB},
364 {T("vendor"), 1_GiB}});
365
366 EXPECT_TRUE(dynamicControl().PreparePartitionsForUpdate(
367 source(),
368 target(),
369 PartitionSizesToManifest({{"system", 2_GiB}, {"vendor", 1_GiB}}),
370 false));
371
372 // Dynamic partition "system".
373 EXPECT_CALL(dynamicControl(), GetState(S("system")))
374 .Times(1)
375 .WillOnce(Return(DmDeviceState::ACTIVE));
376 string system_device;
377 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
378 "system", source(), source(), &system_device));
379 EXPECT_EQ(GetDmDevice(S("system")), system_device);
380
381 EXPECT_CALL(dynamicControl(), GetState(T("system")))
382 .Times(AnyNumber())
383 .WillOnce(Return(DmDeviceState::ACTIVE));
384 EXPECT_CALL(dynamicControl(),
385 MapPartitionOnDeviceMapper(
386 GetSuperDevice(target()), T("system"), target(), _, _))
387 .Times(AnyNumber())
388 .WillRepeatedly(
389 Invoke([](const auto&, const auto& name, auto, auto, auto* device) {
390 *device = "/fake/remapped/" + name;
391 return true;
392 }));
393 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
394 "system", target(), source(), &system_device));
395 EXPECT_EQ("/fake/remapped/" + T("system"), system_device);
396
397 // Static partition "bar".
398 EXPECT_CALL(dynamicControl(), GetState(S("bar"))).Times(0);
399 std::string bar_device;
400 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
401 "bar", source(), source(), &bar_device));
402 EXPECT_EQ(GetDevice(S("bar")), bar_device);
403
404 EXPECT_CALL(dynamicControl(), GetState(T("bar"))).Times(0);
405 EXPECT_TRUE(dynamicControl().GetPartitionDevice(
406 "bar", target(), source(), &bar_device));
407 EXPECT_EQ(GetDevice(T("bar")), bar_device);
408}
409
Yifan Hongc049f932019-07-23 15:06:05 -0700410INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
411 DynamicPartitionControlAndroidTestP,
412 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
413
414class DynamicPartitionControlAndroidGroupTestP
415 : public DynamicPartitionControlAndroidTestP {
416 public:
Yifan Hong13d41cb2019-09-16 13:18:22 -0700417 DeltaArchiveManifest source_manifest;
Yifan Hongc049f932019-07-23 15:06:05 -0700418 void SetUp() override {
419 DynamicPartitionControlAndroidTestP::SetUp();
Yifan Hong13d41cb2019-09-16 13:18:22 -0700420 AddGroupAndPartition(
421 &source_manifest, S("android"), 3_GiB, S("system"), 2_GiB);
422 AddGroupAndPartition(&source_manifest, S("oem"), 2_GiB, S("vendor"), 1_GiB);
423 AddGroupAndPartition(&source_manifest, T("android"), 3_GiB, T("system"), 0);
424 AddGroupAndPartition(&source_manifest, T("oem"), 2_GiB, T("vendor"), 0);
Yifan Hongc049f932019-07-23 15:06:05 -0700425 }
426
Yifan Hong13d41cb2019-09-16 13:18:22 -0700427 void AddGroupAndPartition(DeltaArchiveManifest* manifest,
428 const string& group,
429 uint64_t group_size,
430 const string& partition,
431 uint64_t partition_size) {
432 auto* g = AddGroup(manifest, group, group_size);
433 AddPartition(manifest, g, partition, partition_size);
Yifan Hongc049f932019-07-23 15:06:05 -0700434 }
435};
436
437// Allow to resize within group.
438TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeWithinGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700439 DeltaArchiveManifest expected;
440 AddGroupAndPartition(&expected, T("android"), 3_GiB, T("system"), 3_GiB);
441 AddGroupAndPartition(&expected, T("oem"), 2_GiB, T("vendor"), 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700442
Yifan Hong13d41cb2019-09-16 13:18:22 -0700443 DeltaArchiveManifest update_manifest;
444 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 3_GiB);
445 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700446
447 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700448 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700449}
450
451TEST_P(DynamicPartitionControlAndroidGroupTestP, NotEnoughSpaceForGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700452 DeltaArchiveManifest update_manifest;
453 AddGroupAndPartition(&update_manifest, "android", 3_GiB, "system", 1_GiB),
454 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 3_GiB);
455 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700456 << "Should not be able to grow over maximum size of group";
457}
458
459TEST_P(DynamicPartitionControlAndroidGroupTestP, GroupTooBig) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700460 DeltaArchiveManifest update_manifest;
461 AddGroup(&update_manifest, "android", 3_GiB);
462 AddGroup(&update_manifest, "oem", 3_GiB);
463 EXPECT_FALSE(UpdatePartitionMetadata(source_manifest, update_manifest, {}))
Yifan Hongc049f932019-07-23 15:06:05 -0700464 << "Should not be able to grow over size of super / 2";
465}
466
467TEST_P(DynamicPartitionControlAndroidGroupTestP, AddPartitionToGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700468 DeltaArchiveManifest expected;
469 auto* g = AddGroup(&expected, T("android"), 3_GiB);
470 AddPartition(&expected, g, T("system"), 2_GiB);
471 AddPartition(&expected, g, T("system_ext"), 1_GiB);
472
473 DeltaArchiveManifest update_manifest;
474 g = AddGroup(&update_manifest, "android", 3_GiB);
475 AddPartition(&update_manifest, g, "system", 2_GiB);
476 AddPartition(&update_manifest, g, "system_ext", 1_GiB);
477 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
478
Yifan Hongc049f932019-07-23 15:06:05 -0700479 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700480 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700481}
482
483TEST_P(DynamicPartitionControlAndroidGroupTestP, RemovePartitionFromGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700484 DeltaArchiveManifest expected;
485 AddGroup(&expected, T("android"), 3_GiB);
486
487 DeltaArchiveManifest update_manifest;
488 AddGroup(&update_manifest, "android", 3_GiB);
489 AddGroupAndPartition(&update_manifest, "oem", 2_GiB, "vendor", 2_GiB);
490
Yifan Hongc049f932019-07-23 15:06:05 -0700491 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700492 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700493}
494
495TEST_P(DynamicPartitionControlAndroidGroupTestP, AddGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700496 DeltaArchiveManifest expected;
497 AddGroupAndPartition(
498 &expected, T("new_group"), 2_GiB, T("new_partition"), 2_GiB);
499
500 DeltaArchiveManifest update_manifest;
501 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
502 AddGroupAndPartition(&update_manifest, "oem", 1_GiB, "vendor", 1_GiB);
503 AddGroupAndPartition(
504 &update_manifest, "new_group", 2_GiB, "new_partition", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700505 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700506 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700507}
508
509TEST_P(DynamicPartitionControlAndroidGroupTestP, RemoveGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700510 DeltaArchiveManifest update_manifest;
511 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700512
513 EXPECT_TRUE(UpdatePartitionMetadata(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700514 source_manifest, update_manifest, Not(HasGroup(T("oem")))));
Yifan Hongc049f932019-07-23 15:06:05 -0700515}
516
517TEST_P(DynamicPartitionControlAndroidGroupTestP, ResizeGroup) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700518 DeltaArchiveManifest expected;
519 AddGroupAndPartition(&expected, T("android"), 2_GiB, T("system"), 2_GiB);
520 AddGroupAndPartition(&expected, T("oem"), 3_GiB, T("vendor"), 3_GiB);
521 DeltaArchiveManifest update_manifest;
522 AddGroupAndPartition(&update_manifest, "android", 2_GiB, "system", 2_GiB),
523 AddGroupAndPartition(&update_manifest, "oem", 3_GiB, "vendor", 3_GiB);
Yifan Hongc049f932019-07-23 15:06:05 -0700524 EXPECT_TRUE(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700525 UpdatePartitionMetadata(source_manifest, update_manifest, expected));
Yifan Hongc049f932019-07-23 15:06:05 -0700526}
527
528INSTANTIATE_TEST_CASE_P(DynamicPartitionControlAndroidTest,
529 DynamicPartitionControlAndroidGroupTestP,
530 testing::Values(TestParam{0, 1}, TestParam{1, 0}));
531
532const PartitionSuffixSizes update_sizes_0() {
533 // Initial state is 0 for "other" slot.
534 return {
535 {"grown_a", 2_GiB},
536 {"shrunk_a", 1_GiB},
537 {"same_a", 100_MiB},
538 {"deleted_a", 150_MiB},
539 // no added_a
540 {"grown_b", 200_MiB},
541 // simulate system_other
542 {"shrunk_b", 0},
543 {"same_b", 0},
544 {"deleted_b", 0},
545 // no added_b
546 };
547}
548
549const PartitionSuffixSizes update_sizes_1() {
550 return {
551 {"grown_a", 2_GiB},
552 {"shrunk_a", 1_GiB},
553 {"same_a", 100_MiB},
554 {"deleted_a", 150_MiB},
555 // no added_a
556 {"grown_b", 3_GiB},
557 {"shrunk_b", 150_MiB},
558 {"same_b", 100_MiB},
559 {"added_b", 150_MiB},
560 // no deleted_b
561 };
562}
563
564const PartitionSuffixSizes update_sizes_2() {
565 return {
566 {"grown_a", 4_GiB},
567 {"shrunk_a", 100_MiB},
568 {"same_a", 100_MiB},
569 {"deleted_a", 64_MiB},
570 // no added_a
571 {"grown_b", 3_GiB},
572 {"shrunk_b", 150_MiB},
573 {"same_b", 100_MiB},
574 {"added_b", 150_MiB},
575 // no deleted_b
576 };
577}
578
579// Test case for first update after the device is manufactured, in which
580// case the "other" slot is likely of size "0" (except system, which is
581// non-zero because of system_other partition)
582TEST_F(DynamicPartitionControlAndroidTest, SimulatedFirstUpdate) {
583 SetSlots({0, 1});
584
585 SetMetadata(source(), update_sizes_0());
586 SetMetadata(target(), update_sizes_0());
587 ExpectStoreMetadata(update_sizes_1());
588 ExpectUnmap({"grown_b", "shrunk_b", "same_b", "added_b"});
589
590 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 3_GiB},
591 {"shrunk", 150_MiB},
592 {"same", 100_MiB},
593 {"added", 150_MiB}}));
594}
595
596// After first update, test for the second update. In the second update, the
597// "added" partition is deleted and "deleted" partition is re-added.
598TEST_F(DynamicPartitionControlAndroidTest, SimulatedSecondUpdate) {
599 SetSlots({1, 0});
600
601 SetMetadata(source(), update_sizes_1());
602 SetMetadata(target(), update_sizes_0());
603
604 ExpectStoreMetadata(update_sizes_2());
605 ExpectUnmap({"grown_a", "shrunk_a", "same_a", "deleted_a"});
606
607 EXPECT_TRUE(PreparePartitionsForUpdate({{"grown", 4_GiB},
608 {"shrunk", 100_MiB},
609 {"same", 100_MiB},
610 {"deleted", 64_MiB}}));
611}
612
Yifan Hong3a1a5612019-11-05 16:34:32 -0800613TEST_F(DynamicPartitionControlAndroidTest, ApplyingToCurrentSlot) {
614 SetSlots({1, 1});
615 EXPECT_FALSE(PreparePartitionsForUpdate({}))
616 << "Should not be able to apply to current slot.";
617}
618
Yifan Hongc049f932019-07-23 15:06:05 -0700619} // namespace chromeos_update_engine