merge_session_helper_unittest.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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 <algorithm>
6#include <string>
7#include <vector>
8
9#include "base/memory/ref_counted.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/message_loop/message_loop.h"
12#include "base/strings/stringprintf.h"
13#include "google_apis/gaia/fake_oauth2_token_service.h"
14#include "google_apis/gaia/gaia_constants.h"
15#include "google_apis/gaia/merge_session_helper.h"
16#include "net/url_request/test_url_fetcher_factory.h"
17#include "net/url_request/url_request_test_util.h"
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace {
22
23class MockObserver : public MergeSessionHelper::Observer {
24 public:
25  explicit MockObserver(MergeSessionHelper* helper) : helper_(helper) {
26    helper_->AddObserver(this);
27  }
28
29  ~MockObserver() {
30    helper_->RemoveObserver(this);
31  }
32
33  MOCK_METHOD2(MergeSessionCompleted,
34               void(const std::string&,
35                    const GoogleServiceAuthError& ));
36 private:
37  MergeSessionHelper* helper_;
38
39  DISALLOW_COPY_AND_ASSIGN(MockObserver);
40};
41
42// Counts number of InstrumentedMergeSessionHelper created.
43// We can EXPECT_* to be zero at the end of our unit tests
44// to make sure everything is properly deleted.
45
46int total = 0;
47
48class InstrumentedMergeSessionHelper : public MergeSessionHelper {
49 public:
50  InstrumentedMergeSessionHelper(
51      OAuth2TokenService* token_service,
52      net::URLRequestContextGetter* request_context) :
53    MergeSessionHelper(token_service, request_context, NULL) {
54    total++;
55  }
56
57  virtual ~InstrumentedMergeSessionHelper() {
58    total--;
59  }
60
61  MOCK_METHOD0(StartFetching, void());
62  MOCK_METHOD0(StartLogOutUrlFetch, void());
63
64 private:
65  DISALLOW_COPY_AND_ASSIGN(InstrumentedMergeSessionHelper);
66};
67
68class MergeSessionHelperTest : public testing::Test {
69 public:
70   MergeSessionHelperTest()
71       : no_error_(GoogleServiceAuthError::NONE),
72         error_(GoogleServiceAuthError::SERVICE_ERROR),
73         canceled_(GoogleServiceAuthError::REQUEST_CANCELED),
74         request_context_getter_(new net::TestURLRequestContextGetter(
75             base::MessageLoopProxy::current())) {}
76
77  OAuth2TokenService* token_service() { return &token_service_; }
78  net::URLRequestContextGetter* request_context() {
79    return request_context_getter_;
80  }
81
82  void SimulateUbertokenFailure(UbertokenConsumer* consumer,
83                                const GoogleServiceAuthError& error) {
84    consumer->OnUbertokenFailure(error);
85  }
86
87  void SimulateMergeSessionSuccess(GaiaAuthConsumer* consumer,
88                                   const std::string& data) {
89    consumer->OnMergeSessionSuccess(data);
90  }
91
92  void SimulateMergeSessionFailure(GaiaAuthConsumer* consumer,
93                                   const GoogleServiceAuthError& error) {
94    consumer->OnMergeSessionFailure(error);
95  }
96
97  void SimulateLogoutSuccess(net::URLFetcherDelegate* consumer) {
98    consumer->OnURLFetchComplete(NULL);
99  }
100
101  void SimulateGetCheckConnctionInfoSuccess(
102      net::TestURLFetcher* fetcher,
103      const std::string& data) {
104    fetcher->set_status(net::URLRequestStatus());
105    fetcher->set_response_code(200);
106    fetcher->SetResponseString(data);
107    fetcher->delegate()->OnURLFetchComplete(fetcher);
108  }
109
110  void SimulateGetCheckConnctionInfoResult(
111      net::URLFetcher* fetcher,
112      const std::string& result) {
113    net::TestURLFetcher* test_fetcher =
114        static_cast<net::TestURLFetcher*>(fetcher);
115    test_fetcher->set_status(net::URLRequestStatus());
116    test_fetcher->set_response_code(200);
117    test_fetcher->SetResponseString(result);
118    test_fetcher->delegate()->OnURLFetchComplete(fetcher);
119  }
120
121  const GoogleServiceAuthError& no_error() { return no_error_; }
122  const GoogleServiceAuthError& error() { return error_; }
123  const GoogleServiceAuthError& canceled() { return canceled_; }
124
125  net::TestURLFetcherFactory* factory() { return &factory_; }
126
127 private:
128  base::MessageLoop message_loop_;
129  net::TestURLFetcherFactory factory_;
130  FakeOAuth2TokenService token_service_;
131  GoogleServiceAuthError no_error_;
132  GoogleServiceAuthError error_;
133  GoogleServiceAuthError canceled_;
134  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
135};
136
137} // namespace
138
139using ::testing::_;
140
141TEST_F(MergeSessionHelperTest, Success) {
142  InstrumentedMergeSessionHelper helper(token_service(), request_context());
143  MockObserver observer(&helper);
144
145  EXPECT_CALL(helper, StartFetching());
146  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", no_error()));
147
148  helper.LogIn("acc1@gmail.com");
149  SimulateMergeSessionSuccess(&helper, "token");
150}
151
152TEST_F(MergeSessionHelperTest, FailedMergeSession) {
153  InstrumentedMergeSessionHelper helper(token_service(), request_context());
154  MockObserver observer(&helper);
155
156  EXPECT_CALL(helper, StartFetching());
157  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", error()));
158
159  helper.LogIn("acc1@gmail.com");
160  SimulateMergeSessionFailure(&helper, error());
161}
162
163TEST_F(MergeSessionHelperTest, FailedUbertoken) {
164  InstrumentedMergeSessionHelper helper(token_service(), request_context());
165  MockObserver observer(&helper);
166
167  EXPECT_CALL(helper, StartFetching());
168  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", error()));
169
170  helper.LogIn("acc1@gmail.com");
171  SimulateUbertokenFailure(&helper, error());
172}
173
174TEST_F(MergeSessionHelperTest, ContinueAfterSuccess) {
175  InstrumentedMergeSessionHelper helper(token_service(), request_context());
176  MockObserver observer(&helper);
177
178  EXPECT_CALL(helper, StartFetching()).Times(2);
179  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", no_error()));
180  EXPECT_CALL(observer, MergeSessionCompleted("acc2@gmail.com", no_error()));
181
182  helper.LogIn("acc1@gmail.com");
183  helper.LogIn("acc2@gmail.com");
184  SimulateMergeSessionSuccess(&helper, "token1");
185  SimulateMergeSessionSuccess(&helper, "token2");
186}
187
188TEST_F(MergeSessionHelperTest, ContinueAfterFailure1) {
189  InstrumentedMergeSessionHelper helper(token_service(), request_context());
190  MockObserver observer(&helper);
191
192  EXPECT_CALL(helper, StartFetching()).Times(2);
193  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", error()));
194  EXPECT_CALL(observer, MergeSessionCompleted("acc2@gmail.com", no_error()));
195
196  helper.LogIn("acc1@gmail.com");
197  helper.LogIn("acc2@gmail.com");
198  SimulateMergeSessionFailure(&helper, error());
199  SimulateMergeSessionSuccess(&helper, "token2");
200}
201
202TEST_F(MergeSessionHelperTest, ContinueAfterFailure2) {
203  InstrumentedMergeSessionHelper helper(token_service(), request_context());
204  MockObserver observer(&helper);
205
206  EXPECT_CALL(helper, StartFetching()).Times(2);
207  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", error()));
208  EXPECT_CALL(observer, MergeSessionCompleted("acc2@gmail.com", no_error()));
209
210  helper.LogIn("acc1@gmail.com");
211  helper.LogIn("acc2@gmail.com");
212  SimulateUbertokenFailure(&helper, error());
213  SimulateMergeSessionSuccess(&helper, "token2");
214}
215
216TEST_F(MergeSessionHelperTest, AllRequestsInMultipleGoes) {
217  InstrumentedMergeSessionHelper helper(token_service(), request_context());
218  MockObserver observer(&helper);
219
220  EXPECT_CALL(helper, StartFetching()).Times(4);
221  EXPECT_CALL(observer, MergeSessionCompleted(_, no_error())).Times(4);
222
223  helper.LogIn("acc1@gmail.com");
224  helper.LogIn("acc2@gmail.com");
225
226  SimulateMergeSessionSuccess(&helper, "token1");
227
228  helper.LogIn("acc3@gmail.com");
229
230  SimulateMergeSessionSuccess(&helper, "token2");
231  SimulateMergeSessionSuccess(&helper, "token3");
232
233  helper.LogIn("acc4@gmail.com");
234
235  SimulateMergeSessionSuccess(&helper, "token4");
236}
237
238TEST_F(MergeSessionHelperTest, LogOut) {
239  InstrumentedMergeSessionHelper helper(token_service(), request_context());
240  MockObserver observer(&helper);
241
242  std::vector<std::string> current_accounts;
243  current_accounts.push_back("acc1@gmail.com");
244  current_accounts.push_back("acc2@gmail.com");
245  current_accounts.push_back("acc3@gmail.com");
246
247  EXPECT_CALL(helper, StartLogOutUrlFetch());
248  EXPECT_CALL(helper, StartFetching()).Times(2);
249  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", no_error()));
250  EXPECT_CALL(observer, MergeSessionCompleted("acc3@gmail.com", no_error()));
251
252  helper.LogOut("acc2@gmail.com", current_accounts);
253  SimulateLogoutSuccess(&helper);
254  SimulateMergeSessionSuccess(&helper, "token1");
255  SimulateMergeSessionSuccess(&helper, "token3");
256}
257
258TEST_F(MergeSessionHelperTest, PendingSigninThenSignout) {
259  InstrumentedMergeSessionHelper helper(token_service(), request_context());
260  MockObserver observer(&helper);
261
262  std::vector<std::string> current_accounts;
263  current_accounts.push_back("acc2@gmail.com");
264  current_accounts.push_back("acc3@gmail.com");
265
266  // From the first Signin.
267  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", no_error()));
268
269  // From the sign out and then re-sign in.
270  EXPECT_CALL(helper, StartLogOutUrlFetch());
271  EXPECT_CALL(observer, MergeSessionCompleted("acc3@gmail.com", no_error()));
272
273  // Total sign in 2 times, not enforcing ordered sequences.
274  EXPECT_CALL(helper, StartFetching()).Times(2);
275
276  helper.LogIn("acc1@gmail.com");
277  helper.LogOut("acc2@gmail.com", current_accounts);
278
279  SimulateMergeSessionSuccess(&helper, "token1");
280  SimulateLogoutSuccess(&helper);
281  SimulateMergeSessionSuccess(&helper, "token3");
282}
283
284TEST_F(MergeSessionHelperTest, CancelSignIn) {
285  InstrumentedMergeSessionHelper helper(token_service(), request_context());
286  MockObserver observer(&helper);
287
288  std::vector<std::string> current_accounts;
289
290  EXPECT_CALL(helper, StartFetching());
291  EXPECT_CALL(observer, MergeSessionCompleted("acc2@gmail.com", canceled()));
292  EXPECT_CALL(observer, MergeSessionCompleted("acc1@gmail.com", no_error()));
293  EXPECT_CALL(helper, StartLogOutUrlFetch());
294
295  helper.LogIn("acc1@gmail.com");
296  helper.LogIn("acc2@gmail.com");
297  helper.LogOut("acc2@gmail.com", current_accounts);
298
299  SimulateMergeSessionSuccess(&helper, "token1");
300  SimulateLogoutSuccess(&helper);
301}
302
303TEST_F(MergeSessionHelperTest, DoubleSignout) {
304  InstrumentedMergeSessionHelper helper(token_service(), request_context());
305  MockObserver observer(&helper);
306
307  std::vector<std::string> current_accounts1;
308  current_accounts1.push_back("acc1@gmail.com");
309  current_accounts1.push_back("acc2@gmail.com");
310  current_accounts1.push_back("acc3@gmail.com");
311
312  std::vector<std::string> current_accounts2;
313  current_accounts2.push_back("acc1@gmail.com");
314  current_accounts2.push_back("acc3@gmail.com");
315
316  EXPECT_CALL(helper, StartFetching()).Times(2);
317  EXPECT_CALL(observer, MergeSessionCompleted("acc3@gmail.com", canceled()));
318  EXPECT_CALL(observer,
319      MergeSessionCompleted("acc1@gmail.com", no_error())).Times(2);
320  EXPECT_CALL(helper, StartLogOutUrlFetch());
321
322  helper.LogIn("acc1@gmail.com");
323  helper.LogOut("acc2@gmail.com", current_accounts1);
324  helper.LogOut("acc3@gmail.com", current_accounts2);
325
326  SimulateMergeSessionSuccess(&helper, "token1");
327  SimulateLogoutSuccess(&helper);
328  SimulateMergeSessionSuccess(&helper, "token1");
329}
330
331TEST_F(MergeSessionHelperTest, ExternalCcResultFetcher) {
332  InstrumentedMergeSessionHelper helper(token_service(), request_context());
333  MergeSessionHelper::ExternalCcResultFetcher result_fetcher(&helper);
334  result_fetcher.Start();
335
336  // Simulate a successful completion of GetCheckConnctionInfo.
337  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
338  ASSERT_TRUE(NULL != fetcher);
339  SimulateGetCheckConnctionInfoSuccess(fetcher,
340      "[{\"carryBackToken\": \"yt\", \"url\": \"http://www.yt.com\"},"
341      " {\"carryBackToken\": \"bl\", \"url\": \"http://www.bl.com\"}]");
342
343  // Simulate responses for the two connection URLs.
344  MergeSessionHelper::ExternalCcResultFetcher::URLToTokenAndFetcher fetchers =
345      result_fetcher.get_fetcher_map_for_testing();
346  ASSERT_EQ(2u, fetchers.size());
347  ASSERT_EQ(1u, fetchers.count(GURL("http://www.yt.com")));
348  ASSERT_EQ(1u, fetchers.count(GURL("http://www.bl.com")));
349
350  ASSERT_EQ("bl:null,yt:null", result_fetcher.GetExternalCcResult());
351  SimulateGetCheckConnctionInfoResult(
352      fetchers[GURL("http://www.yt.com")].second, "yt_result");
353  ASSERT_EQ("bl:null,yt:yt_result", result_fetcher.GetExternalCcResult());
354  SimulateGetCheckConnctionInfoResult(
355      fetchers[GURL("http://www.bl.com")].second, "bl_result");
356  ASSERT_EQ("bl:bl_result,yt:yt_result", result_fetcher.GetExternalCcResult());
357}
358
359TEST_F(MergeSessionHelperTest, ExternalCcResultFetcherTimeout) {
360  InstrumentedMergeSessionHelper helper(token_service(), request_context());
361  MergeSessionHelper::ExternalCcResultFetcher result_fetcher(&helper);
362  result_fetcher.Start();
363
364  // Simulate a successful completion of GetCheckConnctionInfo.
365  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
366  ASSERT_TRUE(NULL != fetcher);
367  SimulateGetCheckConnctionInfoSuccess(fetcher,
368      "[{\"carryBackToken\": \"yt\", \"url\": \"http://www.yt.com\"},"
369      " {\"carryBackToken\": \"bl\", \"url\": \"http://www.bl.com\"}]");
370
371  MergeSessionHelper::ExternalCcResultFetcher::URLToTokenAndFetcher fetchers =
372      result_fetcher.get_fetcher_map_for_testing();
373  ASSERT_EQ(2u, fetchers.size());
374  ASSERT_EQ(1u, fetchers.count(GURL("http://www.yt.com")));
375  ASSERT_EQ(1u, fetchers.count(GURL("http://www.bl.com")));
376
377  // Simulate response only for "yt".
378  ASSERT_EQ("bl:null,yt:null", result_fetcher.GetExternalCcResult());
379  SimulateGetCheckConnctionInfoResult(
380      fetchers[GURL("http://www.yt.com")].second, "yt_result");
381  ASSERT_EQ("bl:null,yt:yt_result", result_fetcher.GetExternalCcResult());
382
383  // Now timeout.
384  result_fetcher.TimeoutForTests();
385  ASSERT_EQ("bl:null,yt:yt_result", result_fetcher.GetExternalCcResult());
386  fetchers = result_fetcher.get_fetcher_map_for_testing();
387  ASSERT_EQ(0u, fetchers.size());
388}
389
390TEST_F(MergeSessionHelperTest, ExternalCcResultFetcherTruncate) {
391  InstrumentedMergeSessionHelper helper(token_service(), request_context());
392  MergeSessionHelper::ExternalCcResultFetcher result_fetcher(&helper);
393  result_fetcher.Start();
394
395  // Simulate a successful completion of GetCheckConnctionInfo.
396  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
397  ASSERT_TRUE(NULL != fetcher);
398  SimulateGetCheckConnctionInfoSuccess(fetcher,
399      "[{\"carryBackToken\": \"yt\", \"url\": \"http://www.yt.com\"}]");
400
401  MergeSessionHelper::ExternalCcResultFetcher::URLToTokenAndFetcher fetchers =
402      result_fetcher.get_fetcher_map_for_testing();
403  ASSERT_EQ(1u, fetchers.size());
404  ASSERT_EQ(1u, fetchers.count(GURL("http://www.yt.com")));
405
406  // Simulate response for "yt" with a string that is too long.
407  SimulateGetCheckConnctionInfoResult(
408      fetchers[GURL("http://www.yt.com")].second, "1234567890123456trunc");
409  ASSERT_EQ("yt:1234567890123456", result_fetcher.GetExternalCcResult());
410}
411