1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/scoped_ptr.h"
#include "base/scoped_temp_dir.h"
#include "base/test/test_file_util.h"
#include "base/waitable_event.h"
#include "chrome/browser/sync/engine/all_status.h"
#include "chrome/browser/sync/engine/auth_watcher.h"
#include "chrome/browser/sync/engine/net/gaia_authenticator.h"
#include "chrome/browser/sync/engine/net/http_return.h"
#include "chrome/browser/sync/notifier/listener/talk_mediator_impl.h"
#include "chrome/browser/sync/util/user_settings.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
#include "chrome/test/sync/engine/mock_server_connection.h"
#include "chrome/test/sync/engine/test_directory_setter_upper.h"
#include "testing/gtest/include/gtest/gtest.h"
static FilePath::CharType kUserSettingsDB[] =
FILE_PATH_LITERAL("Settings.sqlite3");
static const char* kTestUserAgent = "useragent";
static const char* kTestServiceId = "serviceid";
static const char* kTestGaiaURL = "http://gaia_url";
static const char* kUserDisplayName = "Mr. Auth Watcher";
static const char* kUserDisplayEmail = "authwatcherdisplay@gmail.com";
static const char* kTestEmail = "authwatchertest@gmail.com";
static const char* kWrongPassword = "wrongpassword";
static const char* kCorrectPassword = "correctpassword";
static const char* kValidSID = "validSID";
static const char* kValidLSID = "validLSID";
static const char* kInvalidAuthToken = "invalidAuthToken";
static const char* kValidAuthToken = "validAuthToken";
namespace browser_sync {
class GaiaAuthMockForAuthWatcher : public browser_sync::GaiaAuthenticator {
public:
GaiaAuthMockForAuthWatcher() : browser_sync::GaiaAuthenticator(
kTestUserAgent, kTestServiceId, kTestGaiaURL),
use_bad_auth_token_(false) {}
virtual ~GaiaAuthMockForAuthWatcher() {}
void SendBadAuthTokenForNextRequest() { use_bad_auth_token_ = true; }
std::string renewed_token() {
return renewed_token_;
}
protected:
bool PerformGaiaRequest(const AuthParams& params, AuthResults* results) {
if (params.password == kWrongPassword) {
results->auth_error = browser_sync::BadAuthentication;
return false;
}
if (params.password == kCorrectPassword) {
results->sid = kValidSID;
results->lsid = kValidLSID;
results->auth_token = kValidAuthToken;
}
if (use_bad_auth_token_) {
results->auth_token = kInvalidAuthToken;
use_bad_auth_token_ = false;
}
return true;
}
bool LookupEmail(AuthResults* results) {
results->signin = GMAIL_SIGNIN;
return true;
}
void RenewAuthToken(const std::string& auth_token) {
renewed_token_ = auth_token;
}
private:
// Whether we should send an invalid auth token on the next request.
bool use_bad_auth_token_;
std::string renewed_token_;
};
class AuthWatcherTest : public testing::Test {
public:
AuthWatcherTest() : metadb_(kUserDisplayEmail),
consumer_ready(false, false),
event_produced(false, false) {}
virtual void SetUp() {
metadb_.SetUp();
connection_.reset(new MockConnectionManager(metadb_.manager(),
metadb_.name()));
// Mock out data that would normally be sent back from a server.
connection()->SetAuthenticationResponseInfo(kValidAuthToken,
kUserDisplayName, kUserDisplayEmail, "ID");
allstatus_.reset(new AllStatus());
user_settings_.reset(new UserSettings());
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
FilePath user_settings_path = temp_dir_.path().Append(kUserSettingsDB);
user_settings_->Init(user_settings_path);
gaia_auth_ = new GaiaAuthMockForAuthWatcher();
talk_mediator_.reset(new TalkMediatorImpl(
browser_sync::kDefaultNotificationMethod));
auth_watcher_ = new AuthWatcher(metadb_.manager(), connection_.get(),
allstatus_.get(), kTestUserAgent, kTestServiceId, kTestGaiaURL,
user_settings_.get(), gaia_auth_, talk_mediator_.get());
authwatcher_hookup_.reset(NewEventListenerHookup(auth_watcher_->channel(),
this, &AuthWatcherTest::HandleAuthWatcherEvent));
}
virtual void TearDown() {
metadb_.TearDown();
auth_watcher_->Shutdown();
EXPECT_FALSE(auth_watcher()->message_loop());
}
void HandleAuthWatcherEvent(const AuthWatcherEvent& event) {
if (event.what_happened == AuthWatcherEvent::AUTHWATCHER_DESTROYED)
return;
consumer_ready.Wait(); // Block progress until the test is ready.
last_event_reason_ = event.what_happened;
if (event.what_happened == AuthWatcherEvent::AUTH_SUCCEEDED)
user_email_ = event.user_email;
event_produced.Signal();
}
AuthWatcherEvent::WhatHappened ConsumeNextEvent() {
consumer_ready.Signal();
event_produced.Wait();
return last_event_reason_;
}
AuthWatcher* auth_watcher() { return auth_watcher_.get(); }
MockConnectionManager* connection() { return connection_.get(); }
GaiaAuthMockForAuthWatcher* gaia_auth() { return gaia_auth_; }
const std::string& user_email() { return user_email_; }
private:
// Responsible for creating / deleting a temp dir containing user settings DB.
ScopedTempDir temp_dir_;
// The event listener hookup registered for HandleAuthWatcherEvent.
scoped_ptr<EventListenerHookup> authwatcher_hookup_;
// The sync engine pieces necessary to run an AuthWatcher.
TriggeredOpenTestDirectorySetterUpper metadb_;
scoped_ptr<MockConnectionManager> connection_;
scoped_ptr<AllStatus> allstatus_;
scoped_ptr<UserSettings> user_settings_;
GaiaAuthMockForAuthWatcher* gaia_auth_; // Owned by auth_watcher_.
scoped_ptr<TalkMediator> talk_mediator_;
scoped_refptr<AuthWatcher> auth_watcher_;
// This is used to block the AuthWatcherThread when it raises events until we
// are ready to read the event. It is not a manual-reset event, so it goes
// straight back to non-signaled after one thread (the main thread) is
// signaled (or "consumes" the signaled state).
base::WaitableEvent consumer_ready;
// This is signaled by the AuthWatcherThread after it sets last_event_reason_
// and possibly user_email_ for us to read.
base::WaitableEvent event_produced;
// The 'WhatHappened' value from the last AuthWatcherEvent we handled.
AuthWatcherEvent::WhatHappened last_event_reason_;
// Set when we receive an AUTH_SUCCEEDED event.
std::string user_email_;
DISALLOW_COPY_AND_ASSIGN(AuthWatcherTest);
};
TEST_F(AuthWatcherTest, Construction) {
EXPECT_TRUE(auth_watcher()->message_loop());
EXPECT_EQ("SyncEngine_AuthWatcherThread",
auth_watcher()->message_loop()->thread_name());
EXPECT_TRUE(auth_watcher()->auth_backend_thread_.IsRunning());
EXPECT_EQ(AuthWatcher::NOT_AUTHENTICATED, auth_watcher()->status());
}
TEST_F(AuthWatcherTest, AuthenticateGaiaAuthFailure) {
auth_watcher()->Authenticate(kTestEmail, kWrongPassword,
std::string(), // captcha_token
std::string(), // captcha_value
false); // persist_creds_to_disk
EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
EXPECT_EQ(AuthWatcherEvent::GAIA_AUTH_FAILED, ConsumeNextEvent());
}
TEST_F(AuthWatcherTest, AuthenticateBadAuthToken) {
gaia_auth()->SendBadAuthTokenForNextRequest();
auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(),
std::string(), false);
EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
EXPECT_EQ(AuthWatcherEvent::SERVICE_AUTH_FAILED, ConsumeNextEvent());
}
TEST_F(AuthWatcherTest, AuthenticateSuccess) {
auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(),
std::string(), false);
EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent());
// The server responds with a different email than what we used in the call
// to Authenticate, and the AuthWatcher should have told us about.
EXPECT_EQ(kUserDisplayEmail, user_email());
}
TEST_F(AuthWatcherTest, AuthenticateWithTokenBadAuthToken) {
auth_watcher()->AuthenticateWithToken(kTestEmail, kInvalidAuthToken);
EXPECT_EQ(AuthWatcherEvent::SERVICE_AUTH_FAILED, ConsumeNextEvent());
}
TEST_F(AuthWatcherTest, AuthenticateWithTokenSuccess) {
auth_watcher()->AuthenticateWithToken(kTestEmail, kValidAuthToken);
EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent());
EXPECT_EQ(kUserDisplayEmail, user_email());
}
// Just check that the thread task was properly issued.
TEST_F(AuthWatcherTest, RenewAuthToken) {
auth_watcher()->Authenticate(kTestEmail, kCorrectPassword, std::string(),
std::string(), false);
EXPECT_EQ(AuthWatcherEvent::AUTHENTICATION_ATTEMPT_START, ConsumeNextEvent());
EXPECT_EQ(AuthWatcherEvent::AUTH_SUCCEEDED, ConsumeNextEvent());
auth_watcher()->RenewAuthToken("updated_token");
EXPECT_EQ(AuthWatcherEvent::AUTH_RENEWED, ConsumeNextEvent());
EXPECT_EQ(gaia_auth()->renewed_token(), "updated_token");
EXPECT_EQ(connection()->auth_token(), "updated_token");
}
} // namespace browser_sync
|