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