Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(620)

Side by Side Diff: net/reporting/reporting_service_unittest.cc

Issue 2249213002: [OBSOLETE] Reporting: Initial implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "net/reporting/reporting_service.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/json/json_reader.h"
12 #include "base/memory/ptr_util.h"
13 #include "base/test/simple_test_tick_clock.h"
14 #include "base/values.h"
15 #include "net/reporting/reporting_uploader.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "url/gurl.h"
18
19 namespace net {
20 namespace {
21
22 class MockUploader : public ReportingUploader {
23 public:
24 class PendingDelivery {
25 public:
26 PendingDelivery(MockUploader* uploader,
27 const GURL& url,
28 const std::string& json,
29 const Callback& callback)
30 : uploader_(uploader), url_(url), json_(json), callback_(callback) {
31 DCHECK(uploader_);
32 }
33
34 ~PendingDelivery() {}
35
36 void Complete(Outcome outcome) {
37 callback_.Run(outcome);
38 // Deletes |this|.
39 uploader_->OnDeliveryComplete(this);
40 }
41
42 const GURL& url() const { return url_; }
43 const std::string& json() const { return json_; }
44
45 private:
46 MockUploader* uploader_;
47 GURL url_;
48 std::string json_;
49 Callback callback_;
50 };
51
52 MockUploader() {}
53 ~MockUploader() override {}
54
55 void AttemptDelivery(const GURL& url,
56 const std::string& json,
57 const Callback& callback) override {
58 deliveries_.push_back(
59 base::MakeUnique<PendingDelivery>(this, url, json, callback));
60 }
61
62 const std::vector<std::unique_ptr<PendingDelivery>>& GetPendingDeliveries()
63 const {
64 return deliveries_;
65 }
66
67 void OnDeliveryComplete(PendingDelivery* delivery) {
68 for (auto it = deliveries_.begin(); it != deliveries_.end(); ++it) {
69 if (it->get() == delivery) {
70 deliveries_.erase(it);
71 return;
72 }
73 }
74 NOTREACHED();
75 }
76
77 private:
78 std::vector<std::unique_ptr<PendingDelivery>> deliveries_;
79 };
80
81 class ReportingServiceTest : public ::testing::Test {
82 protected:
83 ReportingServiceTest() {}
84
85 void CreateServiceWithDefaultPolicy() {
86 ReportingService::Policy policy = ReportingService::Policy::GetDefault();
87 CreateServiceWithPolicy(policy);
88 }
89
90 void CreateServiceWithPolicy(const ReportingService::Policy& policy) {
91 policy_ = policy;
92 service_ = base::MakeUnique<ReportingService>(policy);
93 clock_ = new base::SimpleTestTickClock();
94 service_->set_clock_for_testing(base::WrapUnique(clock_));
95 uploader_ = new MockUploader();
96 service_->set_uploader(base::WrapUnique(uploader_));
97 }
98
99 void QueueReport(const GURL& url) {
100 service_->QueueReport(base::MakeUnique<base::DictionaryValue>(), url,
101 url.GetOrigin(), "default", "test");
102 }
103
104 const std::vector<std::unique_ptr<MockUploader::PendingDelivery>>&
105 GetPendingDeliveries() {
106 return uploader_->GetPendingDeliveries();
107 }
108
109 bool HasEndpoint(const std::string& endpoint_url) {
110 return service_->HasEndpointForTesting(GURL(endpoint_url));
111 }
112
113 bool HasClient(const std::string& endpoint_url,
114 const std::string& origin_url) {
115 return service_->HasClientForTesting(GURL(endpoint_url), GURL(origin_url));
116 }
117
118 int GetEndpointFailures(const std::string& endpoint_url) {
119 return service_->GetEndpointFailuresForTesting(GURL(endpoint_url));
120 }
121
122 // |policy_| is a copy of the policy used to configure |service_|, for easier
123 // reference.
124 ReportingService::Policy policy_;
125 // |clock_| and |uploader_| are owned by |service_|, not the test.
126 base::SimpleTestTickClock* clock_;
127 MockUploader* uploader_;
128 std::unique_ptr<ReportingService> service_;
129 };
130
131 TEST_F(ReportingServiceTest, ProcessHeaderFromInsecureOrigin) {
132 CreateServiceWithDefaultPolicy();
133
134 service_->ProcessHeader(GURL("http://insecure/"),
135 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
136 EXPECT_FALSE(HasClient("https://endpoint/", "http://insecure"));
137 }
138
139 TEST_F(ReportingServiceTest, ProcessInvalidHeaders) {
140 static const struct {
141 const char* header_value;
142 const char* description;
143 } kInvalidHeaderTestCases[] = {
144 {"{\"max-age\":1}", "missing url"},
145 {"{\"url\":0,\"max-age\":1}", "non-string url"},
146 {"{\"url\":\"http://insecure/\",\"max-age\":1}", "insecure url"},
147
148 {"{\"url\":\"https://endpoint/\"}", "missing max-age"},
149 {"{\"url\":\"https://endpoint/\",\"max-age\":\"\"}",
150 "non-integer max-age"},
151 {"{\"url\":\"https://endpoint/\",\"max-age\":-1}", "negative max-age"},
152
153 {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"group\":0}",
154 "non-string group"},
155
156 {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"includeSubdomains\":0}",
157 "non-boolean includeSubdomains"},
158 };
159
160 CreateServiceWithDefaultPolicy();
161
162 for (size_t i = 0; i < arraysize(kInvalidHeaderTestCases); ++i) {
163 auto& test_case = kInvalidHeaderTestCases[i];
164 service_->ProcessHeader(GURL("https://origin/"), test_case.header_value);
165 EXPECT_FALSE(HasClient("https://endpoint/", "https://origin/"));
166 }
167 }
168
169 TEST_F(ReportingServiceTest, ProcessValidHeader) {
170 CreateServiceWithDefaultPolicy();
171
172 service_->ProcessHeader(GURL("https://origin/"),
173 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
174 EXPECT_TRUE(HasClient("https://endpoint/", "https://origin/"));
175
176 #if 0
177 EXPECT_EQ(1u, GetCache().GetEndpoints().size());
178 const std::unique_ptr<ReportingEndpoint>* endpoint_ptr =
179 GetCache().GetEndpoint(GURL("https://endpoint/"));
180 ASSERT_TRUE(endpoint_ptr);
181 const std::unique_ptr<ReportingEndpoint>& endpoint = *endpoint_ptr;
182 EXPECT_EQ(GURL("https://endpoint/"), endpoint->url);
183
184 EXPECT_EQ(1u, endpoint->clients.count(GURL("https://origin/")));
185 auto client_it = endpoint->clients.find(GURL("https://origin/"));
186 ASSERT_TRUE(client_it != endpoint->clients.end());
187 const ReportingClient& client = client_it->second;
188 EXPECT_EQ(GURL("https://origin"), client.origin);
189 EXPECT_FALSE(client.subdomains);
190 EXPECT_EQ("default", client.group);
191 EXPECT_EQ(base::TimeDelta::FromSeconds(1), client.ttl);
192 #endif
193 }
194
195 TEST_F(ReportingServiceTest, ProcessZeroMaxAgeHeader) {
196 CreateServiceWithDefaultPolicy();
197
198 service_->ProcessHeader(GURL("https://origin/"),
199 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
200 EXPECT_TRUE(HasClient("https://endpoint/", "https://origin/"));
201 service_->ProcessHeader(GURL("https://origin/"),
202 "{\"url\":\"https://endpoint/\",\"max-age\":0}");
203 EXPECT_FALSE(HasClient("https://endpoint/", "https://origin/"));
204 }
205
206 TEST_F(ReportingServiceTest, DeliverySuccess) {
207 CreateServiceWithDefaultPolicy();
208
209 service_->ProcessHeader(GURL("https://origin/"),
210 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
211 QueueReport(GURL("https://origin/path"));
212 service_->SendReports();
213
214 ASSERT_EQ(1u, GetPendingDeliveries().size());
215 const std::unique_ptr<MockUploader::PendingDelivery>& delivery =
216 GetPendingDeliveries()[0];
217 EXPECT_EQ(GURL("https://endpoint/"), delivery->url());
218 {
219 auto reports_value = base::JSONReader::Read(delivery->json());
220 const base::ListValue* reports;
221 ASSERT_TRUE(reports_value->GetAsList(&reports));
222 ASSERT_EQ(1u, reports->GetSize());
223 const base::DictionaryValue* report;
224 ASSERT_TRUE(reports->GetDictionary(0u, &report));
225 std::string type;
226 ASSERT_TRUE(report->GetString("type", &type));
227 EXPECT_EQ("test", type);
228 std::string url;
229 ASSERT_TRUE(report->GetString("url", &url));
230 EXPECT_EQ("https://origin/path", url);
231 }
232
233 delivery->Complete(ReportingUploader::SUCCESS);
234
235 EXPECT_EQ(0, GetEndpointFailures("https://endpoint/"));
236 }
237
238 TEST_F(ReportingServiceTest, DeliveryFailure) {
239 CreateServiceWithDefaultPolicy();
240
241 service_->ProcessHeader(GURL("https://origin/"),
242 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
243 QueueReport(GURL("https://origin/path"));
244 service_->SendReports();
245
246 GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
247
248 EXPECT_EQ(1, GetEndpointFailures("https://endpoint/"));
249 }
250
251 TEST_F(ReportingServiceTest, DeliveryRemoveEndpoint) {
252 CreateServiceWithDefaultPolicy();
253
254 service_->ProcessHeader(GURL("https://origin/"),
255 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
256 QueueReport(GURL("https://origin/path"));
257 service_->SendReports();
258
259 GetPendingDeliveries()[0]->Complete(ReportingUploader::REMOVE_ENDPOINT);
260
261 EXPECT_FALSE(HasClient("https://endpoint/", "https://origin/"));
262 }
263
264 TEST_F(ReportingServiceTest, NoDeliveryToPendingEndpoint) {
265 CreateServiceWithDefaultPolicy();
266
267 service_->ProcessHeader(GURL("https://origin/"),
268 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
269 QueueReport(GURL("https://origin/"));
270 service_->SendReports();
271
272 GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
273
274 // Without advancing the clock, the endpoint should still be pending, so the
275 // Manager should not try to deliver reports to it.
276 service_->SendReports();
277
278 EXPECT_TRUE(GetPendingDeliveries().empty());
279 }
280
281 TEST_F(ReportingServiceTest, NoDeliveryToMismatchedEndpoint) {
282 CreateServiceWithDefaultPolicy();
283
284 service_->ProcessHeader(GURL("https://origin1/"),
285 "{\"url\":\"https://endpoint1/\",\"max-age\":1}");
286 QueueReport(GURL("https://origin2/"));
287 service_->SendReports();
288
289 EXPECT_TRUE(GetPendingDeliveries().empty());
290 }
291
292 TEST_F(ReportingServiceTest, BatchReportsForSameOrigin) {
293 CreateServiceWithDefaultPolicy();
294
295 service_->ProcessHeader(GURL("https://origin/"),
296 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
297 QueueReport(GURL("https://origin/"));
298 QueueReport(GURL("https://origin/"));
299 service_->SendReports();
300
301 EXPECT_EQ(1u, GetPendingDeliveries().size());
302
303 GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
304 }
305
306 TEST_F(ReportingServiceTest, BatchReportsForSameEndpoint) {
307 CreateServiceWithDefaultPolicy();
308
309 service_->ProcessHeader(GURL("https://origin1/"),
310 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
311 service_->ProcessHeader(GURL("https://origin2/"),
312 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
313 QueueReport(GURL("https://origin1/"));
314 QueueReport(GURL("https://origin2/"));
315 service_->SendReports();
316
317 EXPECT_EQ(1u, GetPendingDeliveries().size());
318
319 GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
320 }
321
322 TEST_F(ReportingServiceTest, ExpiredEndpoint) {
323 CreateServiceWithDefaultPolicy();
324
325 service_->ProcessHeader(GURL("https://origin/"),
326 "{\"url\":\"https://endpoint/\",\"max-age\":1}");
327 EXPECT_TRUE(HasEndpoint("https://endpoint/"));
328
329 clock_->Advance(base::TimeDelta::FromSeconds(2));
330 service_->CollectGarbageForTesting();
331 EXPECT_FALSE(HasEndpoint("https://endpoint/"));
332 }
333
334 TEST_F(ReportingServiceTest, UnusedEndpoint) {
335 CreateServiceWithDefaultPolicy();
336
337 service_->ProcessHeader(
338 GURL("https://origin/"),
339 "{\"url\":\"https://endpoint/\",\"max-age\":999999999}");
340 EXPECT_TRUE(HasEndpoint("https://endpoint/"));
341
342 clock_->Advance(2 * policy_.endpoint_lifetime);
343 service_->CollectGarbageForTesting();
344 EXPECT_FALSE(HasEndpoint("https://endpoint/"));
345 }
346
347 TEST_F(ReportingServiceTest, FailedEndpoint) {
348 ReportingService::Policy policy = ReportingService::Policy::GetDefault();
349 policy.endpoint_backoff.initial_delay_ms = 0;
350 policy.endpoint_backoff.maximum_backoff_ms = 0;
351 policy.endpoint_backoff.entry_lifetime_ms = 1000;
352 policy.max_endpoint_failures = 5;
353 policy.max_report_failures = 999;
354 CreateServiceWithPolicy(policy);
355
356 service_->ProcessHeader(
357 GURL("https://origin/"),
358 "{\"url\":\"https://endpoint/\",\"max-age\":999999999}");
359
360 QueueReport(GURL("https://origin/"));
361
362 for (int i = 0; i < policy_.max_endpoint_failures + 1; i++) {
363 EXPECT_TRUE(HasEndpoint("https://endpoint/"));
364 service_->SendReports();
365 EXPECT_EQ(1u, GetPendingDeliveries().size());
366 GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
367 }
368 service_->CollectGarbageForTesting();
369 EXPECT_TRUE(HasEndpoint("https://endpoint/"));
370
371 clock_->Advance(base::TimeDelta::FromMilliseconds(
372 2 * policy_.endpoint_backoff.entry_lifetime_ms));
373
374 service_->CollectGarbageForTesting();
375 EXPECT_FALSE(HasEndpoint("https://endpoint/"));
376 }
377
378 TEST_F(ReportingServiceTest, EvictedEndpoint) {
379 ReportingService::Policy policy = ReportingService::Policy::GetDefault();
380 policy.max_endpoint_count = 1;
381 CreateServiceWithPolicy(policy);
382
383 service_->ProcessHeader(GURL("https://origin1/"),
384 "{\"url\":\"https://endpoint1/\",\"max-age\":1}");
385 EXPECT_TRUE(HasEndpoint("https://endpoint1"));
386
387 service_->ProcessHeader(GURL("https://origin2/"),
388 "{\"url\":\"https://endpoint2/\",\"max-age\":1}");
389 EXPECT_FALSE(HasEndpoint("https://endpoint1"));
390 EXPECT_TRUE(HasEndpoint("https://endpoint2"));
391 }
392
393 // TODO: Test:
394 // Expired report (happens after lifetime passes -> GC)
395 // Failed report (happens after failed attempt -> attempt)
396 // Evicted report (happens after queue or failed attempt -> queue)
397 // No-action cases (e.g. don't evict pending report).
398
399 } // namespace
400 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698