587 lines
25 KiB
C++
587 lines
25 KiB
C++
// Copyright 2017 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "net/reporting/reporting_service.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "base/functional/bind.h"
|
|
#include "base/memory/ptr_util.h"
|
|
#include "base/memory/raw_ptr.h"
|
|
#include "base/test/scoped_feature_list.h"
|
|
#include "base/time/tick_clock.h"
|
|
#include "base/values.h"
|
|
#include "net/base/features.h"
|
|
#include "net/base/isolation_info.h"
|
|
#include "net/base/network_anonymization_key.h"
|
|
#include "net/base/schemeful_site.h"
|
|
#include "net/reporting/mock_persistent_reporting_store.h"
|
|
#include "net/reporting/reporting_browsing_data_remover.h"
|
|
#include "net/reporting/reporting_cache.h"
|
|
#include "net/reporting/reporting_context.h"
|
|
#include "net/reporting/reporting_endpoint.h"
|
|
#include "net/reporting/reporting_policy.h"
|
|
#include "net/reporting/reporting_report.h"
|
|
#include "net/reporting/reporting_service.h"
|
|
#include "net/reporting/reporting_test_util.h"
|
|
#include "net/test/test_with_task_environment.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
|
#include "url/gurl.h"
|
|
#include "url/origin.h"
|
|
|
|
namespace net {
|
|
namespace {
|
|
|
|
using CommandType = MockPersistentReportingStore::Command::Type;
|
|
|
|
// The tests are parametrized on a boolean value which represents whether to use
|
|
// a MockPersistentReportingStore (if false, no store is used).
|
|
class ReportingServiceTest : public ::testing::TestWithParam<bool>,
|
|
public WithTaskEnvironment {
|
|
protected:
|
|
const GURL kUrl_ = GURL("https://origin/path");
|
|
const GURL kUrl2_ = GURL("https://origin2/path");
|
|
const url::Origin kOrigin_ = url::Origin::Create(kUrl_);
|
|
const url::Origin kOrigin2_ = url::Origin::Create(kUrl2_);
|
|
const GURL kEndpoint_ = GURL("https://endpoint/");
|
|
const GURL kEndpoint2_ = GURL("https://endpoint2/");
|
|
const std::string kUserAgent_ = "Mozilla/1.0";
|
|
const std::string kGroup_ = "group";
|
|
const std::string kGroup2_ = "group2";
|
|
const std::string kType_ = "type";
|
|
const absl::optional<base::UnguessableToken> kReportingSource_ =
|
|
base::UnguessableToken::Create();
|
|
const NetworkAnonymizationKey kNak_ =
|
|
NetworkAnonymizationKey::CreateSameSite(SchemefulSite(kOrigin_));
|
|
const NetworkAnonymizationKey kNak2_ =
|
|
NetworkAnonymizationKey::CreateSameSite(SchemefulSite(kOrigin2_));
|
|
const ReportingEndpointGroupKey kGroupKey_ =
|
|
ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_);
|
|
const ReportingEndpointGroupKey kGroupKey2_ =
|
|
ReportingEndpointGroupKey(kNak2_, kOrigin2_, kGroup_);
|
|
const IsolationInfo kIsolationInfo_ =
|
|
IsolationInfo::Create(IsolationInfo::RequestType::kOther,
|
|
kOrigin_,
|
|
kOrigin_,
|
|
SiteForCookies::FromOrigin(kOrigin_));
|
|
|
|
ReportingServiceTest() {
|
|
feature_list_.InitAndEnableFeature(
|
|
features::kPartitionNelAndReportingByNetworkIsolationKey);
|
|
Init();
|
|
}
|
|
|
|
// Initializes, or re-initializes, |service_| and its dependencies.
|
|
void Init() {
|
|
if (GetParam())
|
|
store_ = std::make_unique<MockPersistentReportingStore>();
|
|
else
|
|
store_ = nullptr;
|
|
|
|
auto test_context = std::make_unique<TestReportingContext>(
|
|
&clock_, &tick_clock_, ReportingPolicy(), store_.get());
|
|
context_ = test_context.get();
|
|
|
|
service_ = ReportingService::CreateForTesting(std::move(test_context));
|
|
}
|
|
|
|
// If the store exists, simulate finishing loading the store, which should
|
|
// make the rest of the test run synchronously.
|
|
void FinishLoading(bool load_success) {
|
|
if (store_)
|
|
store_->FinishLoading(load_success);
|
|
}
|
|
|
|
MockPersistentReportingStore* store() { return store_.get(); }
|
|
TestReportingContext* context() { return context_; }
|
|
ReportingService* service() { return service_.get(); }
|
|
|
|
private:
|
|
base::test::ScopedFeatureList feature_list_;
|
|
|
|
base::SimpleTestClock clock_;
|
|
base::SimpleTestTickClock tick_clock_;
|
|
|
|
std::unique_ptr<MockPersistentReportingStore> store_;
|
|
raw_ptr<TestReportingContext> context_;
|
|
std::unique_ptr<ReportingService> service_;
|
|
};
|
|
|
|
TEST_P(ReportingServiceTest, QueueReport) {
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
FinishLoading(true /* load_success */);
|
|
|
|
std::vector<const ReportingReport*> reports;
|
|
context()->cache()->GetReports(&reports);
|
|
ASSERT_EQ(1u, reports.size());
|
|
EXPECT_EQ(kUrl_, reports[0]->url);
|
|
EXPECT_EQ(kNak_, reports[0]->network_anonymization_key);
|
|
EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
|
|
EXPECT_EQ(kGroup_, reports[0]->group);
|
|
EXPECT_EQ(kType_, reports[0]->type);
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, QueueReportSanitizeUrl) {
|
|
// Same as kUrl_ but with username, password, and fragment.
|
|
GURL url = GURL("https://username:password@origin/path#fragment");
|
|
service()->QueueReport(url, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
FinishLoading(true /* load_success */);
|
|
|
|
std::vector<const ReportingReport*> reports;
|
|
context()->cache()->GetReports(&reports);
|
|
ASSERT_EQ(1u, reports.size());
|
|
EXPECT_EQ(kUrl_, reports[0]->url);
|
|
EXPECT_EQ(kNak_, reports[0]->network_anonymization_key);
|
|
EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
|
|
EXPECT_EQ(kGroup_, reports[0]->group);
|
|
EXPECT_EQ(kType_, reports[0]->type);
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, DontQueueReportInvalidUrl) {
|
|
GURL url = GURL("https://");
|
|
// This does not trigger an attempt to load from the store because the url
|
|
// is immediately rejected as invalid.
|
|
service()->QueueReport(url, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
|
|
std::vector<const ReportingReport*> reports;
|
|
context()->cache()->GetReports(&reports);
|
|
ASSERT_EQ(0u, reports.size());
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, QueueReportNetworkIsolationKeyDisabled) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitAndDisableFeature(
|
|
features::kPartitionNelAndReportingByNetworkIsolationKey);
|
|
|
|
// Re-create the store, so it reads the new feature value.
|
|
Init();
|
|
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
FinishLoading(true /* load_success */);
|
|
|
|
std::vector<const ReportingReport*> reports;
|
|
context()->cache()->GetReports(&reports);
|
|
ASSERT_EQ(1u, reports.size());
|
|
|
|
// NetworkAnonymizationKey should be empty, instead of kNak_;
|
|
EXPECT_EQ(NetworkAnonymizationKey(), reports[0]->network_anonymization_key);
|
|
EXPECT_NE(kNak_, reports[0]->network_anonymization_key);
|
|
|
|
EXPECT_EQ(kUrl_, reports[0]->url);
|
|
EXPECT_EQ(kUserAgent_, reports[0]->user_agent);
|
|
EXPECT_EQ(kGroup_, reports[0]->group);
|
|
EXPECT_EQ(kType_, reports[0]->type);
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, ProcessReportToHeader) {
|
|
service()->ProcessReportToHeader(kOrigin_, kNak_,
|
|
"{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
FinishLoading(true /* load_success */);
|
|
|
|
EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
|
|
EXPECT_TRUE(context()->cache()->GetEndpointForTesting(
|
|
ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_), kEndpoint_));
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, ProcessReportingEndpointsHeader) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
|
|
auto parsed_header =
|
|
ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\"");
|
|
ASSERT_TRUE(parsed_header.has_value());
|
|
service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
|
|
kIsolationInfo_, *parsed_header);
|
|
FinishLoading(true /* load_success */);
|
|
|
|
// Endpoint should not be part of the persistent store.
|
|
EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
|
|
// Endpoint should be associated with the reporting source.
|
|
ReportingEndpoint cached_endpoint =
|
|
context()->cache()->GetV1EndpointForTesting(*kReportingSource_, kGroup_);
|
|
EXPECT_TRUE(cached_endpoint);
|
|
|
|
// Ensure that the NIK is stored properly with the endpoint group.
|
|
EXPECT_FALSE(cached_endpoint.group_key.network_anonymization_key.IsEmpty());
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest,
|
|
ProcessReportingEndpointsHeaderNetworkIsolationKeyDisabled) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitWithFeatures(
|
|
{net::features::kDocumentReporting},
|
|
{features::kPartitionNelAndReportingByNetworkIsolationKey});
|
|
|
|
// Re-create the store, so it reads the new feature value.
|
|
Init();
|
|
|
|
auto parsed_header =
|
|
ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\"");
|
|
ASSERT_TRUE(parsed_header.has_value());
|
|
service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
|
|
kIsolationInfo_, *parsed_header);
|
|
FinishLoading(true /* load_success */);
|
|
|
|
// Endpoint should not be part of the persistent store.
|
|
EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
|
|
// Endpoint should be associated with the reporting source.
|
|
ReportingEndpoint cached_endpoint =
|
|
context()->cache()->GetV1EndpointForTesting(*kReportingSource_, kGroup_);
|
|
EXPECT_TRUE(cached_endpoint);
|
|
|
|
// When isolation is disabled, cached endpoints should have a null NIK.
|
|
EXPECT_TRUE(cached_endpoint.group_key.network_anonymization_key.IsEmpty());
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, SendReportsAndRemoveSource) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
|
|
auto parsed_header =
|
|
ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\", " +
|
|
kGroup2_ + "=\"" + kEndpoint2_.spec() + "\"");
|
|
ASSERT_TRUE(parsed_header.has_value());
|
|
service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
|
|
kIsolationInfo_, *parsed_header);
|
|
// This report should be sent immediately, starting the delivery agent timer.
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
|
|
FinishLoading(true /* load_success */);
|
|
|
|
std::vector<const ReportingReport*> reports;
|
|
context()->cache()->GetReports(&reports);
|
|
ASSERT_EQ(1u, reports.size());
|
|
EXPECT_EQ(0u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::QUEUED));
|
|
|
|
// Now simulate the source being destroyed.
|
|
service()->SendReportsAndRemoveSource(*kReportingSource_);
|
|
|
|
// There should be no queued reports, but the previously sent report should
|
|
// still be pending.
|
|
EXPECT_EQ(0u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::QUEUED));
|
|
EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::PENDING));
|
|
// Source should be marked as expired.
|
|
ASSERT_TRUE(
|
|
context()->cache()->GetExpiredSources().contains(*kReportingSource_));
|
|
}
|
|
|
|
// Flaky in ChromeOS: crbug.com/1356127
|
|
#if BUILDFLAG(IS_CHROMEOS)
|
|
#define MAYBE_SendReportsAndRemoveSourceWithPendingReports \
|
|
DISABLED_SendReportsAndRemoveSourceWithPendingReports
|
|
#else
|
|
#define MAYBE_SendReportsAndRemoveSourceWithPendingReports \
|
|
SendReportsAndRemoveSourceWithPendingReports
|
|
#endif
|
|
TEST_P(ReportingServiceTest,
|
|
MAYBE_SendReportsAndRemoveSourceWithPendingReports) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
|
|
auto parsed_header =
|
|
ParseReportingEndpoints(kGroup_ + "=\"" + kEndpoint_.spec() + "\", " +
|
|
kGroup2_ + "=\"" + kEndpoint2_.spec() + "\"");
|
|
ASSERT_TRUE(parsed_header.has_value());
|
|
service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
|
|
kIsolationInfo_, *parsed_header);
|
|
// This report should be sent immediately, starting the delivery agent timer.
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
|
|
FinishLoading(true /* load_success */);
|
|
|
|
std::vector<const ReportingReport*> reports;
|
|
context()->cache()->GetReports(&reports);
|
|
ASSERT_EQ(1u, reports.size());
|
|
EXPECT_EQ(0u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::QUEUED));
|
|
EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::PENDING));
|
|
|
|
// Queue another report, which should remain queued.
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::QUEUED));
|
|
EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::PENDING));
|
|
|
|
// Now simulate the source being destroyed.
|
|
service()->SendReportsAndRemoveSource(*kReportingSource_);
|
|
|
|
// The report should still be queued, while the source should be marked as
|
|
// expired. (The original report is still pending.)
|
|
EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::QUEUED));
|
|
EXPECT_EQ(1u, context()->cache()->GetReportCountWithStatusForTesting(
|
|
ReportingReport::Status::PENDING));
|
|
ASSERT_TRUE(
|
|
context()->cache()->GetExpiredSources().contains(kReportingSource_));
|
|
}
|
|
|
|
#if BUILDFLAG(IS_CHROMEOS)
|
|
#define MAYBE_ProcessReportingEndpointsHeaderPathAbsolute DISABLED_ProcessReportingEndpointsHeaderPathAbsolute
|
|
#else
|
|
#define MAYBE_ProcessReportingEndpointsHeaderPathAbsolute ProcessReportingEndpointsHeaderPathAbsolute
|
|
#endif
|
|
TEST_P(ReportingServiceTest, MAYBE_ProcessReportingEndpointsHeaderPathAbsolute) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitAndEnableFeature(net::features::kDocumentReporting);
|
|
auto parsed_header = ParseReportingEndpoints(kGroup_ + "=\"/path-absolute\"");
|
|
ASSERT_TRUE(parsed_header.has_value());
|
|
service()->SetDocumentReportingEndpoints(*kReportingSource_, kOrigin_,
|
|
kIsolationInfo_, *parsed_header);
|
|
FinishLoading(true /* load_success */);
|
|
|
|
// Endpoint should not be part of the persistent store.
|
|
EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
|
|
// Endpoint should be associated with the reporting source.
|
|
ReportingEndpoint endpoint =
|
|
context()->cache()->GetV1EndpointForTesting(*kReportingSource_, kGroup_);
|
|
EXPECT_TRUE(endpoint);
|
|
// Endpoint should have the correct path.
|
|
EXPECT_EQ(kUrl_.Resolve("/path-absolute"), endpoint.info.url);
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, ProcessReportToHeaderPathAbsolute) {
|
|
service()->ProcessReportToHeader(
|
|
kOrigin_, kNak_,
|
|
"{\"endpoints\":[{\"url\":\"/path-absolute\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
FinishLoading(true /* load_success */);
|
|
|
|
EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, ProcessReportToHeader_TooLong) {
|
|
const std::string header_too_long =
|
|
"{\"endpoints\":[{\"url\":\"" + kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400," +
|
|
"\"junk\":\"" + std::string(32 * 1024, 'a') + "\"}";
|
|
// This does not trigger an attempt to load from the store because the header
|
|
// is immediately rejected as invalid.
|
|
service()->ProcessReportToHeader(kOrigin_, kNak_, header_too_long);
|
|
|
|
EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, ProcessReportToHeader_TooDeep) {
|
|
const std::string header_too_deep = "{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400," +
|
|
"\"junk\":[[[[[[[[[[]]]]]]]]]]}";
|
|
// This does not trigger an attempt to load from the store because the header
|
|
// is immediately rejected as invalid.
|
|
service()->ProcessReportToHeader(kOrigin_, kNak_, header_too_deep);
|
|
|
|
EXPECT_EQ(0u, context()->cache()->GetEndpointCount());
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, ProcessReportToHeaderNetworkIsolationKeyDisabled) {
|
|
base::test::ScopedFeatureList feature_list;
|
|
feature_list.InitAndDisableFeature(
|
|
features::kPartitionNelAndReportingByNetworkIsolationKey);
|
|
|
|
// Re-create the store, so it reads the new feature value.
|
|
Init();
|
|
|
|
service()->ProcessReportToHeader(kOrigin_, kNak_,
|
|
"{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
FinishLoading(true /* load_success */);
|
|
|
|
EXPECT_EQ(1u, context()->cache()->GetEndpointCount());
|
|
EXPECT_FALSE(context()->cache()->GetEndpointForTesting(
|
|
ReportingEndpointGroupKey(kNak_, kOrigin_, kGroup_), kEndpoint_));
|
|
EXPECT_TRUE(context()->cache()->GetEndpointForTesting(
|
|
ReportingEndpointGroupKey(NetworkAnonymizationKey(), kOrigin_, kGroup_),
|
|
kEndpoint_));
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, WriteToStore) {
|
|
if (!store())
|
|
return;
|
|
|
|
MockPersistentReportingStore::CommandList expected_commands;
|
|
|
|
// This first call to any public method triggers a load. The load will block
|
|
// until we call FinishLoading.
|
|
service()->ProcessReportToHeader(kOrigin_, kNak_,
|
|
"{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
expected_commands.emplace_back(CommandType::LOAD_REPORTING_CLIENTS);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
// Unblock the load. The will let the remaining calls to the service complete
|
|
// without blocking.
|
|
FinishLoading(true /* load_success */);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
|
|
kGroupKey_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey_);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->ProcessReportToHeader(kOrigin2_, kNak2_,
|
|
"{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
|
|
kGroupKey2_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey2_);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
expected_commands.emplace_back(
|
|
CommandType::UPDATE_REPORTING_ENDPOINT_GROUP_ACCESS_TIME, kGroupKey_);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->RemoveBrowsingData(
|
|
ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS,
|
|
base::BindRepeating(
|
|
[](const url::Origin& origin) { return origin.host() == "origin"; }));
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
|
|
kGroupKey_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey_);
|
|
expected_commands.emplace_back(CommandType::FLUSH);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->RemoveAllBrowsingData(
|
|
ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
|
|
kGroupKey2_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey2_);
|
|
expected_commands.emplace_back(CommandType::FLUSH);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
}
|
|
|
|
TEST_P(ReportingServiceTest, WaitUntilLoadFinishesBeforeWritingToStore) {
|
|
if (!store())
|
|
return;
|
|
|
|
MockPersistentReportingStore::CommandList expected_commands;
|
|
|
|
// This first call to any public method triggers a load. The load will block
|
|
// until we call FinishLoading.
|
|
service()->ProcessReportToHeader(kOrigin_, kNak_,
|
|
"{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
expected_commands.emplace_back(CommandType::LOAD_REPORTING_CLIENTS);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->ProcessReportToHeader(kOrigin2_, kNak2_,
|
|
"{\"endpoints\":[{\"url\":\"" +
|
|
kEndpoint_.spec() +
|
|
"\"}],"
|
|
"\"group\":\"" +
|
|
kGroup_ +
|
|
"\","
|
|
"\"max_age\":86400}");
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->QueueReport(kUrl_, kReportingSource_, kNak_, kUserAgent_, kGroup_,
|
|
kType_, base::Value::Dict(), 0);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->RemoveBrowsingData(
|
|
ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS,
|
|
base::BindRepeating(
|
|
[](const url::Origin& origin) { return origin.host() == "origin"; }));
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
service()->RemoveAllBrowsingData(
|
|
ReportingBrowsingDataRemover::DATA_TYPE_CLIENTS);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
|
|
// Unblock the load. The will let the remaining calls to the service complete
|
|
// without blocking.
|
|
FinishLoading(true /* load_success */);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
|
|
kGroupKey_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT,
|
|
kGroupKey2_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey_);
|
|
expected_commands.emplace_back(CommandType::ADD_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey2_);
|
|
expected_commands.emplace_back(
|
|
CommandType::UPDATE_REPORTING_ENDPOINT_GROUP_ACCESS_TIME, kGroupKey_);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
|
|
kGroupKey_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey_);
|
|
expected_commands.emplace_back(CommandType::FLUSH);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT,
|
|
kGroupKey2_, kEndpoint_);
|
|
expected_commands.emplace_back(CommandType::DELETE_REPORTING_ENDPOINT_GROUP,
|
|
kGroupKey2_);
|
|
expected_commands.emplace_back(CommandType::FLUSH);
|
|
EXPECT_THAT(store()->GetAllCommands(),
|
|
testing::UnorderedElementsAreArray(expected_commands));
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ReportingServiceStoreTest,
|
|
ReportingServiceTest,
|
|
::testing::Bool());
|
|
} // namespace
|
|
} // namespace net
|