1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/dns/host_resolver_internal_result_test_util.h"
6
7 #include <map>
8 #include <optional>
9 #include <ostream>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "base/check.h"
15 #include "base/json/json_writer.h"
16 #include "base/time/time.h"
17 #include "net/base/connection_endpoint_metadata.h"
18 #include "net/base/host_port_pair.h"
19 #include "net/base/ip_endpoint.h"
20 #include "net/dns/host_resolver_internal_result.h"
21 #include "net/dns/https_record_rdata.h"
22 #include "net/dns/public/dns_query_type.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace net {
27
28 using ::testing::AllOf;
29 using ::testing::Eq;
30 using ::testing::MakeMatcher;
31 using ::testing::Matcher;
32 using ::testing::MatchResultListener;
33 using ::testing::PrintToString;
34 using ::testing::Property;
35 using ::testing::StringMatchResultListener;
36
37 namespace {
38
39 class HostResolverInternalResultBaseMatcher
40 : public ::testing::MatcherInterface<const HostResolverInternalResult&> {
41 public:
HostResolverInternalResultBaseMatcher(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher)42 HostResolverInternalResultBaseMatcher(
43 std::string expected_domain_name,
44 DnsQueryType expected_query_type,
45 HostResolverInternalResult::Source expected_source,
46 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
47 Matcher<std::optional<base::Time>> timed_expiration_matcher)
48 : expected_domain_name_(std::move(expected_domain_name)),
49 expected_query_type_(expected_query_type),
50 expected_source_(expected_source),
51 expiration_matcher_(std::move(expiration_matcher)),
52 timed_expiration_matcher_(std::move(timed_expiration_matcher)) {}
53 ~HostResolverInternalResultBaseMatcher() override = default;
54
MatchAndExplain(const HostResolverInternalResult & result,MatchResultListener * result_listener) const55 bool MatchAndExplain(const HostResolverInternalResult& result,
56 MatchResultListener* result_listener) const override {
57 if (result.type() == GetSubtype()) {
58 *result_listener << "which is type ";
59 NameSubtype(*result_listener);
60 } else {
61 *result_listener << "which is not type ";
62 NameSubtype(*result_listener);
63 return false;
64 }
65
66 StringMatchResultListener base_listener;
67 bool base_matches = MatchAndExplainBaseProperties(result, base_listener);
68 StringMatchResultListener subtype_listener;
69 bool subtype_matches =
70 MatchAndExplainSubtypeProperties(result, subtype_listener);
71
72 // If only one part mismatches, just explain that.
73 if (!base_matches || subtype_matches) {
74 *result_listener << ", and " << base_listener.str();
75 }
76 if (!subtype_matches || base_matches) {
77 *result_listener << ", and " << subtype_listener.str();
78 }
79
80 return base_matches && subtype_matches;
81 }
82
DescribeTo(std::ostream * os) const83 void DescribeTo(std::ostream* os) const override {
84 *os << "matches ";
85 Describe(*os);
86 }
87
DescribeNegationTo(std::ostream * os) const88 void DescribeNegationTo(std::ostream* os) const override {
89 *os << "does not match ";
90 Describe(*os);
91 }
92
93 protected:
94 virtual HostResolverInternalResult::Type GetSubtype() const = 0;
95 virtual void NameSubtype(MatchResultListener& result_listener) const = 0;
96 virtual bool MatchAndExplainSubtypeProperties(
97 const HostResolverInternalResult& result,
98 MatchResultListener& result_listener) const = 0;
99 virtual void DescribeSubtype(std::ostream& os) const = 0;
100
101 private:
MatchAndExplainBaseProperties(const HostResolverInternalResult & result,MatchResultListener & result_listener) const102 bool MatchAndExplainBaseProperties(
103 const HostResolverInternalResult& result,
104 MatchResultListener& result_listener) const {
105 return ExplainMatchResult(
106 AllOf(Property("domain_name", &HostResolverInternalResult::domain_name,
107 Eq(expected_domain_name_)),
108 Property("query_type", &HostResolverInternalResult::query_type,
109 Eq(expected_query_type_)),
110 Property("source", &HostResolverInternalResult::source,
111 Eq(expected_source_)),
112 Property("expiration", &HostResolverInternalResult::expiration,
113 expiration_matcher_),
114 Property("timed_expiration",
115 &HostResolverInternalResult::timed_expiration,
116 timed_expiration_matcher_)),
117 result, &result_listener);
118 }
119
Describe(std::ostream & os) const120 void Describe(std::ostream& os) const {
121 os << "\n HostResolverInternalResult {";
122 DescribeBase(os);
123 DescribeSubtype(os);
124 os << "\n }\n";
125 }
126
DescribeBase(std::ostream & os) const127 void DescribeBase(std::ostream& os) const {
128 StringMatchResultListener subtype_name_listener;
129 NameSubtype(subtype_name_listener);
130
131 os << "\n domain_name: \"" << expected_domain_name_
132 << "\"\n query_type: " << kDnsQueryTypes.at(expected_query_type_)
133 << "\n type: " << subtype_name_listener.str()
134 << "\n source: " << static_cast<int>(expected_source_)
135 << "\n expiration: " << PrintToString(expiration_matcher_)
136 << "\n timed_expiration: "
137 << PrintToString(timed_expiration_matcher_);
138 }
139
140 std::string expected_domain_name_;
141 DnsQueryType expected_query_type_;
142 HostResolverInternalResult::Source expected_source_;
143 Matcher<std::optional<base::TimeTicks>> expiration_matcher_;
144 Matcher<std::optional<base::Time>> timed_expiration_matcher_;
145 };
146
147 class HostResolverInternalDataResultMatcher
148 : public HostResolverInternalResultBaseMatcher {
149 public:
HostResolverInternalDataResultMatcher(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,Matcher<std::vector<IPEndPoint>> endpoints_matcher,Matcher<std::vector<std::string>> strings_matcher,Matcher<std::vector<HostPortPair>> hosts_matcher)150 HostResolverInternalDataResultMatcher(
151 std::string expected_domain_name,
152 DnsQueryType expected_query_type,
153 HostResolverInternalResult::Source expected_source,
154 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
155 Matcher<std::optional<base::Time>> timed_expiration_matcher,
156 Matcher<std::vector<IPEndPoint>> endpoints_matcher,
157 Matcher<std::vector<std::string>> strings_matcher,
158 Matcher<std::vector<HostPortPair>> hosts_matcher)
159 : HostResolverInternalResultBaseMatcher(
160 std::move(expected_domain_name),
161 expected_query_type,
162 expected_source,
163 std::move(expiration_matcher),
164 std::move(timed_expiration_matcher)),
165 endpoints_matcher_(std::move(endpoints_matcher)),
166 strings_matcher_(std::move(strings_matcher)),
167 hosts_matcher_(std::move(hosts_matcher)) {}
168
169 ~HostResolverInternalDataResultMatcher() override = default;
170
171 HostResolverInternalDataResultMatcher(
172 const HostResolverInternalDataResultMatcher&) = default;
173 HostResolverInternalDataResultMatcher& operator=(
174 const HostResolverInternalDataResultMatcher&) = default;
175 HostResolverInternalDataResultMatcher(
176 HostResolverInternalDataResultMatcher&&) = default;
177 HostResolverInternalDataResultMatcher& operator=(
178 HostResolverInternalDataResultMatcher&&) = default;
179
180 protected:
GetSubtype() const181 HostResolverInternalResult::Type GetSubtype() const override {
182 return HostResolverInternalResult::Type::kData;
183 }
184
NameSubtype(MatchResultListener & result_listener) const185 void NameSubtype(MatchResultListener& result_listener) const override {
186 result_listener << "kData";
187 }
188
MatchAndExplainSubtypeProperties(const HostResolverInternalResult & result,MatchResultListener & result_listener) const189 bool MatchAndExplainSubtypeProperties(
190 const HostResolverInternalResult& result,
191 MatchResultListener& result_listener) const override {
192 return ExplainMatchResult(
193 AllOf(Property("endpoints", &HostResolverInternalDataResult::endpoints,
194 endpoints_matcher_),
195 Property("strings", &HostResolverInternalDataResult::strings,
196 strings_matcher_),
197 Property("hosts", &HostResolverInternalDataResult::hosts,
198 hosts_matcher_)),
199 result.AsData(), &result_listener);
200 }
201
DescribeSubtype(std::ostream & os) const202 void DescribeSubtype(std::ostream& os) const override {
203 os << "\n endpoints: " << PrintToString(endpoints_matcher_)
204 << "\n strings: " << PrintToString(strings_matcher_)
205 << "\n hosts: " << PrintToString(hosts_matcher_);
206 }
207
208 private:
209 Matcher<std::vector<IPEndPoint>> endpoints_matcher_;
210 Matcher<std::vector<std::string>> strings_matcher_;
211 Matcher<std::vector<HostPortPair>> hosts_matcher_;
212 };
213
214 class HostResolverInternalMetadataResultMatcher
215 : public HostResolverInternalResultBaseMatcher {
216 public:
HostResolverInternalMetadataResultMatcher(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,Matcher<std::multimap<HttpsRecordPriority,ConnectionEndpointMetadata>> metadatas_matcher)217 HostResolverInternalMetadataResultMatcher(
218 std::string expected_domain_name,
219 DnsQueryType expected_query_type,
220 HostResolverInternalResult::Source expected_source,
221 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
222 Matcher<std::optional<base::Time>> timed_expiration_matcher,
223 Matcher<std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>>
224 metadatas_matcher)
225 : HostResolverInternalResultBaseMatcher(
226 std::move(expected_domain_name),
227 expected_query_type,
228 expected_source,
229 std::move(expiration_matcher),
230 std::move(timed_expiration_matcher)),
231 metadatas_matcher_(std::move(metadatas_matcher)) {}
232
233 ~HostResolverInternalMetadataResultMatcher() override = default;
234
235 HostResolverInternalMetadataResultMatcher(
236 const HostResolverInternalMetadataResultMatcher&) = default;
237 HostResolverInternalMetadataResultMatcher& operator=(
238 const HostResolverInternalMetadataResultMatcher&) = default;
239 HostResolverInternalMetadataResultMatcher(
240 HostResolverInternalMetadataResultMatcher&&) = default;
241 HostResolverInternalMetadataResultMatcher& operator=(
242 HostResolverInternalMetadataResultMatcher&&) = default;
243
244 protected:
GetSubtype() const245 HostResolverInternalResult::Type GetSubtype() const override {
246 return HostResolverInternalResult::Type::kMetadata;
247 }
248
NameSubtype(MatchResultListener & result_listener) const249 void NameSubtype(MatchResultListener& result_listener) const override {
250 result_listener << "kMetadata";
251 }
252
MatchAndExplainSubtypeProperties(const HostResolverInternalResult & result,MatchResultListener & result_listener) const253 bool MatchAndExplainSubtypeProperties(
254 const HostResolverInternalResult& result,
255 MatchResultListener& result_listener) const override {
256 return ExplainMatchResult(
257 Property("metadatas", &HostResolverInternalMetadataResult::metadatas,
258 metadatas_matcher_),
259 result.AsMetadata(), &result_listener);
260 }
261
DescribeSubtype(std::ostream & os) const262 void DescribeSubtype(std::ostream& os) const override {
263 os << "\n metadatas: " << PrintToString(metadatas_matcher_);
264 }
265
266 private:
267 Matcher<std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>>
268 metadatas_matcher_;
269 };
270
271 class HostResolverInternalErrorResultMatcher
272 : public HostResolverInternalResultBaseMatcher {
273 public:
HostResolverInternalErrorResultMatcher(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,int expected_error)274 HostResolverInternalErrorResultMatcher(
275 std::string expected_domain_name,
276 DnsQueryType expected_query_type,
277 HostResolverInternalResult::Source expected_source,
278 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
279 Matcher<std::optional<base::Time>> timed_expiration_matcher,
280 int expected_error)
281 : HostResolverInternalResultBaseMatcher(
282 std::move(expected_domain_name),
283 expected_query_type,
284 expected_source,
285 std::move(expiration_matcher),
286 std::move(timed_expiration_matcher)),
287 expected_error_(expected_error) {}
288
289 ~HostResolverInternalErrorResultMatcher() override = default;
290
291 HostResolverInternalErrorResultMatcher(
292 const HostResolverInternalErrorResultMatcher&) = default;
293 HostResolverInternalErrorResultMatcher& operator=(
294 const HostResolverInternalErrorResultMatcher&) = default;
295 HostResolverInternalErrorResultMatcher(
296 HostResolverInternalErrorResultMatcher&&) = default;
297 HostResolverInternalErrorResultMatcher& operator=(
298 HostResolverInternalErrorResultMatcher&&) = default;
299
300 protected:
GetSubtype() const301 HostResolverInternalResult::Type GetSubtype() const override {
302 return HostResolverInternalResult::Type::kError;
303 }
304
NameSubtype(MatchResultListener & result_listener) const305 void NameSubtype(MatchResultListener& result_listener) const override {
306 result_listener << "kError";
307 }
308
MatchAndExplainSubtypeProperties(const HostResolverInternalResult & result,MatchResultListener & result_listener) const309 bool MatchAndExplainSubtypeProperties(
310 const HostResolverInternalResult& result,
311 MatchResultListener& result_listener) const override {
312 return ExplainMatchResult(
313 Property("error", &HostResolverInternalErrorResult::error,
314 Eq(expected_error_)),
315 result.AsError(), &result_listener);
316 }
317
DescribeSubtype(std::ostream & os) const318 void DescribeSubtype(std::ostream& os) const override {
319 os << "\n error: " << expected_error_;
320 }
321
322 private:
323 int expected_error_;
324 };
325
326 class HostResolverInternalAliasResultMatcher
327 : public HostResolverInternalResultBaseMatcher {
328 public:
HostResolverInternalAliasResultMatcher(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,std::string expected_alias_target)329 HostResolverInternalAliasResultMatcher(
330 std::string expected_domain_name,
331 DnsQueryType expected_query_type,
332 HostResolverInternalResult::Source expected_source,
333 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
334 Matcher<std::optional<base::Time>> timed_expiration_matcher,
335 std::string expected_alias_target)
336 : HostResolverInternalResultBaseMatcher(
337 std::move(expected_domain_name),
338 expected_query_type,
339 expected_source,
340 std::move(expiration_matcher),
341 std::move(timed_expiration_matcher)),
342 expected_alias_target_(std::move(expected_alias_target)) {}
343
344 ~HostResolverInternalAliasResultMatcher() override = default;
345
346 HostResolverInternalAliasResultMatcher(
347 const HostResolverInternalAliasResultMatcher&) = default;
348 HostResolverInternalAliasResultMatcher& operator=(
349 const HostResolverInternalAliasResultMatcher&) = default;
350 HostResolverInternalAliasResultMatcher(
351 HostResolverInternalAliasResultMatcher&&) = default;
352 HostResolverInternalAliasResultMatcher& operator=(
353 HostResolverInternalAliasResultMatcher&&) = default;
354
355 protected:
GetSubtype() const356 HostResolverInternalResult::Type GetSubtype() const override {
357 return HostResolverInternalResult::Type::kAlias;
358 }
359
NameSubtype(MatchResultListener & result_listener) const360 void NameSubtype(MatchResultListener& result_listener) const override {
361 result_listener << "kAlias";
362 }
363
MatchAndExplainSubtypeProperties(const HostResolverInternalResult & result,MatchResultListener & result_listener) const364 bool MatchAndExplainSubtypeProperties(
365 const HostResolverInternalResult& result,
366 MatchResultListener& result_listener) const override {
367 return ExplainMatchResult(
368 Property("alias_target", &HostResolverInternalAliasResult::alias_target,
369 Eq(expected_alias_target_)),
370 result.AsAlias(), &result_listener);
371 }
372
DescribeSubtype(std::ostream & os) const373 void DescribeSubtype(std::ostream& os) const override {
374 os << "\n target: \"" << expected_alias_target_ << "\"";
375 }
376
377 private:
378 std::string expected_alias_target_;
379 };
380
381 } // namespace
382
ExpectHostResolverInternalDataResult(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,Matcher<std::vector<IPEndPoint>> endpoints_matcher,Matcher<std::vector<std::string>> strings_matcher,Matcher<std::vector<HostPortPair>> hosts_matcher)383 Matcher<const HostResolverInternalResult&> ExpectHostResolverInternalDataResult(
384 std::string expected_domain_name,
385 DnsQueryType expected_query_type,
386 HostResolverInternalResult::Source expected_source,
387 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
388 Matcher<std::optional<base::Time>> timed_expiration_matcher,
389 Matcher<std::vector<IPEndPoint>> endpoints_matcher,
390 Matcher<std::vector<std::string>> strings_matcher,
391 Matcher<std::vector<HostPortPair>> hosts_matcher) {
392 return MakeMatcher(new HostResolverInternalDataResultMatcher(
393 std::move(expected_domain_name), expected_query_type, expected_source,
394 std::move(expiration_matcher), std::move(timed_expiration_matcher),
395 std::move(endpoints_matcher), std::move(strings_matcher),
396 std::move(hosts_matcher)));
397 }
398
399 testing::Matcher<const HostResolverInternalResult&>
ExpectHostResolverInternalMetadataResult(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,testing::Matcher<std::optional<base::TimeTicks>> expiration_matcher,testing::Matcher<std::optional<base::Time>> timed_expiration_matcher,testing::Matcher<std::multimap<HttpsRecordPriority,ConnectionEndpointMetadata>> metadatas_matcher)400 ExpectHostResolverInternalMetadataResult(
401 std::string expected_domain_name,
402 DnsQueryType expected_query_type,
403 HostResolverInternalResult::Source expected_source,
404 testing::Matcher<std::optional<base::TimeTicks>> expiration_matcher,
405 testing::Matcher<std::optional<base::Time>> timed_expiration_matcher,
406 testing::Matcher<
407 std::multimap<HttpsRecordPriority, ConnectionEndpointMetadata>>
408 metadatas_matcher) {
409 return MakeMatcher(new HostResolverInternalMetadataResultMatcher(
410 std::move(expected_domain_name), expected_query_type, expected_source,
411 std::move(expiration_matcher), std::move(timed_expiration_matcher),
412 std::move(metadatas_matcher)));
413 }
414
415 Matcher<const HostResolverInternalResult&>
ExpectHostResolverInternalErrorResult(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,int expected_error)416 ExpectHostResolverInternalErrorResult(
417 std::string expected_domain_name,
418 DnsQueryType expected_query_type,
419 HostResolverInternalResult::Source expected_source,
420 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
421 Matcher<std::optional<base::Time>> timed_expiration_matcher,
422 int expected_error) {
423 return MakeMatcher(new HostResolverInternalErrorResultMatcher(
424 std::move(expected_domain_name), expected_query_type, expected_source,
425 std::move(expiration_matcher), std::move(timed_expiration_matcher),
426 expected_error));
427 }
428
429 Matcher<const HostResolverInternalResult&>
ExpectHostResolverInternalAliasResult(std::string expected_domain_name,DnsQueryType expected_query_type,HostResolverInternalResult::Source expected_source,Matcher<std::optional<base::TimeTicks>> expiration_matcher,Matcher<std::optional<base::Time>> timed_expiration_matcher,std::string expected_alias_target)430 ExpectHostResolverInternalAliasResult(
431 std::string expected_domain_name,
432 DnsQueryType expected_query_type,
433 HostResolverInternalResult::Source expected_source,
434 Matcher<std::optional<base::TimeTicks>> expiration_matcher,
435 Matcher<std::optional<base::Time>> timed_expiration_matcher,
436 std::string expected_alias_target) {
437 return MakeMatcher(new HostResolverInternalAliasResultMatcher(
438 std::move(expected_domain_name), expected_query_type, expected_source,
439 std::move(expiration_matcher), std::move(timed_expiration_matcher),
440 std::move(expected_alias_target)));
441 }
442
operator <<(std::ostream & os,const HostResolverInternalResult & result)443 std::ostream& operator<<(std::ostream& os,
444 const HostResolverInternalResult& result) {
445 std::string json_string;
446 CHECK(base::JSONWriter::Write(result.ToValue(), &json_string));
447 return os << json_string;
448 }
449
450 } // namespace net
451