blob: 6277f9aa1a79598fd10a11db3830f4fa5e901f61 [file] [log] [blame]
juliatuttle381d77e2017-04-07 18:54:121// 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 "net/reporting/reporting_service.h"
6
7#include <memory>
8#include <string>
9
Sam Burnettf13c06b2019-07-30 15:53:4910#include "base/bind.h"
juliatuttle381d77e2017-04-07 18:54:1211#include "base/memory/ptr_util.h"
12#include "base/time/tick_clock.h"
13#include "base/values.h"
Sam Burnettf13c06b2019-07-30 15:53:4914#include "net/reporting/mock_persistent_reporting_store.h"
15#include "net/reporting/reporting_browsing_data_remover.h"
juliatuttle381d77e2017-04-07 18:54:1216#include "net/reporting/reporting_cache.h"
17#include "net/reporting/reporting_context.h"
juliatuttle381d77e2017-04-07 18:54:1218#include "net/reporting/reporting_policy.h"
19#include "net/reporting/reporting_report.h"
20#include "net/reporting/reporting_service.h"
21#include "net/reporting/reporting_test_util.h"
Bence Béky98447b12018-05-08 03:14:0122#include "net/test/test_with_scoped_task_environment.h"
Sam Burnettf13c06b2019-07-30 15:53:4923#include "testing/gmock/include/gmock/gmock.h"
juliatuttle381d77e2017-04-07 18:54:1224#include "testing/gtest/include/gtest/gtest.h"
25
26namespace net {
27namespace {
28
Sam Burnettf13c06b2019-07-30 15:53:4929using CommandType = MockPersistentReportingStore::Command::Type;
30
31// The tests are parametrized on a boolean value which represents whether to use
32// a MockPersistentReportingStore (if false, no store is used).
33class ReportingServiceTest : public ::testing::TestWithParam<bool>,
34 public WithScopedTaskEnvironment {
juliatuttle381d77e2017-04-07 18:54:1235 protected:
36 const GURL kUrl_ = GURL("https://origin/path");
Sam Burnettf13c06b2019-07-30 15:53:4937 const GURL kUrl2_ = GURL("https://origin2/path");
Daniel Cheng88186bd52017-10-20 08:14:4638 const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
Sam Burnettf13c06b2019-07-30 15:53:4939 const url::Origin kOrigin2_ = url::Origin::Create(kUrl2_);
juliatuttle381d77e2017-04-07 18:54:1240 const GURL kEndpoint_ = GURL("https://endpoint/");
Douglas Creagerf6cb49f72018-07-19 20:14:5341 const std::string kUserAgent_ = "Mozilla/1.0";
juliatuttle381d77e2017-04-07 18:54:1242 const std::string kGroup_ = "group";
43 const std::string kType_ = "type";
44
Sam Burnettf13c06b2019-07-30 15:53:4945 ReportingServiceTest() {
46 if (GetParam())
47 store_ = std::make_unique<MockPersistentReportingStore>();
48 else
49 store_ = nullptr;
juliatuttle381d77e2017-04-07 18:54:1250
Sam Burnettf13c06b2019-07-30 15:53:4951 auto test_context = std::make_unique<TestReportingContext>(
52 &clock_, &tick_clock_, ReportingPolicy(), store_.get());
53 context_ = test_context.get();
54
55 service_ = ReportingService::CreateForTesting(std::move(test_context));
56 }
57
58 // If the store exists, simulate finishing loading the store, which should
59 // make the rest of the test run synchronously.
60 void FinishLoading(bool load_success) {
61 if (store_)
62 store_->FinishLoading(load_success);
63 }
64
65 MockPersistentReportingStore* store() { return store_.get(); }
juliatuttle381d77e2017-04-07 18:54:1266 TestReportingContext* context() { return context_; }
67 ReportingService* service() { return service_.get(); }
68
69 private:
tzik26331742017-12-07 07:28:3370 base::SimpleTestClock clock_;
71 base::SimpleTestTickClock tick_clock_;
72
Sam Burnettf13c06b2019-07-30 15:53:4973 std::unique_ptr<MockPersistentReportingStore> store_;
juliatuttle381d77e2017-04-07 18:54:1274 TestReportingContext* context_;
75 std::unique_ptr<ReportingService> service_;
76};
77
Sam Burnettf13c06b2019-07-30 15:53:4978TEST_P(ReportingServiceTest, QueueReport) {
Douglas Creagerf6cb49f72018-07-19 20:14:5379 service()->QueueReport(kUrl_, kUserAgent_, kGroup_, kType_,
Julia Tuttle107e30672018-03-29 18:48:4280 std::make_unique<base::DictionaryValue>(), 0);
Sam Burnettf13c06b2019-07-30 15:53:4981 FinishLoading(true /* load_success */);
juliatuttle381d77e2017-04-07 18:54:1282
83 std::vector<const ReportingReport*> reports;
84 context()->cache()->GetReports(&reports);
85 ASSERT_EQ(1u, reports.size());
86 EXPECT_EQ(kUrl_, reports[0]->url);
Douglas Creagerf6cb49f72018-07-19 20:14:5387 EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
juliatuttle381d77e2017-04-07 18:54:1288 EXPECT_EQ(kGroup_, reports[0]->group);
89 EXPECT_EQ(kType_, reports[0]->type);
90}
91
Sam Burnettf13c06b2019-07-30 15:53:4992TEST_P(ReportingServiceTest, QueueReportSanitizeUrl) {
Lily Chen8fed0dd72019-01-23 17:13:2793 // Same as kUrl_ but with username, password, and fragment.
94 GURL url = GURL("https://username:password@origin/path#fragment");
95 service()->QueueReport(url, kUserAgent_, kGroup_, kType_,
96 std::make_unique<base::DictionaryValue>(), 0);
Sam Burnettf13c06b2019-07-30 15:53:4997 FinishLoading(true /* load_success */);
Lily Chen8fed0dd72019-01-23 17:13:2798
99 std::vector<const ReportingReport*> reports;
100 context()->cache()->GetReports(&reports);
101 ASSERT_EQ(1u, reports.size());
102 EXPECT_EQ(kUrl_, reports[0]->url);
103 EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
104 EXPECT_EQ(kGroup_, reports[0]->group);
105 EXPECT_EQ(kType_, reports[0]->type);
106}
107
Sam Burnettf13c06b2019-07-30 15:53:49108TEST_P(ReportingServiceTest, DontQueueReportInvalidUrl) {
Lily Chen8fed0dd72019-01-23 17:13:27109 GURL url = GURL("https://");
Sam Burnettf13c06b2019-07-30 15:53:49110 // This does not trigger an attempt to load from the store because the url
111 // is immediately rejected as invalid.
Lily Chen8fed0dd72019-01-23 17:13:27112 service()->QueueReport(url, kUserAgent_, kGroup_, kType_,
113 std::make_unique<base::DictionaryValue>(), 0);
114
115 std::vector<const ReportingReport*> reports;
116 context()->cache()->GetReports(&reports);
117 ASSERT_EQ(0u, reports.size());
118}
119
Sam Burnettf13c06b2019-07-30 15:53:49120TEST_P(ReportingServiceTest, ProcessHeader) {
Douglas Creagerf0db63a2018-02-28 17:50:23121 service()->ProcessHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" +
122 kEndpoint_.spec() +
123 "\"}],"
juliatuttle381d77e2017-04-07 18:54:12124 "\"group\":\"" +
125 kGroup_ +
126 "\","
Douglas Creagerbca64422018-06-18 13:54:42127 "\"max_age\":86400}");
Sam Burnettf13c06b2019-07-30 15:53:49128 FinishLoading(true /* load_success */);
juliatuttle381d77e2017-04-07 18:54:12129
Lily Chenefb6fcf2019-04-19 04:17:54130 EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
juliatuttle381d77e2017-04-07 18:54:12131}
132
Sam Burnettf13c06b2019-07-30 15:53:49133TEST_P(ReportingServiceTest, ProcessHeader_TooLong) {
Julia Tuttle7d874942018-03-02 01:19:13134 const std::string header_too_long =
135 "{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
136 "\"}],"
137 "\"group\":\"" +
138 kGroup_ +
139 "\","
Douglas Creagerbca64422018-06-18 13:54:42140 "\"max_age\":86400," +
Julia Tuttle7d874942018-03-02 01:19:13141 "\"junk\":\"" + std::string(32 * 1024, 'a') + "\"}";
Sam Burnettf13c06b2019-07-30 15:53:49142 // This does not trigger an attempt to load from the store because the header
143 // is immediately rejected as invalid.
Julia Tuttle7d874942018-03-02 01:19:13144 service()->ProcessHeader(kUrl_, header_too_long);
145
Lily Chenefb6fcf2019-04-19 04:17:54146 EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
Julia Tuttle7d874942018-03-02 01:19:13147}
148
Sam Burnettf13c06b2019-07-30 15:53:49149TEST_P(ReportingServiceTest, ProcessHeader_TooDeep) {
Julia Tuttle7d874942018-03-02 01:19:13150 const std::string header_too_deep = "{\"endpoints\":[{\"url\":\"" +
151 kEndpoint_.spec() +
152 "\"}],"
153 "\"group\":\"" +
154 kGroup_ +
155 "\","
Douglas Creagerbca64422018-06-18 13:54:42156 "\"max_age\":86400," +
Julia Tuttle7d874942018-03-02 01:19:13157 "\"junk\":[[[[[[[[[[]]]]]]]]]]}";
Sam Burnettf13c06b2019-07-30 15:53:49158 // This does not trigger an attempt to load from the store because the header
159 // is immediately rejected as invalid.
Julia Tuttle7d874942018-03-02 01:19:13160 service()->ProcessHeader(kUrl_, header_too_deep);
161
Lily Chenefb6fcf2019-04-19 04:17:54162 EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
Julia Tuttle7d874942018-03-02 01:19:13163}
164
Sam Burnettf13c06b2019-07-30 15:53:49165TEST_P(ReportingServiceTest, WriteToStore) {
166 if (!store())
167 return;
168
169 MockPersistentReportingStore::CommandList expected_commands;
170
171 // This first call to any public method triggers a load. The load will block
172 // until we call FinishLoading.
173 service()->ProcessHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" +
174 kEndpoint_.spec() +
175 "\"}],"
176 "\"group\":\"" +
177 kGroup_ +
178 "\","
179 "\"max_age\":86400}");
180 expected_commands.emplace_back(CommandType::LOAD_REPORTING_CLIENTS);
181 EXPECT_THAT(store()->GetAllCommands(),
182 testing::UnorderedElementsAreArray(expected_commands));
183
184 // Unblock the load. The will let the remaining calls to the service complete
185 // without blocking.
186 FinishLoading(true /* load_success */);
187 expected_commands.emplace_back(
188 CommandType::ADD_REPORTING_ENDPOINT,
189 ReportingEndpoint(kOrigin_, kGroup_,
190 ReportingEndpoint::EndpointInfo{kEndpoint_}));
191 expected_commands.emplace_back(
192 CommandType::ADD_REPORTING_ENDPOINT_GROUP,
193 CachedReportingEndpointGroup(
194 kOrigin_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
195 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
196 EXPECT_THAT(store()->GetAllCommands(),
197 testing::UnorderedElementsAreArray(expected_commands));
198
199 service()->ProcessHeader(kUrl2_, "{\"endpoints\":[{\"url\":\"" +
200 kEndpoint_.spec() +
201 "\"}],"
202 "\"group\":\"" +
203 kGroup_ +
204 "\","
205 "\"max_age\":86400}");
206 expected_commands.emplace_back(
207 CommandType::ADD_REPORTING_ENDPOINT,
208 ReportingEndpoint(kOrigin2_, kGroup_,
209 ReportingEndpoint::EndpointInfo{kEndpoint_}));
210 expected_commands.emplace_back(
211 CommandType::ADD_REPORTING_ENDPOINT_GROUP,
212 CachedReportingEndpointGroup(
213 kOrigin2_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
214 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
215 EXPECT_THAT(store()->GetAllCommands(),
216 testing::UnorderedElementsAreArray(expected_commands));
217
218 service()->QueueReport(kUrl_, kUserAgent_, kGroup_, kType_,
219 std::make_unique<base::DictionaryValue>(), 0);
220 expected_commands.emplace_back(
221 CommandType::UPDATE_REPORTING_ENDPOINT_GROUP_ACCESS_TIME,
222 CachedReportingEndpointGroup(
223 kOrigin_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
224 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
225 EXPECT_THAT(store()->GetAllCommands(),
226 testing::UnorderedElementsAreArray(expected_commands));
227
228 service()->RemoveBrowsingData(ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS,
229 base::BindRepeating([](const GURL& url) {
230 return url.host() == "origin";
231 }));
232 expected_commands.emplace_back(
233 CommandType::DELETE_REPORTING_ENDPOINT,
234 ReportingEndpoint(kOrigin_, kGroup_,
235 ReportingEndpoint::EndpointInfo{kEndpoint_}));
236 expected_commands.emplace_back(
237 CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
238 CachedReportingEndpointGroup(
239 kOrigin_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
240 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
241 expected_commands.emplace_back(CommandType::FLUSH);
242 EXPECT_THAT(store()->GetAllCommands(),
243 testing::UnorderedElementsAreArray(expected_commands));
244
245 service()->RemoveAllBrowsingData(
246 ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS);
247 expected_commands.emplace_back(
248 CommandType::DELETE_REPORTING_ENDPOINT,
249 ReportingEndpoint(kOrigin2_, kGroup_,
250 ReportingEndpoint::EndpointInfo{kEndpoint_}));
251 expected_commands.emplace_back(
252 CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
253 CachedReportingEndpointGroup(
254 kOrigin2_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
255 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
256 expected_commands.emplace_back(CommandType::FLUSH);
257 EXPECT_THAT(store()->GetAllCommands(),
258 testing::UnorderedElementsAreArray(expected_commands));
259}
260
261TEST_P(ReportingServiceTest, WaitUntilLoadFinishesBeforeWritingToStore) {
262 if (!store())
263 return;
264
265 MockPersistentReportingStore::CommandList expected_commands;
266
267 // This first call to any public method triggers a load. The load will block
268 // until we call FinishLoading.
269 service()->ProcessHeader(kUrl_, "{\"endpoints\":[{\"url\":\"" +
270 kEndpoint_.spec() +
271 "\"}],"
272 "\"group\":\"" +
273 kGroup_ +
274 "\","
275 "\"max_age\":86400}");
276 expected_commands.emplace_back(CommandType::LOAD_REPORTING_CLIENTS);
277 EXPECT_THAT(store()->GetAllCommands(),
278 testing::UnorderedElementsAreArray(expected_commands));
279
280 service()->ProcessHeader(kUrl2_, "{\"endpoints\":[{\"url\":\"" +
281 kEndpoint_.spec() +
282 "\"}],"
283 "\"group\":\"" +
284 kGroup_ +
285 "\","
286 "\"max_age\":86400}");
287 EXPECT_THAT(store()->GetAllCommands(),
288 testing::UnorderedElementsAreArray(expected_commands));
289
290 service()->QueueReport(kUrl_, kUserAgent_, kGroup_, kType_,
291 std::make_unique<base::DictionaryValue>(), 0);
292 EXPECT_THAT(store()->GetAllCommands(),
293 testing::UnorderedElementsAreArray(expected_commands));
294
295 service()->RemoveBrowsingData(ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS,
296 base::BindRepeating([](const GURL& url) {
297 return url.host() == "origin";
298 }));
299 EXPECT_THAT(store()->GetAllCommands(),
300 testing::UnorderedElementsAreArray(expected_commands));
301
302 service()->RemoveAllBrowsingData(
303 ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS);
304 EXPECT_THAT(store()->GetAllCommands(),
305 testing::UnorderedElementsAreArray(expected_commands));
306
307 // Unblock the load. The will let the remaining calls to the service complete
308 // without blocking.
309 FinishLoading(true /* load_success */);
310 expected_commands.emplace_back(
311 CommandType::ADD_REPORTING_ENDPOINT,
312 ReportingEndpoint(kOrigin_, kGroup_,
313 ReportingEndpoint::EndpointInfo{kEndpoint_}));
314 expected_commands.emplace_back(
315 CommandType::ADD_REPORTING_ENDPOINT,
316 ReportingEndpoint(kOrigin2_, kGroup_,
317 ReportingEndpoint::EndpointInfo{kEndpoint_}));
318 expected_commands.emplace_back(
319 CommandType::ADD_REPORTING_ENDPOINT_GROUP,
320 CachedReportingEndpointGroup(
321 kOrigin_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
322 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
323 expected_commands.emplace_back(
324 CommandType::ADD_REPORTING_ENDPOINT_GROUP,
325 CachedReportingEndpointGroup(
326 kOrigin2_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
327 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
328 expected_commands.emplace_back(
329 CommandType::UPDATE_REPORTING_ENDPOINT_GROUP_ACCESS_TIME,
330 CachedReportingEndpointGroup(
331 kOrigin_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
332 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
333 expected_commands.emplace_back(
334 CommandType::DELETE_REPORTING_ENDPOINT,
335 ReportingEndpoint(kOrigin_, kGroup_,
336 ReportingEndpoint::EndpointInfo{kEndpoint_}));
337 expected_commands.emplace_back(
338 CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
339 CachedReportingEndpointGroup(
340 kOrigin_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
341 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
342 expected_commands.emplace_back(CommandType::FLUSH);
343 expected_commands.emplace_back(
344 CommandType::DELETE_REPORTING_ENDPOINT,
345 ReportingEndpoint(kOrigin2_, kGroup_,
346 ReportingEndpoint::EndpointInfo{kEndpoint_}));
347 expected_commands.emplace_back(
348 CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
349 CachedReportingEndpointGroup(
350 kOrigin2_, kGroup_, OriginSubdomains::DEFAULT /* irrelevant */,
351 base::Time() /* irrelevant */, base::Time() /* irrelevant */));
352 expected_commands.emplace_back(CommandType::FLUSH);
353 EXPECT_THAT(store()->GetAllCommands(),
354 testing::UnorderedElementsAreArray(expected_commands));
355}
356
357INSTANTIATE_TEST_SUITE_P(ReportingServiceStoreTest,
358 ReportingServiceTest,
359 ::testing::Bool());
juliatuttle381d77e2017-04-07 18:54:12360} // namespace
361} // namespace net