summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/signin/force_signin_verifier_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/signin/force_signin_verifier_unittest.cc')
-rw-r--r--chromium/chrome/browser/signin/force_signin_verifier_unittest.cc416
1 files changed, 416 insertions, 0 deletions
diff --git a/chromium/chrome/browser/signin/force_signin_verifier_unittest.cc b/chromium/chrome/browser/signin/force_signin_verifier_unittest.cc
new file mode 100644
index 00000000000..dcd382d6b38
--- /dev/null
+++ b/chromium/chrome/browser/signin/force_signin_verifier_unittest.cc
@@ -0,0 +1,416 @@
+// Copyright 2017 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 "chrome/browser/signin/force_signin_verifier.h"
+
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/signin/public/identity_manager/identity_test_environment.h"
+#include "content/public/browser/network_service_instance.h"
+#include "services/network/test/test_network_connection_tracker.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class ForceSigninVerifierWithAccessToInternalsForTesting
+ : public ForceSigninVerifier {
+ public:
+ explicit ForceSigninVerifierWithAccessToInternalsForTesting(
+ signin::IdentityManager* identity_manager)
+ : ForceSigninVerifier(nullptr, identity_manager) {}
+
+ bool IsDelayTaskPosted() { return GetOneShotTimerForTesting()->IsRunning(); }
+
+ int FailureCount() { return GetBackoffEntryForTesting()->failure_count(); }
+
+ signin::PrimaryAccountAccessTokenFetcher* access_token_fetcher() {
+ return GetAccessTokenFetcherForTesting();
+ }
+
+ MOCK_METHOD0(CloseAllBrowserWindows, void(void));
+};
+
+// A NetworkConnectionObserver that invokes a base::RepeatingClosure when
+// NetworkConnectionObserver::OnConnectionChanged() is invoked.
+class NetworkConnectionObserverHelper
+ : public network::NetworkConnectionTracker::NetworkConnectionObserver {
+ public:
+ explicit NetworkConnectionObserverHelper(base::RepeatingClosure closure)
+ : closure_(std::move(closure)) {
+ DCHECK(!closure_.is_null());
+ content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
+ }
+
+ NetworkConnectionObserverHelper(const NetworkConnectionObserverHelper&) =
+ delete;
+ NetworkConnectionObserverHelper& operator=(
+ const NetworkConnectionObserverHelper&) = delete;
+
+ ~NetworkConnectionObserverHelper() override {
+ content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(
+ this);
+ }
+
+ void OnConnectionChanged(network::mojom::ConnectionType type) override {
+ closure_.Run();
+ }
+
+ private:
+ base::RepeatingClosure closure_;
+};
+
+// Used to select which type of network type NetworkConnectionTracker should
+// be configured to.
+enum class NetworkConnectionType {
+ Undecided,
+ ConnectionNone,
+ ConnectionWifi,
+ Connection4G,
+};
+
+// Used to select which type of response NetworkConnectionTracker should give.
+enum class NetworkResponseType {
+ Undecided,
+ Synchronous,
+ Asynchronous,
+};
+
+// Forces the network connection type to change to |connection_type| and wait
+// till the notification has been propagated to the observers. Also change the
+// response type to be synchronous/asynchronous based on |response_type|.
+void ConfigureNetworkConnectionTracker(NetworkConnectionType connection_type,
+ NetworkResponseType response_type) {
+ network::TestNetworkConnectionTracker* tracker =
+ network::TestNetworkConnectionTracker::GetInstance();
+
+ switch (response_type) {
+ case NetworkResponseType::Undecided:
+ // nothing to do
+ break;
+
+ case NetworkResponseType::Synchronous:
+ tracker->SetRespondSynchronously(true);
+ break;
+
+ case NetworkResponseType::Asynchronous:
+ tracker->SetRespondSynchronously(false);
+ break;
+ }
+
+ if (connection_type != NetworkConnectionType::Undecided) {
+ network::mojom::ConnectionType mojom_connection_type =
+ network::mojom::ConnectionType::CONNECTION_UNKNOWN;
+
+ switch (connection_type) {
+ case NetworkConnectionType::Undecided:
+ NOTREACHED();
+ break;
+
+ case NetworkConnectionType::ConnectionNone:
+ mojom_connection_type = network::mojom::ConnectionType::CONNECTION_NONE;
+ break;
+
+ case NetworkConnectionType::ConnectionWifi:
+ mojom_connection_type = network::mojom::ConnectionType::CONNECTION_WIFI;
+ break;
+
+ case NetworkConnectionType::Connection4G:
+ mojom_connection_type = network::mojom::ConnectionType::CONNECTION_4G;
+ break;
+ }
+
+ DCHECK_NE(mojom_connection_type,
+ network::mojom::ConnectionType::CONNECTION_UNKNOWN);
+
+ base::RunLoop wait_for_network_type_change;
+ NetworkConnectionObserverHelper scoped_observer(
+ wait_for_network_type_change.QuitWhenIdleClosure());
+
+ tracker->SetConnectionType(mojom_connection_type);
+
+ wait_for_network_type_change.Run();
+ }
+}
+
+// Forces the current sequence's task runner to spin. This is used because the
+// ForceSigninVerifier ends up posting task to the sequence's task runner when
+// MetworkConnectionTracker is returning results asynchronously.
+void SpinCurrentSequenceTaskRunner() {
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ run_loop.QuitClosure());
+ run_loop.Run();
+}
+
+} // namespace
+
+TEST(ForceSigninVerifierTest, OnGetTokenSuccess) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ ASSERT_NE(nullptr, verifier.access_token_fetcher());
+ ASSERT_FALSE(verifier.HasTokenBeenVerified());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+ EXPECT_CALL(verifier, CloseAllBrowserWindows()).Times(0);
+
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+ account_info.account_id, /*token=*/"", base::Time());
+
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+ ASSERT_TRUE(verifier.HasTokenBeenVerified());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+ ASSERT_EQ(0, verifier.FailureCount());
+}
+
+TEST(ForceSigninVerifierTest, OnGetTokenPersistentFailure) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ ASSERT_NE(nullptr, verifier.access_token_fetcher());
+ ASSERT_FALSE(verifier.HasTokenBeenVerified());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+ EXPECT_CALL(verifier, CloseAllBrowserWindows()).Times(1);
+
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
+ GoogleServiceAuthError(
+ GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
+
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+ ASSERT_TRUE(verifier.HasTokenBeenVerified());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+ ASSERT_EQ(0, verifier.FailureCount());
+}
+
+TEST(ForceSigninVerifierTest, OnGetTokenTransientFailure) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ ASSERT_NE(nullptr, verifier.access_token_fetcher());
+ ASSERT_FALSE(verifier.HasTokenBeenVerified());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+ EXPECT_CALL(verifier, CloseAllBrowserWindows()).Times(0);
+
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
+ GoogleServiceAuthError(GoogleServiceAuthError::State::CONNECTION_FAILED));
+
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+ ASSERT_FALSE(verifier.HasTokenBeenVerified());
+ ASSERT_TRUE(verifier.IsDelayTaskPosted());
+ ASSERT_EQ(1, verifier.FailureCount());
+}
+
+TEST(ForceSigninVerifierTest, OnLostConnection) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
+ GoogleServiceAuthError(GoogleServiceAuthError::State::CONNECTION_FAILED));
+
+ ASSERT_EQ(1, verifier.FailureCount());
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+ ASSERT_TRUE(verifier.IsDelayTaskPosted());
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::ConnectionNone,
+ NetworkResponseType::Undecided);
+
+ ASSERT_EQ(0, verifier.FailureCount());
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+}
+
+TEST(ForceSigninVerifierTest, OnReconnected) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
+ GoogleServiceAuthError(GoogleServiceAuthError::State::CONNECTION_FAILED));
+
+ ASSERT_EQ(1, verifier.FailureCount());
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+ ASSERT_TRUE(verifier.IsDelayTaskPosted());
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::ConnectionWifi,
+ NetworkResponseType::Undecided);
+
+ ASSERT_EQ(0, verifier.FailureCount());
+ ASSERT_NE(nullptr, verifier.access_token_fetcher());
+ ASSERT_FALSE(verifier.IsDelayTaskPosted());
+}
+
+TEST(ForceSigninVerifierTest, GetNetworkStatusAsync) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::Undecided,
+ NetworkResponseType::Asynchronous);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ // There is no network type at first.
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Waiting for the network type returns.
+ SpinCurrentSequenceTaskRunner();
+
+ // Get the type and send the request.
+ ASSERT_NE(nullptr, verifier.access_token_fetcher());
+}
+
+TEST(ForceSigninVerifierTest, LaunchVerifierWithoutNetwork) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::ConnectionNone,
+ NetworkResponseType::Asynchronous);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ // There is no network type.
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Waiting for the network type returns.
+ SpinCurrentSequenceTaskRunner();
+
+ // Get the type, there is no network connection, don't send the request.
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Network is resumed.
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::ConnectionWifi,
+ NetworkResponseType::Undecided);
+
+ // Send the request.
+ ASSERT_NE(nullptr, verifier.access_token_fetcher());
+}
+
+TEST(ForceSigninVerifierTest, ChangeNetworkFromWIFITo4GWithOnGoingRequest) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::ConnectionWifi,
+ NetworkResponseType::Asynchronous);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ EXPECT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Waiting for the network type returns.
+ SpinCurrentSequenceTaskRunner();
+
+ // The network type if wifi, send the request.
+ auto* first_request = verifier.access_token_fetcher();
+ EXPECT_NE(nullptr, first_request);
+
+ // Network is changed to 4G.
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::Connection4G,
+ NetworkResponseType::Undecided);
+
+ // There is still one on-going request.
+ EXPECT_EQ(first_request, verifier.access_token_fetcher());
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+ account_info.account_id, /*token=*/"", base::Time());
+}
+
+TEST(ForceSigninVerifierTest, ChangeNetworkFromWIFITo4GWithFinishedRequest) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::ConnectionWifi,
+ NetworkResponseType::Asynchronous);
+
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ EXPECT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Waiting for the network type returns.
+ SpinCurrentSequenceTaskRunner();
+
+ // The network type if wifi, send the request.
+ EXPECT_NE(nullptr, verifier.access_token_fetcher());
+
+ // Finishes the request.
+ identity_test_env.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
+ account_info.account_id, /*token=*/"", base::Time());
+ EXPECT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Network is changed to 4G.
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::Connection4G,
+ NetworkResponseType::Undecided);
+
+ // No more request because it's verfied already.
+ EXPECT_EQ(nullptr, verifier.access_token_fetcher());
+}
+
+// Regression test for https://crbug.com/1259864
+TEST(ForceSigninVerifierTest, DeleteWithPendingRequestShouldNotCrash) {
+ base::test::TaskEnvironment scoped_task_env;
+ signin::IdentityTestEnvironment identity_test_env;
+ const AccountInfo account_info =
+ identity_test_env.MakePrimaryAccountAvailable(
+ "email@test.com", signin::ConsentLevel::kSync);
+
+ ConfigureNetworkConnectionTracker(NetworkConnectionType::Undecided,
+ NetworkResponseType::Asynchronous);
+
+ {
+ ForceSigninVerifierWithAccessToInternalsForTesting verifier(
+ identity_test_env.identity_manager());
+
+ // There is no network type at first.
+ ASSERT_EQ(nullptr, verifier.access_token_fetcher());
+
+ // Delete the verifier while the request is pending.
+ }
+
+ // Waiting for the network type returns, this should not crash.
+ SpinCurrentSequenceTaskRunner();
+}