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

Unified Diff: components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc

Issue 807503002: Implement throttling logic for fetching affiliation information. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@aff_database
Patch Set: Nit Created 5 years, 11 months 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: components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc
diff --git a/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc b/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..39d333c3e6839ed768167dc76770ac1cd8717b8e
--- /dev/null
+++ b/components/password_manager/core/browser/affiliation_fetch_throttler_unittest.cc
@@ -0,0 +1,231 @@
+// Copyright 2015 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 "components/password_manager/core/browser/affiliation_fetch_throttler.h"
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "components/password_manager/core/browser/affiliation_fetch_throttler_delegate.h"
+#include "net/base/network_change_notifier.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+namespace {
+
+class MockAffiliationFetchThrottlerDelegate
+ : public testing::StrictMock<AffiliationFetchThrottlerDelegate> {
+ public:
+ MockAffiliationFetchThrottlerDelegate() {}
+
+ MOCK_METHOD0(OnCanSendNetworkRequest, bool());
mmenke 2015/01/21 17:18:52 It's generally recommended you don't use GMOCK, to
mmenke 2015/01/21 17:18:53 In no tests does OnCanSendNetworkRequest return fa
engedy 2015/01/23 22:09:43 While the password_manager component uses GMock ex
engedy 2015/01/23 22:09:43 Done.
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAffiliationFetchThrottlerDelegate);
+};
+
+class MockNetworkChangeNotifier : public net::NetworkChangeNotifier {
+ public:
+ MockNetworkChangeNotifier() : connection_type_(CONNECTION_UNKNOWN) {}
+
+ void set_connection_type(ConnectionType connection_type) {
+ connection_type_ = connection_type;
+ NotifyObserversOfConnectionTypeChangeForTests(connection_type_);
+ }
+
+ ConnectionType GetCurrentConnectionType() const override {
+ return connection_type_;
+ }
+
+ private:
+ ConnectionType connection_type_;
+};
+
+} // namespace
+
+class AffiliationFetchThrottlerTest : public testing::Test {
+ public:
+ AffiliationFetchThrottlerTest()
+ : network_change_notifier_(new MockNetworkChangeNotifier),
mmenke 2015/01/21 17:18:53 Any reason this needs to be a scoped_ptr?
engedy 2015/01/23 22:09:43 Nope. Done.
+ task_runner_(new base::TestMockTimeTaskRunner) {}
+ ~AffiliationFetchThrottlerTest() override {}
+
+ void SetUp() override {
+ policy_.reset(new AffiliationFetchThrottler(
+ &mock_delegate_, task_runner_, task_runner_->GetMockTickClock()));
mmenke 2015/01/21 17:18:52 Can this be done in the constructor, preferable in
engedy 2015/01/23 22:09:44 N/A. The instance under test is created in the tes
+ }
+
+ void SimulateHasNetworkConnectivity(bool has_connectivity) {
+ network_change_notifier_->set_connection_type(
+ has_connectivity ? net::NetworkChangeNotifier::CONNECTION_UNKNOWN
+ : net::NetworkChangeNotifier::CONNECTION_NONE);
+ base::RunLoop().RunUntilIdle();
+ }
+
+ // Forwards time, and given that MockAffiliationFetchThrottlerDelegate is a
+ // strict mock, also ensures OnCanSendNetworkRequest() is not called back
+ // during this period.
+ void FastForwardTimeBySecs(double secs) {
+ task_runner_->FastForwardBy(base::TimeDelta::FromSecondsD(secs));
+ }
+
+ void FastForwardUntilNoTasksRemain() {
+ task_runner_->FastForwardUntilNoTasksRemain();
+ }
+
+ size_t GetPendingTaskCount() { return task_runner_->GetPendingTaskCount(); }
mmenke 2015/01/21 17:18:52 const
engedy 2015/01/23 22:09:43 Done.
+
+ // Forwards time until the next OnCanSendNetworkRequest() callback, and
+ // verifies that it occurs between |min_delay_sec| and |max_delay_sec| seconds
+ // from now, inclusive.
+ void AssertReleaseBetweenSecs(double min_delay_sec, double max_delay_sec) {
+ base::TimeTicks ticks_at_start = task_runner_->GetCurrentMockTime();
+ base::TimeDelta min_delay = base::TimeDelta::FromSecondsD(min_delay_sec);
+ if (min_delay.ToInternalValue() > 0) {
+ task_runner_->FastForwardBy(min_delay -
+ base::TimeDelta::FromInternalValue(1));
+ }
+ EXPECT_CALL(mock_delegate_, OnCanSendNetworkRequest())
+ .Times(1)
+ .WillRepeatedly(testing::Return(true));
+ task_runner_->FastForwardUntilNoTasksRemain();
+ ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&mock_delegate_));
+ ASSERT_GE(base::TimeDelta::FromSecondsD(max_delay_sec),
+ task_runner_->GetCurrentMockTime() - ticks_at_start);
+ }
+
+ AffiliationFetchThrottler& policy() { return *policy_.get(); }
mmenke 2015/01/21 17:18:53 Seems like this should be returning an Affiliation
engedy 2015/01/23 22:09:44 Done.
+
+ private:
+ // Needed because NetworkChangeNotifier uses ObserverList, which notifies
+ // observers on the MessageLoop that belongs to the thread from which they
+ // have registered.
+ base::MessageLoop message_loop_;
+ scoped_ptr<MockNetworkChangeNotifier> network_change_notifier_;
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ MockAffiliationFetchThrottlerDelegate mock_delegate_;
+ scoped_ptr<AffiliationFetchThrottler> policy_;
mmenke 2015/01/21 17:18:53 Calling an "AffiliationFetchThrottler" policy_ is
engedy 2015/01/23 22:09:44 Done.
+
+ DISALLOW_COPY_AND_ASSIGN(AffiliationFetchThrottlerTest);
+};
+
+TEST_F(AffiliationFetchThrottlerTest, SuccessfulRequests) {
+ SimulateHasNetworkConnectivity(true);
+
+ policy().SignalNetworkRequestNeeded();
+ AssertReleaseBetweenSecs(0, 0);
+
+ // Signal while request is in flight should be ignored.
mmenke 2015/01/21 17:18:53 We should make sure that it's ignored here. Is th
engedy 2015/01/23 22:09:44 Yes, the strict mock ensured this, but I have made
+ policy().SignalNetworkRequestNeeded();
+ FastForwardUntilNoTasksRemain();
+ policy().InformOfNetworkRequestComplete(true);
+ FastForwardUntilNoTasksRemain();
+
+ // Duplicate the second signal 3 times: still only 1 callback should arrive.
+ policy().SignalNetworkRequestNeeded();
+ policy().SignalNetworkRequestNeeded();
+ policy().SignalNetworkRequestNeeded();
+ AssertReleaseBetweenSecs(0, 0);
+}
+
+TEST_F(AffiliationFetchThrottlerTest, FailedRequests) {
+ SimulateHasNetworkConnectivity(true);
+
+ policy().SignalNetworkRequestNeeded();
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(0, 0));
+ policy().InformOfNetworkRequestComplete(false);
+
+ // Request after first failure should be delayed by 10 seconds with 50%
+ // fuzzing factor.
+ policy().SignalNetworkRequestNeeded();
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10));
mmenke 2015/01/21 17:18:53 Relying on exact values for doubles just seems lik
engedy 2015/01/23 22:09:44 Not that we are not relying on *exact* value: this
mmenke 2015/01/23 22:39:53 If we get a 5 or a 10 in the random calculation (A
engedy 2015/01/24 00:35:38 Not sure I understand what you mean by this. Excep
+ policy().InformOfNetworkRequestComplete(false);
+
+ // Request after first failure should be delayed by 40 seconds with 50%
+ // fuzzing factor, applied twice.
mmenke 2015/01/21 17:18:52 This isn't true. Jitter factor is applied indepen
engedy 2015/01/23 22:09:44 Right. Done.
+ policy().SignalNetworkRequestNeeded();
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(10, 40));
+ policy().InformOfNetworkRequestComplete(false);
+}
+
+TEST_F(AffiliationFetchThrottlerTest, GracePeriodAfterConnectivityIsRestored) {
+ SimulateHasNetworkConnectivity(false);
+
+ // After connectivity is re-established, the first request should be delayed
+ // by 10 seconds with 50% fuzzing factor.
+ policy().SignalNetworkRequestNeeded();
mmenke 2015/01/21 17:18:52 FastForwardUntilNoTasksRemain();? (And same goes
engedy 2015/01/23 22:09:43 I have added it here, and verified elsewhere, plea
+ SimulateHasNetworkConnectivity(true);
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10));
mmenke 2015/01/21 17:18:53 These numbers should not be hardcoded. Should use
engedy 2015/01/23 22:09:44 Done.
+ policy().InformOfNetworkRequestComplete(true);
+
+ // The next request should not be delayed.
+ policy().SignalNetworkRequestNeeded();
+ AssertReleaseBetweenSecs(0, 0);
+}
+
+// Same as GracePeriodAfterConnectivityIsRestored, but the network comes back
+// just before SignalNetworkRequestNeeded() is called.
+TEST_F(AffiliationFetchThrottlerTest, GracePeriodAfterConnectivityIsRestored2) {
+ SimulateHasNetworkConnectivity(false);
+
+ SimulateHasNetworkConnectivity(true);
+ policy().SignalNetworkRequestNeeded();
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10));
mmenke 2015/01/21 17:18:53 You may want to add a way to EXPECT on the actual
engedy 2015/01/23 22:09:44 Done.
+ policy().InformOfNetworkRequestComplete(true);
+
+ policy().SignalNetworkRequestNeeded();
+ AssertReleaseBetweenSecs(0, 0);
+}
+
+// TODO(engedy): This test is flaky. Investigate.
+TEST_F(AffiliationFetchThrottlerTest, ConnectivityLostDuringBackoff) {
+ SimulateHasNetworkConnectivity(true);
+
+ policy().SignalNetworkRequestNeeded();
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(0, 0));
+ policy().InformOfNetworkRequestComplete(false);
+
+ policy().SignalNetworkRequestNeeded();
+ SimulateHasNetworkConnectivity(false);
+
+ // Let the exponential backoff delay expire, and verify nothing happens.
+ FastForwardUntilNoTasksRemain();
+
+ // Verify that the request is, however, sent after 10 seconds with 50% fuzzing
+ // factor.
+ SimulateHasNetworkConnectivity(true);
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10));
+}
+
+TEST_F(AffiliationFetchThrottlerTest,
+ ConnectivityLostAndRestoredDuringBackoff) {
+ SimulateHasNetworkConnectivity(true);
+
+ policy().SignalNetworkRequestNeeded();
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(0, 0));
+ policy().InformOfNetworkRequestComplete(false);
+
+ policy().SignalNetworkRequestNeeded();
+
+ // Also verify that a flaky connection will not flood the task queue with lots
+ // of tasks.
mmenke 2015/01/21 17:18:52 I don't think this is needed... The NCN itself al
engedy 2015/01/23 22:09:43 This mostly test what you have pointed out earlier
+ for (size_t t = 1; t <= 5; ++t) {
+ SimulateHasNetworkConnectivity(false);
+ SimulateHasNetworkConnectivity(true);
+ FastForwardTimeBySecs(1);
+ }
+ EXPECT_EQ(1u, GetPendingTaskCount());
+
+ ASSERT_NO_FATAL_FAILURE(AssertReleaseBetweenSecs(5, 10));
+}
mmenke 2015/01/21 17:18:53 Do we have a test where connectivity is lost and r
engedy 2015/01/23 22:09:44 I have added two, though I wasn't sure if the URLF
mmenke 2015/01/23 22:39:53 You shouldn't depend on what it does - it depends
engedy 2015/01/26 19:39:34 I have added an additional test.
+
+} // namespace password_manager

Powered by Google App Engine
This is Rietveld 408576698