blob: 61d8e0a34b74b7d7a1f505be302ce37991e43cd6 [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#ifndef UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
18#define UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_
19
20#include <stdint.h>
21
22#include <iostream>
23#include <map>
24#include <memory>
25#include <string>
26#include <vector>
27
28#include <base/strings/string_util.h>
29#include <fs_mgr.h>
30#include <gmock/gmock.h>
31#include <gtest/gtest.h>
32#include <liblp/builder.h>
Yifan Hong87ea73f2019-09-12 13:07:37 -070033#include <storage_literals/storage_literals.h>
Yifan Hongc049f932019-07-23 15:06:05 -070034
35#include "update_engine/common/boot_control_interface.h"
36
37namespace chromeos_update_engine {
38
39using android::fs_mgr::MetadataBuilder;
40using testing::_;
41using testing::MakeMatcher;
42using testing::Matcher;
43using testing::MatcherInterface;
44using testing::MatchResultListener;
Yifan Hong87ea73f2019-09-12 13:07:37 -070045using namespace android::storage_literals; // NOLINT(build/namespaces)
Yifan Hongc049f932019-07-23 15:06:05 -070046
47constexpr const uint32_t kMaxNumSlots = 2;
48constexpr const char* kSlotSuffixes[kMaxNumSlots] = {"_a", "_b"};
49constexpr const char* kFakeDevicePath = "/fake/dev/path/";
50constexpr const char* kFakeDmDevicePath = "/fake/dm/dev/path/";
51constexpr const uint32_t kFakeMetadataSize = 65536;
52constexpr const char* kDefaultGroup = "foo";
Yifan Hong700d7c12019-07-23 20:49:16 -070053constexpr const char* kFakeSuper = "fake_super";
Yifan Hongc049f932019-07-23 15:06:05 -070054
55// A map describing the size of each partition.
56// "{name, size}"
57using PartitionSizes = std::map<std::string, uint64_t>;
58
59// "{name_a, size}"
60using PartitionSuffixSizes = std::map<std::string, uint64_t>;
61
62using PartitionMetadata = BootControlInterface::PartitionMetadata;
63
Yifan Hongc049f932019-07-23 15:06:05 -070064constexpr uint64_t kDefaultGroupSize = 5_GiB;
65// Super device size. 1 MiB for metadata.
66constexpr uint64_t kDefaultSuperSize = kDefaultGroupSize * 2 + 1_MiB;
67
68template <typename U, typename V>
69inline std::ostream& operator<<(std::ostream& os, const std::map<U, V>& param) {
70 os << "{";
71 bool first = true;
72 for (const auto& pair : param) {
73 if (!first)
74 os << ", ";
75 os << pair.first << ":" << pair.second;
76 first = false;
77 }
78 return os << "}";
79}
80
81template <typename T>
82inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& param) {
83 os << "[";
84 bool first = true;
85 for (const auto& e : param) {
86 if (!first)
87 os << ", ";
88 os << e;
89 first = false;
90 }
91 return os << "]";
92}
93
94inline std::ostream& operator<<(std::ostream& os,
95 const PartitionMetadata::Partition& p) {
96 return os << "{" << p.name << ", " << p.size << "}";
97}
98
99inline std::ostream& operator<<(std::ostream& os,
100 const PartitionMetadata::Group& g) {
101 return os << "{" << g.name << ", " << g.size << ", " << g.partitions << "}";
102}
103
104inline std::ostream& operator<<(std::ostream& os, const PartitionMetadata& m) {
105 return os << m.groups;
106}
107
108inline std::string GetDevice(const std::string& name) {
109 return kFakeDevicePath + name;
110}
111
112inline std::string GetDmDevice(const std::string& name) {
113 return kFakeDmDevicePath + name;
114}
115
Yifan Hongc049f932019-07-23 15:06:05 -0700116// To support legacy tests, auto-convert {name_a: size} map to
117// PartitionMetadata.
118inline PartitionMetadata PartitionSuffixSizesToMetadata(
119 const PartitionSuffixSizes& partition_sizes) {
120 PartitionMetadata metadata;
121 for (const char* suffix : kSlotSuffixes) {
122 metadata.groups.push_back(
123 {std::string(kDefaultGroup) + suffix, kDefaultGroupSize, {}});
124 }
125 for (const auto& pair : partition_sizes) {
126 for (size_t suffix_idx = 0; suffix_idx < kMaxNumSlots; ++suffix_idx) {
127 if (base::EndsWith(pair.first,
128 kSlotSuffixes[suffix_idx],
129 base::CompareCase::SENSITIVE)) {
130 metadata.groups[suffix_idx].partitions.push_back(
131 {pair.first, pair.second});
132 }
133 }
134 }
135 return metadata;
136}
137
138// To support legacy tests, auto-convert {name: size} map to PartitionMetadata.
139inline PartitionMetadata PartitionSizesToMetadata(
140 const PartitionSizes& partition_sizes) {
141 PartitionMetadata metadata;
142 metadata.groups.push_back(
143 {std::string{kDefaultGroup}, kDefaultGroupSize, {}});
144 for (const auto& pair : partition_sizes) {
145 metadata.groups[0].partitions.push_back({pair.first, pair.second});
146 }
147 return metadata;
148}
149
150inline std::unique_ptr<MetadataBuilder> NewFakeMetadata(
151 const PartitionMetadata& metadata) {
152 auto builder =
153 MetadataBuilder::New(kDefaultSuperSize, kFakeMetadataSize, kMaxNumSlots);
154 EXPECT_GE(builder->AllocatableSpace(), kDefaultGroupSize * 2);
155 EXPECT_NE(nullptr, builder);
156 if (builder == nullptr)
157 return nullptr;
158 for (const auto& group : metadata.groups) {
159 EXPECT_TRUE(builder->AddGroup(group.name, group.size));
160 for (const auto& partition : group.partitions) {
161 auto p = builder->AddPartition(partition.name, group.name, 0 /* attr */);
162 EXPECT_TRUE(p && builder->ResizePartition(p, partition.size));
163 }
164 }
165 return builder;
166}
167
168class MetadataMatcher : public MatcherInterface<MetadataBuilder*> {
169 public:
170 explicit MetadataMatcher(const PartitionSuffixSizes& partition_sizes)
171 : partition_metadata_(PartitionSuffixSizesToMetadata(partition_sizes)) {}
172 explicit MetadataMatcher(const PartitionMetadata& partition_metadata)
173 : partition_metadata_(partition_metadata) {}
174
175 bool MatchAndExplain(MetadataBuilder* metadata,
176 MatchResultListener* listener) const override {
177 bool success = true;
178 for (const auto& group : partition_metadata_.groups) {
179 for (const auto& partition : group.partitions) {
180 auto p = metadata->FindPartition(partition.name);
181 if (p == nullptr) {
182 if (!success)
183 *listener << "; ";
184 *listener << "No partition " << partition.name;
185 success = false;
186 continue;
187 }
188 if (p->size() != partition.size) {
189 if (!success)
190 *listener << "; ";
191 *listener << "Partition " << partition.name << " has size "
192 << p->size() << ", expected " << partition.size;
193 success = false;
194 }
195 if (p->group_name() != group.name) {
196 if (!success)
197 *listener << "; ";
198 *listener << "Partition " << partition.name << " has group "
199 << p->group_name() << ", expected " << group.name;
200 success = false;
201 }
202 }
203 }
204 return success;
205 }
206
207 void DescribeTo(std::ostream* os) const override {
208 *os << "expect: " << partition_metadata_;
209 }
210
211 void DescribeNegationTo(std::ostream* os) const override {
212 *os << "expect not: " << partition_metadata_;
213 }
214
215 private:
216 PartitionMetadata partition_metadata_;
217};
218
219inline Matcher<MetadataBuilder*> MetadataMatches(
220 const PartitionSuffixSizes& partition_sizes) {
221 return MakeMatcher(new MetadataMatcher(partition_sizes));
222}
223
224inline Matcher<MetadataBuilder*> MetadataMatches(
225 const PartitionMetadata& partition_metadata) {
226 return MakeMatcher(new MetadataMatcher(partition_metadata));
227}
228
229MATCHER_P(HasGroup, group, " has group " + group) {
230 auto groups = arg->ListGroups();
231 return std::find(groups.begin(), groups.end(), group) != groups.end();
232}
233
234struct TestParam {
235 uint32_t source;
236 uint32_t target;
237};
238inline std::ostream& operator<<(std::ostream& os, const TestParam& param) {
239 return os << "{source: " << param.source << ", target:" << param.target
240 << "}";
241}
242
243} // namespace chromeos_update_engine
244
245#endif // UPDATE_ENGINE_DYNAMIC_PARTITION_TEST_UTILS_H_