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