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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: net/reporting/reporting_service_unittest.cc
diff --git a/net/reporting/reporting_service_unittest.cc b/net/reporting/reporting_service_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5d18ff141e15340bb12147a4a75a7f6c4637c19c
--- /dev/null
+++ b/net/reporting/reporting_service_unittest.cc
@@ -0,0 +1,400 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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 <string>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/values.h"
+#include "net/reporting/reporting_uploader.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace net {
+namespace {
+
+class MockUploader : public ReportingUploader {
+ public:
+ class PendingDelivery {
+ public:
+ PendingDelivery(MockUploader* uploader,
+ const GURL& url,
+ const std::string& json,
+ const Callback& callback)
+ : uploader_(uploader), url_(url), json_(json), callback_(callback) {
+ DCHECK(uploader_);
+ }
+
+ ~PendingDelivery() {}
+
+ void Complete(Outcome outcome) {
+ callback_.Run(outcome);
+ // Deletes |this|.
+ uploader_->OnDeliveryComplete(this);
+ }
+
+ const GURL& url() const { return url_; }
+ const std::string& json() const { return json_; }
+
+ private:
+ MockUploader* uploader_;
+ GURL url_;
+ std::string json_;
+ Callback callback_;
+ };
+
+ MockUploader() {}
+ ~MockUploader() override {}
+
+ void AttemptDelivery(const GURL& url,
+ const std::string& json,
+ const Callback& callback) override {
+ deliveries_.push_back(
+ base::MakeUnique<PendingDelivery>(this, url, json, callback));
+ }
+
+ const std::vector<std::unique_ptr<PendingDelivery>>& GetPendingDeliveries()
+ const {
+ return deliveries_;
+ }
+
+ void OnDeliveryComplete(PendingDelivery* delivery) {
+ for (auto it = deliveries_.begin(); it != deliveries_.end(); ++it) {
+ if (it->get() == delivery) {
+ deliveries_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+ }
+
+ private:
+ std::vector<std::unique_ptr<PendingDelivery>> deliveries_;
+};
+
+class ReportingServiceTest : public ::testing::Test {
+ protected:
+ ReportingServiceTest() {}
+
+ void CreateServiceWithDefaultPolicy() {
+ ReportingService::Policy policy = ReportingService::Policy::GetDefault();
+ CreateServiceWithPolicy(policy);
+ }
+
+ void CreateServiceWithPolicy(const ReportingService::Policy& policy) {
+ policy_ = policy;
+ service_ = base::MakeUnique<ReportingService>(policy);
+ clock_ = new base::SimpleTestTickClock();
+ service_->set_clock_for_testing(base::WrapUnique(clock_));
+ uploader_ = new MockUploader();
+ service_->set_uploader(base::WrapUnique(uploader_));
+ }
+
+ void QueueReport(const GURL& url) {
+ service_->QueueReport(base::MakeUnique<base::DictionaryValue>(), url,
+ url.GetOrigin(), "default", "test");
+ }
+
+ const std::vector<std::unique_ptr<MockUploader::PendingDelivery>>&
+ GetPendingDeliveries() {
+ return uploader_->GetPendingDeliveries();
+ }
+
+ bool HasEndpoint(const std::string& endpoint_url) {
+ return service_->HasEndpointForTesting(GURL(endpoint_url));
+ }
+
+ bool HasClient(const std::string& endpoint_url,
+ const std::string& origin_url) {
+ return service_->HasClientForTesting(GURL(endpoint_url), GURL(origin_url));
+ }
+
+ int GetEndpointFailures(const std::string& endpoint_url) {
+ return service_->GetEndpointFailuresForTesting(GURL(endpoint_url));
+ }
+
+ // |policy_| is a copy of the policy used to configure |service_|, for easier
+ // reference.
+ ReportingService::Policy policy_;
+ // |clock_| and |uploader_| are owned by |service_|, not the test.
+ base::SimpleTestTickClock* clock_;
+ MockUploader* uploader_;
+ std::unique_ptr<ReportingService> service_;
+};
+
+TEST_F(ReportingServiceTest, ProcessHeaderFromInsecureOrigin) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("http://insecure/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ EXPECT_FALSE(HasClient("https://endpoint/", "http://insecure"));
+}
+
+TEST_F(ReportingServiceTest, ProcessInvalidHeaders) {
+ static const struct {
+ const char* header_value;
+ const char* description;
+ } kInvalidHeaderTestCases[] = {
+ {"{\"max-age\":1}", "missing url"},
+ {"{\"url\":0,\"max-age\":1}", "non-string url"},
+ {"{\"url\":\"http://insecure/\",\"max-age\":1}", "insecure url"},
+
+ {"{\"url\":\"https://endpoint/\"}", "missing max-age"},
+ {"{\"url\":\"https://endpoint/\",\"max-age\":\"\"}",
+ "non-integer max-age"},
+ {"{\"url\":\"https://endpoint/\",\"max-age\":-1}", "negative max-age"},
+
+ {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"group\":0}",
+ "non-string group"},
+
+ {"{\"url\":\"https://endpoint/\",\"max-age\":1,\"includeSubdomains\":0}",
+ "non-boolean includeSubdomains"},
+ };
+
+ CreateServiceWithDefaultPolicy();
+
+ for (size_t i = 0; i < arraysize(kInvalidHeaderTestCases); ++i) {
+ auto& test_case = kInvalidHeaderTestCases[i];
+ service_->ProcessHeader(GURL("https://origin/"), test_case.header_value);
+ EXPECT_FALSE(HasClient("https://endpoint/", "https://origin/"));
+ }
+}
+
+TEST_F(ReportingServiceTest, ProcessValidHeader) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ EXPECT_TRUE(HasClient("https://endpoint/", "https://origin/"));
+
+#if 0
+ EXPECT_EQ(1u, GetCache().GetEndpoints().size());
+ const std::unique_ptr<ReportingEndpoint>* endpoint_ptr =
+ GetCache().GetEndpoint(GURL("https://endpoint/"));
+ ASSERT_TRUE(endpoint_ptr);
+ const std::unique_ptr<ReportingEndpoint>& endpoint = *endpoint_ptr;
+ EXPECT_EQ(GURL("https://endpoint/"), endpoint->url);
+
+ EXPECT_EQ(1u, endpoint->clients.count(GURL("https://origin/")));
+ auto client_it = endpoint->clients.find(GURL("https://origin/"));
+ ASSERT_TRUE(client_it != endpoint->clients.end());
+ const ReportingClient& client = client_it->second;
+ EXPECT_EQ(GURL("https://origin"), client.origin);
+ EXPECT_FALSE(client.subdomains);
+ EXPECT_EQ("default", client.group);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(1), client.ttl);
+#endif
+}
+
+TEST_F(ReportingServiceTest, ProcessZeroMaxAgeHeader) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ EXPECT_TRUE(HasClient("https://endpoint/", "https://origin/"));
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":0}");
+ EXPECT_FALSE(HasClient("https://endpoint/", "https://origin/"));
+}
+
+TEST_F(ReportingServiceTest, DeliverySuccess) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin/path"));
+ service_->SendReports();
+
+ ASSERT_EQ(1u, GetPendingDeliveries().size());
+ const std::unique_ptr<MockUploader::PendingDelivery>& delivery =
+ GetPendingDeliveries()[0];
+ EXPECT_EQ(GURL("https://endpoint/"), delivery->url());
+ {
+ auto reports_value = base::JSONReader::Read(delivery->json());
+ const base::ListValue* reports;
+ ASSERT_TRUE(reports_value->GetAsList(&reports));
+ ASSERT_EQ(1u, reports->GetSize());
+ const base::DictionaryValue* report;
+ ASSERT_TRUE(reports->GetDictionary(0u, &report));
+ std::string type;
+ ASSERT_TRUE(report->GetString("type", &type));
+ EXPECT_EQ("test", type);
+ std::string url;
+ ASSERT_TRUE(report->GetString("url", &url));
+ EXPECT_EQ("https://origin/path", url);
+ }
+
+ delivery->Complete(ReportingUploader::SUCCESS);
+
+ EXPECT_EQ(0, GetEndpointFailures("https://endpoint/"));
+}
+
+TEST_F(ReportingServiceTest, DeliveryFailure) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin/path"));
+ service_->SendReports();
+
+ GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
+
+ EXPECT_EQ(1, GetEndpointFailures("https://endpoint/"));
+}
+
+TEST_F(ReportingServiceTest, DeliveryRemoveEndpoint) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin/path"));
+ service_->SendReports();
+
+ GetPendingDeliveries()[0]->Complete(ReportingUploader::REMOVE_ENDPOINT);
+
+ EXPECT_FALSE(HasClient("https://endpoint/", "https://origin/"));
+}
+
+TEST_F(ReportingServiceTest, NoDeliveryToPendingEndpoint) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin/"));
+ service_->SendReports();
+
+ GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
+
+ // Without advancing the clock, the endpoint should still be pending, so the
+ // Manager should not try to deliver reports to it.
+ service_->SendReports();
+
+ EXPECT_TRUE(GetPendingDeliveries().empty());
+}
+
+TEST_F(ReportingServiceTest, NoDeliveryToMismatchedEndpoint) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin1/"),
+ "{\"url\":\"https://endpoint1/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin2/"));
+ service_->SendReports();
+
+ EXPECT_TRUE(GetPendingDeliveries().empty());
+}
+
+TEST_F(ReportingServiceTest, BatchReportsForSameOrigin) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin/"));
+ QueueReport(GURL("https://origin/"));
+ service_->SendReports();
+
+ EXPECT_EQ(1u, GetPendingDeliveries().size());
+
+ GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
+}
+
+TEST_F(ReportingServiceTest, BatchReportsForSameEndpoint) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin1/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ service_->ProcessHeader(GURL("https://origin2/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ QueueReport(GURL("https://origin1/"));
+ QueueReport(GURL("https://origin2/"));
+ service_->SendReports();
+
+ EXPECT_EQ(1u, GetPendingDeliveries().size());
+
+ GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
+}
+
+TEST_F(ReportingServiceTest, ExpiredEndpoint) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":1}");
+ EXPECT_TRUE(HasEndpoint("https://endpoint/"));
+
+ clock_->Advance(base::TimeDelta::FromSeconds(2));
+ service_->CollectGarbageForTesting();
+ EXPECT_FALSE(HasEndpoint("https://endpoint/"));
+}
+
+TEST_F(ReportingServiceTest, UnusedEndpoint) {
+ CreateServiceWithDefaultPolicy();
+
+ service_->ProcessHeader(
+ GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":999999999}");
+ EXPECT_TRUE(HasEndpoint("https://endpoint/"));
+
+ clock_->Advance(2 * policy_.endpoint_lifetime);
+ service_->CollectGarbageForTesting();
+ EXPECT_FALSE(HasEndpoint("https://endpoint/"));
+}
+
+TEST_F(ReportingServiceTest, FailedEndpoint) {
+ ReportingService::Policy policy = ReportingService::Policy::GetDefault();
+ policy.endpoint_backoff.initial_delay_ms = 0;
+ policy.endpoint_backoff.maximum_backoff_ms = 0;
+ policy.endpoint_backoff.entry_lifetime_ms = 1000;
+ policy.max_endpoint_failures = 5;
+ policy.max_report_failures = 999;
+ CreateServiceWithPolicy(policy);
+
+ service_->ProcessHeader(
+ GURL("https://origin/"),
+ "{\"url\":\"https://endpoint/\",\"max-age\":999999999}");
+
+ QueueReport(GURL("https://origin/"));
+
+ for (int i = 0; i < policy_.max_endpoint_failures + 1; i++) {
+ EXPECT_TRUE(HasEndpoint("https://endpoint/"));
+ service_->SendReports();
+ EXPECT_EQ(1u, GetPendingDeliveries().size());
+ GetPendingDeliveries()[0]->Complete(ReportingUploader::FAILURE);
+ }
+ service_->CollectGarbageForTesting();
+ EXPECT_TRUE(HasEndpoint("https://endpoint/"));
+
+ clock_->Advance(base::TimeDelta::FromMilliseconds(
+ 2 * policy_.endpoint_backoff.entry_lifetime_ms));
+
+ service_->CollectGarbageForTesting();
+ EXPECT_FALSE(HasEndpoint("https://endpoint/"));
+}
+
+TEST_F(ReportingServiceTest, EvictedEndpoint) {
+ ReportingService::Policy policy = ReportingService::Policy::GetDefault();
+ policy.max_endpoint_count = 1;
+ CreateServiceWithPolicy(policy);
+
+ service_->ProcessHeader(GURL("https://origin1/"),
+ "{\"url\":\"https://endpoint1/\",\"max-age\":1}");
+ EXPECT_TRUE(HasEndpoint("https://endpoint1"));
+
+ service_->ProcessHeader(GURL("https://origin2/"),
+ "{\"url\":\"https://endpoint2/\",\"max-age\":1}");
+ EXPECT_FALSE(HasEndpoint("https://endpoint1"));
+ EXPECT_TRUE(HasEndpoint("https://endpoint2"));
+}
+
+// TODO: Test:
+// Expired report (happens after lifetime passes -> GC)
+// Failed report (happens after failed attempt -> attempt)
+// Evicted report (happens after queue or failed attempt -> queue)
+// No-action cases (e.g. don't evict pending report).
+
+} // namespace
+} // namespace net

Powered by Google App Engine
This is Rietveld 408576698