1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/signin/signin_global_error.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <string>
11 
12 #include "base/bind.h"
13 #include "base/stl_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/test/metrics/histogram_tester.h"
16 #include "chrome/browser/profiles/profile_attributes_entry.h"
17 #include "chrome/browser/profiles/profile_attributes_storage.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/profiles/profile_metrics.h"
20 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
21 #include "chrome/browser/signin/signin_error_controller_factory.h"
22 #include "chrome/browser/signin/signin_global_error_factory.h"
23 #include "chrome/browser/ui/global_error/global_error_service.h"
24 #include "chrome/browser/ui/global_error/global_error_service_factory.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/testing_profile_manager.h"
29 #include "components/prefs/pref_service.h"
30 #include "components/signin/core/browser/signin_error_controller.h"
31 #include "components/signin/public/identity_manager/identity_test_environment.h"
32 #include "components/signin/public/identity_manager/identity_test_utils.h"
33 #include "components/sync_preferences/pref_service_syncable.h"
34 #include "content/public/test/browser_task_environment.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36 
37 static const char kTestEmail[] = "testuser@test.com";
38 
39 class SigninGlobalErrorTest : public testing::Test {
40  public:
SigninGlobalErrorTest()41   SigninGlobalErrorTest() :
42       profile_manager_(TestingBrowserProcess::GetGlobal()) {}
43 
SetUp()44   void SetUp() override {
45     ASSERT_TRUE(profile_manager_.SetUp());
46 
47     // Create a signed-in profile.
48     TestingProfile::TestingFactories testing_factories =
49         IdentityTestEnvironmentProfileAdaptor::
50             GetIdentityTestEnvironmentFactories();
51 
52     profile_ = profile_manager_.CreateTestingProfile(
53         "Person 1", std::unique_ptr<sync_preferences::PrefServiceSyncable>(),
54         base::UTF8ToUTF16("Person 1"), 0, std::string(),
55         std::move(testing_factories));
56 
57     identity_test_env_profile_adaptor_ =
58         std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile());
59 
60     AccountInfo account_info =
61         identity_test_env_profile_adaptor_->identity_test_env()
62             ->MakePrimaryAccountAvailable(kTestEmail);
63     ProfileAttributesEntry* entry;
64     ASSERT_TRUE(profile_manager_.profile_attributes_storage()->
65         GetProfileAttributesWithPath(profile()->GetPath(), &entry));
66 
67     entry->SetAuthInfo(account_info.gaia, base::UTF8ToUTF16(kTestEmail),
68                        /*is_consented_primary_account=*/true);
69 
70     global_error_ = SigninGlobalErrorFactory::GetForProfile(profile());
71     error_controller_ = SigninErrorControllerFactory::GetForProfile(profile());
72   }
73 
profile()74   TestingProfile* profile() { return profile_; }
testing_profile_manager()75   TestingProfileManager* testing_profile_manager() {
76     return &profile_manager_;
77   }
78 
global_error()79   SigninGlobalError* global_error() { return global_error_; }
error_controller()80   SigninErrorController* error_controller() { return error_controller_; }
81 
SetAuthError(GoogleServiceAuthError::State state)82   void SetAuthError(GoogleServiceAuthError::State state) {
83     signin::IdentityTestEnvironment* identity_test_env =
84         identity_test_env_profile_adaptor_->identity_test_env();
85     CoreAccountId primary_account_id =
86         identity_test_env->identity_manager()->GetPrimaryAccountId();
87 
88     signin::UpdatePersistentErrorOfRefreshTokenForAccount(
89         identity_test_env->identity_manager(), primary_account_id,
90         GoogleServiceAuthError(state));
91   }
92 
93  private:
94   content::BrowserTaskEnvironment task_environment_;
95   TestingProfileManager profile_manager_;
96   TestingProfile* profile_;
97 
98   std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
99       identity_test_env_profile_adaptor_;
100 
101   SigninGlobalError* global_error_;
102   SigninErrorController* error_controller_;
103 };
104 
TEST_F(SigninGlobalErrorTest,Basic)105 TEST_F(SigninGlobalErrorTest, Basic) {
106   ASSERT_FALSE(global_error()->HasMenuItem());
107 
108   SetAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
109   EXPECT_TRUE(global_error()->HasMenuItem());
110 
111   SetAuthError(GoogleServiceAuthError::NONE);
112   EXPECT_FALSE(global_error()->HasMenuItem());
113 }
114 
115 // Verify that SigninGlobalError ignores certain errors.
TEST_F(SigninGlobalErrorTest,AuthStatusEnumerateAllErrors)116 TEST_F(SigninGlobalErrorTest, AuthStatusEnumerateAllErrors) {
117   typedef struct {
118     GoogleServiceAuthError::State error_state;
119     bool is_error;
120   } ErrorTableEntry;
121 
122   ErrorTableEntry table[] = {
123       {GoogleServiceAuthError::NONE, false},
124       {GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, true},
125       {GoogleServiceAuthError::USER_NOT_SIGNED_UP, true},
126       {GoogleServiceAuthError::CONNECTION_FAILED, false},
127       {GoogleServiceAuthError::SERVICE_UNAVAILABLE, false},
128       {GoogleServiceAuthError::REQUEST_CANCELED, false},
129       {GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true},
130       {GoogleServiceAuthError::SERVICE_ERROR, true},
131   };
132   static_assert(
133       base::size(table) == GoogleServiceAuthError::NUM_STATES -
134                                GoogleServiceAuthError::kDeprecatedStateCount,
135       "table size should match number of auth error types");
136 
137   // Mark the profile with an active timestamp so profile_metrics logs it.
138   testing_profile_manager()->UpdateLastUser(profile());
139 
140   for (ErrorTableEntry entry : table) {
141     SetAuthError(GoogleServiceAuthError::NONE);
142 
143     base::HistogramTester histogram_tester;
144     SetAuthError(entry.error_state);
145 
146     EXPECT_EQ(global_error()->HasMenuItem(), entry.is_error);
147     EXPECT_EQ(global_error()->MenuItemLabel().empty(), !entry.is_error);
148     EXPECT_EQ(global_error()->GetBubbleViewMessages().empty(), !entry.is_error);
149     EXPECT_FALSE(global_error()->GetBubbleViewTitle().empty());
150     EXPECT_FALSE(global_error()->GetBubbleViewAcceptButtonLabel().empty());
151     EXPECT_TRUE(global_error()->GetBubbleViewCancelButtonLabel().empty());
152 
153     ProfileMetrics::LogNumberOfProfiles(&testing_profile_manager()
154                                              ->profile_manager()
155                                              ->GetProfileAttributesStorage());
156 
157     if (entry.is_error) {
158       histogram_tester.ExpectBucketCount("Signin.AuthError", entry.error_state,
159                                          1);
160     }
161     histogram_tester.ExpectBucketCount("Profile.NumberOfProfilesWithAuthErrors",
162                                        entry.is_error, 1);
163   }
164 }
165