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 "base/run_loop.h"
6#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
7#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
8#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
9#include "chrome/test/base/testing_profile.h"
10#include "components/gcm_driver/fake_gcm_driver.h"
11#include "components/gcm_driver/gcm_driver.h"
12#include "components/invalidation/gcm_invalidation_bridge.h"
13#include "content/public/test/test_browser_thread_bundle.h"
14#include "google_apis/gaia/fake_identity_provider.h"
15#include "google_apis/gaia/google_service_auth_error.h"
16#include "net/base/ip_endpoint.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace invalidation {
20namespace {
21
22// Implementation of GCMDriver::Register that always succeeds with the same
23// registrationId.
24class CustomFakeGCMDriver : public gcm::FakeGCMDriver {
25 public:
26  CustomFakeGCMDriver() {}
27  virtual ~CustomFakeGCMDriver() {}
28
29 protected:
30  // FakeGCMDriver override:
31  virtual void RegisterImpl(
32      const std::string& app_id,
33      const std::vector<std::string>& sender_ids) OVERRIDE {
34    base::MessageLoop::current()->PostTask(
35        FROM_HERE,
36        base::Bind(&CustomFakeGCMDriver::RegisterFinished,
37                   base::Unretained(this),
38                   app_id,
39                   std::string("registration.id"),
40                   gcm::GCMClient::SUCCESS));
41  }
42
43 private:
44  DISALLOW_COPY_AND_ASSIGN(CustomFakeGCMDriver);
45};
46
47class GCMInvalidationBridgeTest : public ::testing::Test {
48 protected:
49  GCMInvalidationBridgeTest()
50      : connection_online_(false) {}
51
52  virtual ~GCMInvalidationBridgeTest() {}
53
54  virtual void SetUp() OVERRIDE {
55    TestingProfile::Builder builder;
56    builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(),
57                              &BuildAutoIssuingFakeProfileOAuth2TokenService);
58    profile_ = builder.Build();
59
60    FakeProfileOAuth2TokenService* token_service =
61        (FakeProfileOAuth2TokenService*)
62        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
63    token_service->IssueRefreshTokenForUser("", "fake_refresh_token");
64    gcm_driver_.reset(new CustomFakeGCMDriver());
65
66    identity_provider_.reset(new FakeIdentityProvider(token_service));
67    bridge_.reset(new GCMInvalidationBridge(gcm_driver_.get(),
68                                            identity_provider_.get()));
69
70    delegate_ = bridge_->CreateDelegate();
71    delegate_->Initialize(
72        base::Bind(&GCMInvalidationBridgeTest::ConnectionStateChanged,
73                   base::Unretained(this)));
74    RunLoop();
75  }
76
77  void RunLoop() {
78    base::RunLoop run_loop;
79    run_loop.RunUntilIdle();
80  }
81
82 public:
83  void RegisterFinished(const std::string& registration_id,
84                        gcm::GCMClient::Result result) {
85    registration_id_ = registration_id;
86  }
87
88  void RequestTokenFinished(const GoogleServiceAuthError& error,
89                            const std::string& token) {
90    issued_tokens_.push_back(token);
91    request_token_errors_.push_back(error);
92  }
93
94  void ConnectionStateChanged(bool online) {
95    connection_online_ = online;
96  }
97
98  content::TestBrowserThreadBundle thread_bundle_;
99  scoped_ptr<Profile> profile_;
100  scoped_ptr<gcm::GCMDriver> gcm_driver_;
101  scoped_ptr<FakeIdentityProvider> identity_provider_;
102
103  std::vector<std::string> issued_tokens_;
104  std::vector<GoogleServiceAuthError> request_token_errors_;
105  std::string registration_id_;
106  bool connection_online_;
107
108  scoped_ptr<GCMInvalidationBridge> bridge_;
109  scoped_ptr<syncer::GCMNetworkChannelDelegate> delegate_;
110};
111
112TEST_F(GCMInvalidationBridgeTest, RequestToken) {
113  // Make sure that call to RequestToken reaches OAuth2TokenService and gets
114  // back to callback.
115  delegate_->RequestToken(
116      base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished,
117                 base::Unretained(this)));
118  RunLoop();
119  EXPECT_EQ(1U, issued_tokens_.size());
120  EXPECT_NE("", issued_tokens_[0]);
121  EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), request_token_errors_[0]);
122}
123
124TEST_F(GCMInvalidationBridgeTest, RequestTokenTwoConcurrentRequests) {
125  // First call should finish with REQUEST_CANCELLED error.
126  delegate_->RequestToken(
127      base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished,
128                 base::Unretained(this)));
129  // Second request should succeed.
130  delegate_->RequestToken(
131      base::Bind(&GCMInvalidationBridgeTest::RequestTokenFinished,
132                 base::Unretained(this)));
133  RunLoop();
134
135  EXPECT_EQ(2U, issued_tokens_.size());
136
137  EXPECT_EQ("", issued_tokens_[0]);
138  EXPECT_EQ(GoogleServiceAuthError::REQUEST_CANCELED,
139            request_token_errors_[0].state());
140
141  EXPECT_NE("", issued_tokens_[1]);
142  EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(), request_token_errors_[1]);
143}
144
145TEST_F(GCMInvalidationBridgeTest, Register) {
146  EXPECT_TRUE(registration_id_.empty());
147  delegate_->Register(base::Bind(&GCMInvalidationBridgeTest::RegisterFinished,
148                                 base::Unretained(this)));
149  RunLoop();
150
151  EXPECT_FALSE(registration_id_.empty());
152}
153
154TEST_F(GCMInvalidationBridgeTest, ConnectionState) {
155  EXPECT_FALSE(connection_online_);
156  bridge_->OnConnected(net::IPEndPoint());
157  RunLoop();
158  EXPECT_TRUE(connection_online_);
159  bridge_->OnDisconnected();
160  RunLoop();
161  EXPECT_FALSE(connection_online_);
162}
163
164}  // namespace
165}  // namespace invalidation
166