[Tizen][M34-Merge] Implement favicon database get API
[platform/framework/web/chromium-efl.git] / net / network_error_logging / network_error_logging_service_unittest.cc
1 // Copyright 2017 The Chromium Authors. All rights reserved.
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 <memory>
6 #include <string>
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/macros.h"
12 #include "base/test/values_test_util.h"
13 #include "base/time/time.h"
14 #include "base/values.h"
15 #include "net/base/ip_address.h"
16 #include "net/base/net_errors.h"
17 #include "net/network_error_logging/network_error_logging_delegate.h"
18 #include "net/network_error_logging/network_error_logging_service.h"
19 #include "net/reporting/reporting_policy.h"
20 #include "net/reporting/reporting_service.h"
21 #include "net/socket/next_proto.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "url/gurl.h"
24 #include "url/origin.h"
25
26 namespace net {
27 namespace {
28
29 class TestReportingService : public ReportingService {
30  public:
31   struct Report {
32     Report() = default;
33
34     Report(Report&& other)
35         : url(other.url),
36           group(other.group),
37           type(other.type),
38           body(std::move(other.body)),
39           depth(other.depth) {}
40
41     Report(const GURL& url,
42            const std::string& group,
43            const std::string& type,
44            std::unique_ptr<const base::Value> body,
45            int depth)
46         : url(url),
47           group(group),
48           type(type),
49           body(std::move(body)),
50           depth(depth) {}
51
52     ~Report() = default;
53
54     GURL url;
55     std::string group;
56     std::string type;
57     std::unique_ptr<const base::Value> body;
58     int depth;
59
60    private:
61     DISALLOW_COPY(Report);
62   };
63
64   TestReportingService() = default;
65
66   const std::vector<Report>& reports() const { return reports_; }
67
68   // ReportingService implementation:
69
70   ~TestReportingService() override = default;
71
72   void QueueReport(const GURL& url,
73                    const std::string& group,
74                    const std::string& type,
75                    std::unique_ptr<const base::Value> body,
76                    int depth) override {
77     reports_.push_back(Report(url, group, type, std::move(body), depth));
78   }
79
80   void ProcessHeader(const GURL& url,
81                      const std::string& header_value) override {
82     NOTREACHED();
83   }
84
85   void RemoveBrowsingData(int data_type_mask,
86                           const base::RepeatingCallback<bool(const GURL&)>&
87                               origin_filter) override {
88     NOTREACHED();
89   }
90
91   int GetUploadDepth(const URLRequest& request) override {
92     NOTREACHED();
93     return 0;
94   }
95
96   const ReportingPolicy& GetPolicy() const override {
97     NOTREACHED();
98     return dummy_policy_;
99   }
100
101  private:
102   std::vector<Report> reports_;
103   ReportingPolicy dummy_policy_;
104
105   DISALLOW_COPY_AND_ASSIGN(TestReportingService);
106 };
107
108 class NetworkErrorLoggingServiceTest : public ::testing::Test {
109  protected:
110   NetworkErrorLoggingServiceTest() {
111     service_ = NetworkErrorLoggingService::Create(
112         NetworkErrorLoggingDelegate::Create());
113     CreateReportingService();
114   }
115
116   void CreateReportingService() {
117     DCHECK(!reporting_service_);
118
119     reporting_service_ = std::make_unique<TestReportingService>();
120     service_->SetReportingService(reporting_service_.get());
121   }
122
123   void DestroyReportingService() {
124     DCHECK(reporting_service_);
125
126     service_->SetReportingService(nullptr);
127     reporting_service_.reset();
128   }
129
130   NetworkErrorLoggingService::RequestDetails
131   MakeRequestDetails(GURL url, Error error_type, int status_code = 0) {
132     NetworkErrorLoggingService::RequestDetails details;
133
134     details.uri = url;
135     details.referrer = kReferrer_;
136     details.server_ip = IPAddress::IPv4AllZeros();
137     details.protocol = kProtoUnknown;
138     details.status_code = status_code;
139     details.elapsed_time = base::TimeDelta::FromSeconds(1);
140     details.type = error_type;
141     details.reporting_upload_depth = 0;
142
143     return details;
144   }
145
146   NetworkErrorLoggingService* service() { return service_.get(); }
147   const std::vector<TestReportingService::Report>& reports() {
148     return reporting_service_->reports();
149   }
150
151   const GURL kUrl_ = GURL("https://example.com/path");
152   const GURL kUrlDifferentPort_ = GURL("https://example.com:4433/path");
153   const GURL kUrlSubdomain_ = GURL("https://subdomain.example.com/path");
154   const GURL kUrlDifferentHost_ = GURL("https://example2.com/path");
155
156   const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
157   const url::Origin kOriginDifferentPort_ =
158       url::Origin::Create(kUrlDifferentPort_);
159   const url::Origin kOriginSubdomain_ = url::Origin::Create(kUrlSubdomain_);
160   const url::Origin kOriginDifferentHost_ =
161       url::Origin::Create(kUrlDifferentHost_);
162
163   const std::string kHeader_ = "{\"report-to\":\"group\",\"max-age\":86400}";
164   const std::string kHeaderIncludeSubdomains_ =
165       "{\"report-to\":\"group\",\"max-age\":86400,\"includeSubdomains\":true}";
166   const std::string kHeaderMaxAge0_ = "{\"max-age\":0}";
167   const std::string kHeaderTooLong_ =
168       "{\"report-to\":\"group\",\"max-age\":86400,\"junk\":\"" +
169       std::string(32 * 1024, 'a') + "\"}";
170   const std::string kHeaderTooDeep_ =
171       "{\"report-to\":\"group\",\"max-age\":86400,\"junk\":[[[[[[[[[[]]]]]]]]]]"
172       "}";
173
174   const std::string kGroup_ = "group";
175
176   const std::string kType_ = NetworkErrorLoggingService::kReportType;
177
178   const GURL kReferrer_ = GURL("https://referrer.com/");
179
180  private:
181   std::unique_ptr<NetworkErrorLoggingService> service_;
182   std::unique_ptr<TestReportingService> reporting_service_;
183 };
184
185 void ExpectDictDoubleValue(double expected_value,
186                            const base::DictionaryValue& value,
187                            const std::string& key) {
188   double double_value = 0.0;
189   EXPECT_TRUE(value.GetDouble(key, &double_value)) << key;
190   EXPECT_DOUBLE_EQ(expected_value, double_value) << key;
191 }
192
193 TEST_F(NetworkErrorLoggingServiceTest, CreateService) {
194   // Service is created by default in the test fixture..
195   EXPECT_TRUE(service());
196 }
197
198 TEST_F(NetworkErrorLoggingServiceTest, NoReportingService) {
199   DestroyReportingService();
200
201   service()->OnHeader(kOrigin_, kHeader_);
202
203   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
204 }
205
206 TEST_F(NetworkErrorLoggingServiceTest, OriginInsecure) {
207   const GURL kInsecureUrl("http://insecure.com/");
208   const url::Origin kInsecureOrigin = url::Origin::Create(kInsecureUrl);
209
210   service()->OnHeader(kInsecureOrigin, kHeader_);
211
212   service()->OnRequest(
213       MakeRequestDetails(kInsecureUrl, ERR_CONNECTION_REFUSED));
214
215   EXPECT_TRUE(reports().empty());
216 }
217
218 TEST_F(NetworkErrorLoggingServiceTest, NoPolicyForOrigin) {
219   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
220
221   EXPECT_TRUE(reports().empty());
222 }
223
224 TEST_F(NetworkErrorLoggingServiceTest, JsonTooLong) {
225   service()->OnHeader(kOrigin_, kHeaderTooLong_);
226
227   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
228
229   EXPECT_TRUE(reports().empty());
230 }
231
232 TEST_F(NetworkErrorLoggingServiceTest, JsonTooDeep) {
233   service()->OnHeader(kOrigin_, kHeaderTooDeep_);
234
235   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
236
237   EXPECT_TRUE(reports().empty());
238 }
239
240 TEST_F(NetworkErrorLoggingServiceTest, SuccessReportQueued) {
241   static const std::string kHeaderSuccessFraction1 =
242       "{\"report-to\":\"group\",\"max-age\":86400,\"success-fraction\":1.0}";
243   service()->OnHeader(kOrigin_, kHeaderSuccessFraction1);
244
245   service()->OnRequest(MakeRequestDetails(kUrl_, OK));
246
247   ASSERT_EQ(1u, reports().size());
248   EXPECT_EQ(kUrl_, reports()[0].url);
249   EXPECT_EQ(kGroup_, reports()[0].group);
250   EXPECT_EQ(kType_, reports()[0].type);
251   EXPECT_EQ(0, reports()[0].depth);
252
253   const base::DictionaryValue* body;
254   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
255   base::ExpectDictStringValue(kUrl_.spec(), *body,
256                               NetworkErrorLoggingService::kUriKey);
257   base::ExpectDictStringValue(kReferrer_.spec(), *body,
258                               NetworkErrorLoggingService::kReferrerKey);
259   // TODO(juliatuttle): Extract these constants.
260   ExpectDictDoubleValue(1.0, *body,
261                         NetworkErrorLoggingService::kSamplingFractionKey);
262   base::ExpectDictStringValue("0.0.0.0", *body,
263                               NetworkErrorLoggingService::kServerIpKey);
264   base::ExpectDictStringValue("", *body,
265                               NetworkErrorLoggingService::kProtocolKey);
266   base::ExpectDictIntegerValue(0, *body,
267                                NetworkErrorLoggingService::kStatusCodeKey);
268   base::ExpectDictIntegerValue(1000, *body,
269                                NetworkErrorLoggingService::kElapsedTimeKey);
270   base::ExpectDictStringValue("ok", *body,
271                               NetworkErrorLoggingService::kTypeKey);
272 }
273
274 TEST_F(NetworkErrorLoggingServiceTest, FailureReportQueued) {
275   static const std::string kHeaderFailureFraction1 =
276       "{\"report-to\":\"group\",\"max-age\":86400,\"failure-fraction\":1.0}";
277   service()->OnHeader(kOrigin_, kHeaderFailureFraction1);
278
279   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
280
281   ASSERT_EQ(1u, reports().size());
282   EXPECT_EQ(kUrl_, reports()[0].url);
283   EXPECT_EQ(kGroup_, reports()[0].group);
284   EXPECT_EQ(kType_, reports()[0].type);
285   EXPECT_EQ(0, reports()[0].depth);
286
287   const base::DictionaryValue* body;
288   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
289   base::ExpectDictStringValue(kUrl_.spec(), *body,
290                               NetworkErrorLoggingService::kUriKey);
291   base::ExpectDictStringValue(kReferrer_.spec(), *body,
292                               NetworkErrorLoggingService::kReferrerKey);
293   // TODO(juliatuttle): Extract these constants.
294   ExpectDictDoubleValue(1.0, *body,
295                         NetworkErrorLoggingService::kSamplingFractionKey);
296   base::ExpectDictStringValue("0.0.0.0", *body,
297                               NetworkErrorLoggingService::kServerIpKey);
298   base::ExpectDictStringValue("", *body,
299                               NetworkErrorLoggingService::kProtocolKey);
300   base::ExpectDictIntegerValue(0, *body,
301                                NetworkErrorLoggingService::kStatusCodeKey);
302   base::ExpectDictIntegerValue(1000, *body,
303                                NetworkErrorLoggingService::kElapsedTimeKey);
304   base::ExpectDictStringValue("tcp.refused", *body,
305                               NetworkErrorLoggingService::kTypeKey);
306 }
307
308 TEST_F(NetworkErrorLoggingServiceTest, HttpErrorReportQueued) {
309   static const std::string kHeaderFailureFraction1 =
310       "{\"report-to\":\"group\",\"max-age\":86400,\"failure-fraction\":1.0}";
311   service()->OnHeader(kOrigin_, kHeaderFailureFraction1);
312
313   service()->OnRequest(MakeRequestDetails(kUrl_, OK, 504));
314
315   ASSERT_EQ(1u, reports().size());
316   EXPECT_EQ(kUrl_, reports()[0].url);
317   EXPECT_EQ(kGroup_, reports()[0].group);
318   EXPECT_EQ(kType_, reports()[0].type);
319   EXPECT_EQ(0, reports()[0].depth);
320
321   const base::DictionaryValue* body;
322   ASSERT_TRUE(reports()[0].body->GetAsDictionary(&body));
323   base::ExpectDictStringValue(kUrl_.spec(), *body,
324                               NetworkErrorLoggingService::kUriKey);
325   base::ExpectDictStringValue(kReferrer_.spec(), *body,
326                               NetworkErrorLoggingService::kReferrerKey);
327   // TODO(juliatuttle): Extract these constants.
328   ExpectDictDoubleValue(1.0, *body,
329                         NetworkErrorLoggingService::kSamplingFractionKey);
330   base::ExpectDictStringValue("0.0.0.0", *body,
331                               NetworkErrorLoggingService::kServerIpKey);
332   base::ExpectDictStringValue("", *body,
333                               NetworkErrorLoggingService::kProtocolKey);
334   base::ExpectDictIntegerValue(504, *body,
335                                NetworkErrorLoggingService::kStatusCodeKey);
336   base::ExpectDictIntegerValue(1000, *body,
337                                NetworkErrorLoggingService::kElapsedTimeKey);
338   base::ExpectDictStringValue("http.error", *body,
339                               NetworkErrorLoggingService::kTypeKey);
340 }
341
342 TEST_F(NetworkErrorLoggingServiceTest, MaxAge0) {
343   service()->OnHeader(kOrigin_, kHeader_);
344
345   service()->OnHeader(kOrigin_, kHeaderMaxAge0_);
346
347   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
348
349   EXPECT_TRUE(reports().empty());
350 }
351
352 TEST_F(NetworkErrorLoggingServiceTest, SuccessFraction0) {
353   static const std::string kHeaderSuccessFraction0 =
354       "{\"report-to\":\"group\",\"max-age\":86400,\"success-fraction\":0.0}";
355   service()->OnHeader(kOrigin_, kHeaderSuccessFraction0);
356
357   // Each network error has a 0% chance of being reported.  Fire off several and
358   // verify that no reports are produced.
359   constexpr size_t kReportCount = 100;
360   for (size_t i = 0; i < kReportCount; ++i)
361     service()->OnRequest(MakeRequestDetails(kUrl_, OK));
362
363   EXPECT_TRUE(reports().empty());
364 }
365
366 TEST_F(NetworkErrorLoggingServiceTest, SuccessFractionHalf) {
367   // Include a different value for failure-fraction to ensure that we copy the
368   // right value into sampling-fraction.
369   static const std::string kHeaderSuccessFractionHalf =
370       "{\"report-to\":\"group\",\"max-age\":86400,\"success-fraction\":0.5,"
371       "\"failure-fraction\":0.25}";
372   service()->OnHeader(kOrigin_, kHeaderSuccessFractionHalf);
373
374   // Each network error has a 50% chance of being reported.  Fire off several
375   // and verify that some requests were reported and some weren't.  (We can't
376   // verify exact counts because each decision is made randomly.)
377   constexpr size_t kReportCount = 100;
378   for (size_t i = 0; i < kReportCount; ++i)
379     service()->OnRequest(MakeRequestDetails(kUrl_, OK));
380
381   // If our random selection logic is correct, there is a 2^-100 chance that
382   // every single report above was skipped.  If this check fails, it's much more
383   // likely that our code is wrong.
384   EXPECT_FALSE(reports().empty());
385
386   // There's also a 2^-100 chance that every single report was logged.  Same as
387   // above, that's much more likely to be a code error.
388   EXPECT_GT(kReportCount, reports().size());
389
390   for (const auto& report : reports()) {
391     const base::DictionaryValue* body;
392     ASSERT_TRUE(report.body->GetAsDictionary(&body));
393     // Our header includes a different value for failure-fraction, so that this
394     // check verifies that we copy the correct fraction into sampling-fraction.
395     ExpectDictDoubleValue(0.5, *body,
396                           NetworkErrorLoggingService::kSamplingFractionKey);
397   }
398 }
399
400 TEST_F(NetworkErrorLoggingServiceTest, FailureFraction0) {
401   static const std::string kHeaderFailureFraction0 =
402       "{\"report-to\":\"group\",\"max-age\":86400,\"failure-fraction\":0.0}";
403   service()->OnHeader(kOrigin_, kHeaderFailureFraction0);
404
405   // Each network error has a 0% chance of being reported.  Fire off several and
406   // verify that no reports are produced.
407   constexpr size_t kReportCount = 100;
408   for (size_t i = 0; i < kReportCount; ++i)
409     service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
410
411   EXPECT_TRUE(reports().empty());
412 }
413
414 TEST_F(NetworkErrorLoggingServiceTest, FailureFractionHalf) {
415   // Include a different value for success-fraction to ensure that we copy the
416   // right value into sampling-fraction.
417   static const std::string kHeaderFailureFractionHalf =
418       "{\"report-to\":\"group\",\"max-age\":86400,\"failure-fraction\":0.5,"
419       "\"success-fraction\":0.25}";
420   service()->OnHeader(kOrigin_, kHeaderFailureFractionHalf);
421
422   // Each network error has a 50% chance of being reported.  Fire off several
423   // and verify that some requests were reported and some weren't.  (We can't
424   // verify exact counts because each decision is made randomly.)
425   constexpr size_t kReportCount = 100;
426   for (size_t i = 0; i < kReportCount; ++i)
427     service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
428
429   // If our random selection logic is correct, there is a 2^-100 chance that
430   // every single report above was skipped.  If this check fails, it's much more
431   // likely that our code is wrong.
432   EXPECT_FALSE(reports().empty());
433
434   // There's also a 2^-100 chance that every single report was logged.  Same as
435   // above, that's much more likely to be a code error.
436   EXPECT_GT(kReportCount, reports().size());
437
438   for (const auto& report : reports()) {
439     const base::DictionaryValue* body;
440     ASSERT_TRUE(report.body->GetAsDictionary(&body));
441     ExpectDictDoubleValue(0.5, *body,
442                           NetworkErrorLoggingService::kSamplingFractionKey);
443   }
444 }
445
446 TEST_F(NetworkErrorLoggingServiceTest,
447        ExcludeSubdomainsDoesntMatchDifferentPort) {
448   service()->OnHeader(kOrigin_, kHeader_);
449
450   service()->OnRequest(
451       MakeRequestDetails(kUrlDifferentPort_, ERR_CONNECTION_REFUSED));
452
453   EXPECT_TRUE(reports().empty());
454 }
455
456 TEST_F(NetworkErrorLoggingServiceTest, ExcludeSubdomainsDoesntMatchSubdomain) {
457   service()->OnHeader(kOrigin_, kHeader_);
458
459   service()->OnRequest(
460       MakeRequestDetails(kUrlSubdomain_, ERR_CONNECTION_REFUSED));
461
462   EXPECT_TRUE(reports().empty());
463 }
464
465 TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsMatchesDifferentPort) {
466   service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_);
467
468   service()->OnRequest(
469       MakeRequestDetails(kUrlDifferentPort_, ERR_CONNECTION_REFUSED));
470
471   ASSERT_EQ(1u, reports().size());
472   EXPECT_EQ(kUrlDifferentPort_, reports()[0].url);
473 }
474
475 TEST_F(NetworkErrorLoggingServiceTest, IncludeSubdomainsMatchesSubdomain) {
476   service()->OnHeader(kOrigin_, kHeaderIncludeSubdomains_);
477
478   service()->OnRequest(
479       MakeRequestDetails(kUrlSubdomain_, ERR_CONNECTION_REFUSED));
480
481   ASSERT_EQ(1u, reports().size());
482 }
483
484 TEST_F(NetworkErrorLoggingServiceTest,
485        IncludeSubdomainsDoesntMatchSuperdomain) {
486   service()->OnHeader(kOriginSubdomain_, kHeaderIncludeSubdomains_);
487
488   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
489
490   EXPECT_TRUE(reports().empty());
491 }
492
493 TEST_F(NetworkErrorLoggingServiceTest, RemoveAllBrowsingData) {
494   service()->OnHeader(kOrigin_, kHeader_);
495
496   service()->RemoveBrowsingData(base::RepeatingCallback<bool(const GURL&)>());
497
498   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
499
500   EXPECT_TRUE(reports().empty());
501 }
502
503 TEST_F(NetworkErrorLoggingServiceTest, RemoveSomeBrowsingData) {
504   service()->OnHeader(kOrigin_, kHeader_);
505   service()->OnHeader(kOriginDifferentHost_, kHeader_);
506
507   service()->RemoveBrowsingData(
508       base::BindRepeating([](const GURL& origin) -> bool {
509         return origin.host() == "example.com";
510       }));
511
512   service()->OnRequest(MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED));
513
514   EXPECT_TRUE(reports().empty());
515
516   service()->OnRequest(
517       MakeRequestDetails(kUrlDifferentHost_, ERR_CONNECTION_REFUSED));
518
519   ASSERT_EQ(1u, reports().size());
520 }
521
522 TEST_F(NetworkErrorLoggingServiceTest, Nested) {
523   service()->OnHeader(kOrigin_, kHeader_);
524
525   NetworkErrorLoggingService::RequestDetails details =
526       MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED);
527   details.reporting_upload_depth =
528       NetworkErrorLoggingService::kMaxNestedReportDepth;
529   service()->OnRequest(details);
530
531   ASSERT_EQ(1u, reports().size());
532   EXPECT_EQ(NetworkErrorLoggingService::kMaxNestedReportDepth,
533             reports()[0].depth);
534 }
535
536 TEST_F(NetworkErrorLoggingServiceTest, NestedTooDeep) {
537   service()->OnHeader(kOrigin_, kHeader_);
538
539   NetworkErrorLoggingService::RequestDetails details =
540       MakeRequestDetails(kUrl_, ERR_CONNECTION_REFUSED);
541   details.reporting_upload_depth =
542       NetworkErrorLoggingService::kMaxNestedReportDepth + 1;
543   service()->OnRequest(details);
544
545   EXPECT_TRUE(reports().empty());
546 }
547
548 }  // namespace
549 }  // namespace net