blob: cd901bb3a4cb1a86b5fa6ccd11e653f084377dae [file] [log] [blame]
// 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 "chrome/browser/signin/dice_tab_helper.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/task_environment.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "content/public/common/content_features.h"
#include "content/public/test/back_forward_cache_util.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/prerender_test_util.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "google_apis/gaia/gaia_urls.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
class DiceTabHelperTest : public ChromeRenderViewHostTestHarness {
public:
DiceTabHelperTest() {
signin_url_ = GaiaUrls::GetInstance()->signin_chrome_sync_dice();
std::vector<base::test::FeatureRefAndParams> enabled_features =
content::GetBasicBackForwardCacheFeatureForTesting();
std::vector<base::test::FeatureRef> disabled_features =
content::GetDefaultDisabledBackForwardCacheFeaturesForTesting();
feature_list_.InitWithFeaturesAndParameters(enabled_features,
disabled_features);
}
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
identity_test_env_adaptor_ =
std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
}
// ChromeRenderViewHostTestHarness::
TestingProfile::TestingFactories GetTestingFactories() const override {
return IdentityTestEnvironmentProfileAdaptor::
GetIdentityTestEnvironmentFactories();
}
// Does a navigation to Gaia and initializes the tab helper.
void InitializeDiceTabHelper(DiceTabHelper* helper,
signin_metrics::AccessPoint access_point,
signin_metrics::Reason reason) {
// Load the signin page.
std::unique_ptr<content::NavigationSimulator> simulator =
content::NavigationSimulator::CreateRendererInitiated(signin_url_,
main_rfh());
simulator->Start();
helper->InitializeSigninFlow(
signin_url_, access_point, reason,
signin_metrics::PromoAction::PROMO_ACTION_NO_SIGNIN_PROMO, GURL(),
/*record_signin_started_metrics=*/true,
DiceTabHelper::EnableSyncCallback(),
DiceTabHelper::OnSigninHeaderReceived(),
DiceTabHelper::ShowSigninErrorCallback());
EXPECT_TRUE(helper->IsChromeSigninPage());
simulator->Commit();
}
GURL signin_url_;
base::test::ScopedFeatureList feature_list_;
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
};
TEST_F(DiceTabHelperTest, Initialization) {
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
// Check default state.
EXPECT_EQ(signin_metrics::AccessPoint::ACCESS_POINT_WEB_SIGNIN,
dice_tab_helper->signin_access_point());
EXPECT_EQ(signin_metrics::Reason::kUnknownReason,
dice_tab_helper->signin_reason());
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
// Initialize the signin flow.
signin_metrics::AccessPoint access_point =
signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE;
signin_metrics::Reason reason = signin_metrics::Reason::kSigninPrimaryAccount;
InitializeDiceTabHelper(dice_tab_helper, access_point, reason);
EXPECT_EQ(access_point, dice_tab_helper->signin_access_point());
EXPECT_EQ(reason, dice_tab_helper->signin_reason());
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
EXPECT_EQ(identity_test_env_adaptor_->identity_test_env()
->GetNumCallsToPrepareForFetchingAccountCapabilities(),
1);
}
TEST_F(DiceTabHelperTest, SigninPageStatus) {
// The test assumes the previous page gets deleted after navigation and will
// be recreated after navigation (which resets the signin page state). Disable
// back/forward cache to ensure that it doesn't get preserved in the cache.
content::DisableBackForwardCacheForTesting(
web_contents(), content::BackForwardCache::TEST_REQUIRES_NO_CACHING);
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
// Load the signin page.
signin_metrics::AccessPoint access_point =
signin_metrics::AccessPoint::ACCESS_POINT_BOOKMARK_BUBBLE;
signin_metrics::Reason reason = signin_metrics::Reason::kSigninPrimaryAccount;
InitializeDiceTabHelper(dice_tab_helper, access_point, reason);
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
// Reloading the signin page does not interrupt the signin flow.
content::NavigationSimulator::Reload(web_contents());
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
// Subframe navigation are ignored.
std::unique_ptr<content::NavigationSimulator> simulator =
content::NavigationSimulator::CreateRendererInitiated(
signin_url_.Resolve("#baz"), main_rfh());
simulator->CommitSameDocument();
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
// Navigation in subframe does not interrupt the signin flow.
content::RenderFrameHostTester* render_frame_host_tester =
content::RenderFrameHostTester::For(main_rfh());
content::RenderFrameHost* sub_frame =
render_frame_host_tester->AppendChild("subframe");
content::NavigationSimulator::NavigateAndCommitFromDocument(signin_url_,
sub_frame);
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
// Navigating to a different page resets the page status.
simulator = content::NavigationSimulator::CreateRendererInitiated(
signin_url_.Resolve("/foo"), main_rfh());
simulator->Start();
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
simulator->Commit();
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
// Go Back to the signin page
content::NavigationSimulator::GoBack(web_contents());
// IsChromeSigninPage() returns false after navigating away from the
// signin page.
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
// Navigate away from the signin page
content::NavigationSimulator::GoForward(web_contents());
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
}
// Tests DiceTabHelper metrics with the `kSigninPrimaryAccount` reason.
TEST_F(DiceTabHelperTest, SigninPrimaryAccountMetrics) {
base::UserActionTester ua_tester;
base::HistogramTester h_tester;
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
// No metrics are logged when the Dice tab helper is created.
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_Signin_FromStartPage"));
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
// Check metrics logged when the Dice tab helper is initialized.
std::unique_ptr<content::NavigationSimulator> simulator =
content::NavigationSimulator::CreateRendererInitiated(signin_url_,
main_rfh());
simulator->Start();
dice_tab_helper->InitializeSigninFlow(
signin_url_, signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
signin_metrics::Reason::kSigninPrimaryAccount,
signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT,
GURL(), /*record_signin_started_metrics=*/true,
DiceTabHelper::EnableSyncCallback(),
DiceTabHelper::OnSigninHeaderReceived(),
DiceTabHelper::ShowSigninErrorCallback());
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_Signin_FromSettings"));
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
h_tester.ExpectUniqueSample(
"Signin.SigninStartedAccessPoint",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 1);
h_tester.ExpectUniqueSample(
"Signin.SigninStartedAccessPoint.NewAccountNoExistingAccount",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 1);
h_tester.ExpectUniqueSample(
"Signin.SignIn.Started",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 1);
// First call to did finish load does logs any Signin_SigninPage_Shown user
// action.
simulator->Commit();
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
// Second call to did finish load does not log any metrics.
dice_tab_helper->DidFinishLoad(main_rfh(), signin_url_);
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
// Check metrics are logged again when the Dice tab helper is re-initialized.
simulator = content::NavigationSimulator::CreateRendererInitiated(signin_url_,
main_rfh());
simulator->Start();
dice_tab_helper->InitializeSigninFlow(
signin_url_, signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
signin_metrics::Reason::kSigninPrimaryAccount,
signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, GURL(),
/*record_signin_started_metrics=*/true,
DiceTabHelper::EnableSyncCallback(),
DiceTabHelper::OnSigninHeaderReceived(),
DiceTabHelper::ShowSigninErrorCallback());
EXPECT_EQ(2, ua_tester.GetActionCount("Signin_Signin_FromSettings"));
EXPECT_EQ(2, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
h_tester.ExpectUniqueSample(
"Signin.SigninStartedAccessPoint",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 2);
h_tester.ExpectUniqueSample(
"Signin.SigninStartedAccessPoint.WithDefault",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 1);
h_tester.ExpectUniqueSample(
"Signin.SignIn.Started",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 2);
// Check metrics are NOT logged again when `record_signin_started_metrics`is
// false.
simulator = content::NavigationSimulator::CreateRendererInitiated(signin_url_,
main_rfh());
simulator->Start();
dice_tab_helper->InitializeSigninFlow(
signin_url_, signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
signin_metrics::Reason::kSigninPrimaryAccount,
signin_metrics::PromoAction::PROMO_ACTION_WITH_DEFAULT, GURL(),
/*record_signin_started_metrics=*/false,
DiceTabHelper::EnableSyncCallback(),
DiceTabHelper::OnSigninHeaderReceived(),
DiceTabHelper::ShowSigninErrorCallback());
EXPECT_EQ(2, ua_tester.GetActionCount("Signin_Signin_FromSettings"));
EXPECT_EQ(2, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
h_tester.ExpectUniqueSample(
"Signin.SigninStartedAccessPoint",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 2);
h_tester.ExpectUniqueSample(
"Signin.SigninStartedAccessPoint.WithDefault",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 1);
h_tester.ExpectUniqueSample(
"Signin.SignIn.Started",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 2);
}
// Tests DiceTabHelper metrics with the `kAddSecondaryAccount` reason.
TEST_F(DiceTabHelperTest, AddSecondaryAccountMetrics) {
base::UserActionTester ua_tester;
base::HistogramTester h_tester;
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
// Check metrics logged when the Dice tab helper is initialized.
std::unique_ptr<content::NavigationSimulator> simulator =
content::NavigationSimulator::CreateRendererInitiated(signin_url_,
main_rfh());
simulator->Start();
dice_tab_helper->InitializeSigninFlow(
signin_url_, signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
signin_metrics::Reason::kAddSecondaryAccount,
signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT_NO_EXISTING_ACCOUNT,
GURL(), /*record_signin_started_metrics=*/true,
DiceTabHelper::EnableSyncCallback(),
DiceTabHelper::OnSigninHeaderReceived(),
DiceTabHelper::ShowSigninErrorCallback());
h_tester.ExpectUniqueSample(
"Signin.SignIn.Started",
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS, 1);
// First call to did finish load does logs any Signin_SigninPage_Shown user
// action.
simulator->Commit();
// These metrics are only logged with the `kSigninPrimaryAccount` reason.
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_Signin_FromSettings"));
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_SigninPage_Loading"));
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
h_tester.ExpectTotalCount("Signin.SigninStartedAccessPoint", 0);
h_tester.ExpectTotalCount(
"Signin.SigninStartedAccessPoint.NewAccountNoExistingAccount", 0);
}
TEST_F(DiceTabHelperTest, IsSyncSigninInProgress) {
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
EXPECT_FALSE(dice_tab_helper->IsSyncSigninInProgress());
// Non-sync signin.
InitializeDiceTabHelper(dice_tab_helper,
signin_metrics::AccessPoint::ACCESS_POINT_EXTENSIONS,
signin_metrics::Reason::kAddSecondaryAccount);
EXPECT_FALSE(dice_tab_helper->IsSyncSigninInProgress());
// Sync signin
InitializeDiceTabHelper(dice_tab_helper,
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
signin_metrics::Reason::kSigninPrimaryAccount);
EXPECT_TRUE(dice_tab_helper->IsSyncSigninInProgress());
dice_tab_helper->OnSyncSigninFlowComplete();
EXPECT_FALSE(dice_tab_helper->IsSyncSigninInProgress());
}
TEST_F(DiceTabHelperTest, SigninPendingResolutionStarted) {
auto* identity_test_env = identity_test_env_adaptor_->identity_test_env();
// Sign in
identity_test_env->MakePrimaryAccountAvailable("primary@gmail.com",
signin::ConsentLevel::kSignin);
base::HistogramTester h_tester;
signin_metrics::AccessPoint access_point =
signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN;
{
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
InitializeDiceTabHelper(dice_tab_helper, access_point,
signin_metrics::Reason::kReauthentication);
}
// No value recorded as we are not in a Signin pending State yet.
h_tester.ExpectTotalCount("Signin.SigninPending.ResolutionSourceStarted", 0);
// Trigger signin pending.
identity_test_env->SetInvalidRefreshTokenForPrimaryAccount();
{
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
InitializeDiceTabHelper(dice_tab_helper, access_point,
signin_metrics::Reason::kReauthentication);
}
h_tester.ExpectUniqueSample("Signin.SigninPending.ResolutionSourceStarted",
access_point, 1);
}
class DiceTabHelperPrerenderTest : public DiceTabHelperTest {
public:
DiceTabHelperPrerenderTest() = default;
private:
content::test::ScopedPrerenderFeatureList prerender_feature_list_;
};
TEST_F(DiceTabHelperPrerenderTest, SigninStatusAfterPrerendering) {
content::test::ScopedPrerenderWebContentsDelegate web_contents_delegate(
*web_contents());
base::UserActionTester ua_tester;
DiceTabHelper::CreateForWebContents(web_contents());
DiceTabHelper* dice_tab_helper =
DiceTabHelper::FromWebContents(web_contents());
EXPECT_FALSE(dice_tab_helper->IsChromeSigninPage());
EXPECT_EQ(0, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
// Sync signin
InitializeDiceTabHelper(dice_tab_helper,
signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS,
signin_metrics::Reason::kSigninPrimaryAccount);
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
// Starting prerendering a page doesn't navigate away from the signin page.
content::WebContentsTester::For(web_contents())
->AddPrerenderAndCommitNavigation(signin_url_.Resolve("/foo/test.html"));
EXPECT_TRUE(dice_tab_helper->IsChromeSigninPage());
EXPECT_EQ(1, ua_tester.GetActionCount("Signin_SigninPage_Shown"));
}