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