• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "components/signin/core/browser/signin_error_controller.h"
6 
7 #include <functional>
8 
9 #include "base/memory/scoped_ptr.h"
10 #include "components/signin/core/browser/fake_auth_status_provider.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 static const char kTestAccountId[] = "testuser@test.com";
14 static const char kTestUsername[] = "testuser@test.com";
15 static const char kOtherTestAccountId[] = "otheruser@test.com";
16 static const char kOtherTestUsername[] = "otheruser@test.com";
17 
18 class SigninErrorControllerTest : public testing::Test {
19  public:
SetUp()20   virtual void SetUp() OVERRIDE {
21     error_controller_.reset(new SigninErrorController());
22   }
23 
24   scoped_ptr<SigninErrorController> error_controller_;
25 };
26 
TEST_F(SigninErrorControllerTest,NoErrorAuthStatusProviders)27 TEST_F(SigninErrorControllerTest, NoErrorAuthStatusProviders) {
28   scoped_ptr<FakeAuthStatusProvider> provider;
29 
30   // No providers.
31   ASSERT_FALSE(error_controller_->HasError());
32 
33   // Add a provider.
34   provider.reset(new FakeAuthStatusProvider(error_controller_.get()));
35   ASSERT_FALSE(error_controller_->HasError());
36 
37   // Remove the provider.
38   provider.reset();
39   ASSERT_FALSE(error_controller_->HasError());
40 }
41 
TEST_F(SigninErrorControllerTest,ErrorAuthStatusProvider)42 TEST_F(SigninErrorControllerTest, ErrorAuthStatusProvider) {
43   scoped_ptr<FakeAuthStatusProvider> provider;
44   scoped_ptr<FakeAuthStatusProvider> error_provider;
45 
46   provider.reset(new FakeAuthStatusProvider(error_controller_.get()));
47   ASSERT_FALSE(error_controller_->HasError());
48 
49   error_provider.reset(new FakeAuthStatusProvider(error_controller_.get()));
50   error_provider->SetAuthError(
51       kTestAccountId,
52       kTestUsername,
53       GoogleServiceAuthError(
54           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
55   ASSERT_TRUE(error_controller_->HasError());
56 
57   error_provider.reset();
58   ASSERT_FALSE(error_controller_->HasError());
59 
60   provider.reset();
61   // All providers should be removed now.
62   ASSERT_FALSE(error_controller_->HasError());
63 }
64 
TEST_F(SigninErrorControllerTest,AuthStatusProviderErrorTransition)65 TEST_F(SigninErrorControllerTest, AuthStatusProviderErrorTransition) {
66   scoped_ptr<FakeAuthStatusProvider> provider0(
67       new FakeAuthStatusProvider(error_controller_.get()));
68   scoped_ptr<FakeAuthStatusProvider> provider1(
69       new FakeAuthStatusProvider(error_controller_.get()));
70 
71   ASSERT_FALSE(error_controller_->HasError());
72   provider0->SetAuthError(
73       kTestAccountId,
74       kTestUsername,
75       GoogleServiceAuthError(
76           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
77   ASSERT_TRUE(error_controller_->HasError());
78   provider1->SetAuthError(
79       kTestAccountId,
80       kTestUsername,
81       GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED));
82   ASSERT_TRUE(error_controller_->HasError());
83 
84   // Now resolve the auth errors - the menu item should go away.
85   provider0->SetAuthError(kTestAccountId,
86                           kTestUsername,
87                          GoogleServiceAuthError::AuthErrorNone());
88   ASSERT_TRUE(error_controller_->HasError());
89   provider1->SetAuthError(kTestAccountId,
90                           kTestUsername,
91                           GoogleServiceAuthError::AuthErrorNone());
92   ASSERT_FALSE(error_controller_->HasError());
93 
94   provider0.reset();
95   provider1.reset();
96   ASSERT_FALSE(error_controller_->HasError());
97 }
98 
TEST_F(SigninErrorControllerTest,AuthStatusProviderAccountTransition)99 TEST_F(SigninErrorControllerTest, AuthStatusProviderAccountTransition) {
100   scoped_ptr<FakeAuthStatusProvider> provider0(
101       new FakeAuthStatusProvider(error_controller_.get()));
102   scoped_ptr<FakeAuthStatusProvider> provider1(
103       new FakeAuthStatusProvider(error_controller_.get()));
104 
105   ASSERT_FALSE(error_controller_->HasError());
106 
107   provider0->SetAuthError(
108       kTestAccountId,
109       kTestUsername,
110       GoogleServiceAuthError(
111           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
112   provider1->SetAuthError(
113       kOtherTestAccountId,
114       kOtherTestUsername,
115       GoogleServiceAuthError(GoogleServiceAuthError::NONE));
116   ASSERT_TRUE(error_controller_->HasError());
117   ASSERT_STREQ(kTestAccountId,
118                error_controller_->error_account_id().c_str());
119 
120   // Swap providers reporting errors.
121   provider1->set_error_without_status_change(
122       GoogleServiceAuthError(
123           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
124   provider0->set_error_without_status_change(
125       GoogleServiceAuthError(GoogleServiceAuthError::NONE));
126   error_controller_->AuthStatusChanged();
127   ASSERT_TRUE(error_controller_->HasError());
128   ASSERT_STREQ(kOtherTestAccountId,
129                error_controller_->error_account_id().c_str());
130 
131   // Now resolve the auth errors - the menu item should go away.
132   provider0->set_error_without_status_change(
133       GoogleServiceAuthError::AuthErrorNone());
134   provider1->set_error_without_status_change(
135       GoogleServiceAuthError::AuthErrorNone());
136   error_controller_->AuthStatusChanged();
137   ASSERT_FALSE(error_controller_->HasError());
138 
139   provider0.reset();
140   provider1.reset();
141   ASSERT_FALSE(error_controller_->HasError());
142 }
143 
144 // Verify that SigninErrorController handles errors properly.
TEST_F(SigninErrorControllerTest,AuthStatusEnumerateAllErrors)145 TEST_F(SigninErrorControllerTest, AuthStatusEnumerateAllErrors) {
146   typedef struct {
147     GoogleServiceAuthError::State error_state;
148     bool is_error;
149   } ErrorTableEntry;
150 
151   ErrorTableEntry table[] = {
152     { GoogleServiceAuthError::NONE, false },
153     { GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS, true },
154     { GoogleServiceAuthError::USER_NOT_SIGNED_UP, true },
155     { GoogleServiceAuthError::CONNECTION_FAILED, false },
156     { GoogleServiceAuthError::CAPTCHA_REQUIRED, true },
157     { GoogleServiceAuthError::ACCOUNT_DELETED, true },
158     { GoogleServiceAuthError::ACCOUNT_DISABLED, true },
159     { GoogleServiceAuthError::SERVICE_UNAVAILABLE, true },
160     { GoogleServiceAuthError::TWO_FACTOR, true },
161     { GoogleServiceAuthError::REQUEST_CANCELED, true },
162     { GoogleServiceAuthError::HOSTED_NOT_ALLOWED, true },
163     { GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE, true },
164     { GoogleServiceAuthError::SERVICE_ERROR, true },
165   };
166   COMPILE_ASSERT(ARRAYSIZE_UNSAFE(table) == GoogleServiceAuthError::NUM_STATES,
167       kTable_size_does_not_match_number_of_auth_error_types);
168 
169   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(table); ++i) {
170     FakeAuthStatusProvider provider(error_controller_.get());
171     provider.SetAuthError(kTestAccountId,
172                           kTestUsername,
173                           GoogleServiceAuthError(table[i].error_state));
174 
175     EXPECT_EQ(error_controller_->HasError(), table[i].is_error);
176 
177     if (table[i].is_error) {
178       EXPECT_EQ(table[i].error_state,
179                 error_controller_->auth_error().state());
180       EXPECT_STREQ(kTestAccountId,
181                    error_controller_->error_account_id().c_str());
182     } else {
183       EXPECT_EQ(GoogleServiceAuthError::NONE,
184                 error_controller_->auth_error().state());
185       EXPECT_STREQ("",
186                    error_controller_->error_account_id().c_str());
187     }
188   }
189 }
190 
191 // Verify that existing error is not replaced by new error.
TEST_F(SigninErrorControllerTest,AuthStatusChange)192 TEST_F(SigninErrorControllerTest, AuthStatusChange) {
193   scoped_ptr<FakeAuthStatusProvider> fake_provider0(
194       new FakeAuthStatusProvider(error_controller_.get()));
195   scoped_ptr<FakeAuthStatusProvider> fake_provider1(
196       new FakeAuthStatusProvider(error_controller_.get()));
197 
198   // If there are multiple providers in the provider set...
199   //
200   // | provider0 |       provider1          | ...
201   // |   NONE    | INVALID_GAIA_CREDENTIALS | ...
202   //
203   // SigninErrorController picks the first error found when iterating through
204   // the set. But if another error crops up...
205   //
206   // |     provider0       |       provider1          | ...
207   // | SERVICE_UNAVAILABLE | INVALID_GAIA_CREDENTIALS | ...
208   //
209   // we want the controller to still use the original error.
210 
211   // The provider pointers are stored in a set, which is sorted by std::less.
212   std::less<SigninErrorController::AuthStatusProvider*> compare;
213   FakeAuthStatusProvider* provider0 =
214       compare(fake_provider0.get(), fake_provider1.get()) ?
215           fake_provider0.get() : fake_provider1.get();
216   FakeAuthStatusProvider* provider1 =
217       provider0 == fake_provider0.get() ?
218           fake_provider1.get() : fake_provider0.get();
219 
220   provider0->SetAuthError(
221       kTestAccountId,
222       kTestUsername,
223       GoogleServiceAuthError(
224           GoogleServiceAuthError::NONE));
225   provider1->SetAuthError(
226       kOtherTestAccountId,
227       kOtherTestUsername,
228       GoogleServiceAuthError(
229           GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
230   ASSERT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
231             error_controller_->auth_error().state());
232   ASSERT_STREQ(kOtherTestAccountId,
233                error_controller_->error_account_id().c_str());
234 
235   // Change the 1st provider's error.
236   provider1->SetAuthError(
237       kOtherTestAccountId,
238       kOtherTestUsername,
239       GoogleServiceAuthError(
240           GoogleServiceAuthError::SERVICE_UNAVAILABLE));
241   ASSERT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
242             error_controller_->auth_error().state());
243   ASSERT_STREQ(kOtherTestAccountId,
244                error_controller_->error_account_id().c_str());
245 
246   // Set the 0th provider's error -- nothing should change.
247   provider0->SetAuthError(
248       kTestAccountId,
249       kTestUsername,
250       GoogleServiceAuthError(
251           GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE));
252   ASSERT_EQ(GoogleServiceAuthError::SERVICE_UNAVAILABLE,
253             error_controller_->auth_error().state());
254   ASSERT_STREQ(kOtherTestAccountId,
255                error_controller_->error_account_id().c_str());
256 
257   // Clear the 1st provider's error, so the 0th provider's error is used.
258   provider1->SetAuthError(
259       kOtherTestAccountId,
260       kOtherTestUsername,
261       GoogleServiceAuthError(
262           GoogleServiceAuthError::NONE));
263   ASSERT_EQ(GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE,
264             error_controller_->auth_error().state());
265   ASSERT_STREQ(kTestAccountId,
266                error_controller_->error_account_id().c_str());
267 
268   fake_provider0.reset();
269   fake_provider1.reset();
270   ASSERT_FALSE(error_controller_->HasError());
271 }
272