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 "chrome/browser/services/gcm/gcm_profile_service.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/run_loop.h"
14#include "chrome/browser/services/gcm/fake_signin_manager.h"
15#include "chrome/browser/services/gcm/gcm_profile_service_factory.h"
16#include "chrome/browser/signin/signin_manager_factory.h"
17#include "chrome/test/base/testing_profile.h"
18#if defined(OS_CHROMEOS)
19#include "chromeos/dbus/dbus_thread_manager.h"
20#endif
21#include "components/gcm_driver/fake_gcm_app_handler.h"
22#include "components/gcm_driver/fake_gcm_client.h"
23#include "components/gcm_driver/fake_gcm_client_factory.h"
24#include "components/gcm_driver/gcm_client.h"
25#include "components/gcm_driver/gcm_client_factory.h"
26#include "components/gcm_driver/gcm_driver.h"
27#include "components/pref_registry/pref_registry_syncable.h"
28#include "content/public/browser/browser_context.h"
29#include "content/public/browser/browser_thread.h"
30#include "content/public/test/test_browser_thread_bundle.h"
31#include "testing/gtest/include/gtest/gtest.h"
32
33namespace gcm {
34
35namespace {
36
37const char kTestAccountID[] = "user@example.com";
38const char kTestAppID[] = "TestApp";
39const char kUserID[] = "user";
40
41KeyedService* BuildGCMProfileService(content::BrowserContext* context) {
42  return new GCMProfileService(
43      Profile::FromBrowserContext(context),
44      scoped_ptr<GCMClientFactory>(new FakeGCMClientFactory(
45          FakeGCMClient::NO_DELAY_START,
46          content::BrowserThread::GetMessageLoopProxyForThread(
47              content::BrowserThread::UI),
48          content::BrowserThread::GetMessageLoopProxyForThread(
49              content::BrowserThread::IO))));
50}
51
52}  // namespace
53
54class GCMProfileServiceTest : public testing::Test {
55 protected:
56  GCMProfileServiceTest();
57  virtual ~GCMProfileServiceTest();
58
59  // testing::Test:
60  virtual void SetUp() OVERRIDE;
61  virtual void TearDown() OVERRIDE;
62
63  FakeGCMClient* GetGCMClient() const;
64
65  void CreateGCMProfileService();
66  void SignIn();
67  void SignOut();
68
69  void RegisterAndWaitForCompletion(const std::vector<std::string>& sender_ids);
70  void UnregisterAndWaitForCompletion();
71  void SendAndWaitForCompletion(const GCMClient::OutgoingMessage& message);
72
73  void RegisterCompleted(const base::Closure& callback,
74                         const std::string& registration_id,
75                         GCMClient::Result result);
76  void UnregisterCompleted(const base::Closure& callback,
77                           GCMClient::Result result);
78  void SendCompleted(const base::Closure& callback,
79                     const std::string& message_id,
80                     GCMClient::Result result);
81
82  GCMDriver* driver() const { return gcm_profile_service_->driver(); }
83  std::string registration_id() const { return registration_id_; }
84  GCMClient::Result registration_result() const { return registration_result_; }
85  GCMClient::Result unregistration_result() const {
86    return unregistration_result_;
87  }
88  std::string send_message_id() const { return send_message_id_; }
89  GCMClient::Result send_result() const { return send_result_; }
90
91 private:
92  content::TestBrowserThreadBundle thread_bundle_;
93  scoped_ptr<TestingProfile> profile_;
94  GCMProfileService* gcm_profile_service_;
95  scoped_ptr<FakeGCMAppHandler> gcm_app_handler_;
96
97  std::string registration_id_;
98  GCMClient::Result registration_result_;
99  GCMClient::Result unregistration_result_;
100  std::string send_message_id_;
101  GCMClient::Result send_result_;
102
103  DISALLOW_COPY_AND_ASSIGN(GCMProfileServiceTest);
104};
105
106GCMProfileServiceTest::GCMProfileServiceTest()
107    : gcm_profile_service_(NULL),
108      gcm_app_handler_(new FakeGCMAppHandler),
109      registration_result_(GCMClient::UNKNOWN_ERROR),
110      send_result_(GCMClient::UNKNOWN_ERROR) {
111}
112
113GCMProfileServiceTest::~GCMProfileServiceTest() {
114}
115
116FakeGCMClient* GCMProfileServiceTest::GetGCMClient() const {
117  return static_cast<FakeGCMClient*>(
118      gcm_profile_service_->driver()->GetGCMClientForTesting());
119}
120
121void GCMProfileServiceTest::SetUp() {
122#if defined(OS_CHROMEOS)
123  // Create a DBus thread manager setter for its side effect.
124  // Ignore the return value.
125  chromeos::DBusThreadManager::GetSetterForTesting();
126#endif
127  TestingProfile::Builder builder;
128  builder.AddTestingFactory(SigninManagerFactory::GetInstance(),
129                            FakeSigninManager::Build);
130  profile_ = builder.Build();
131}
132
133void GCMProfileServiceTest::TearDown() {
134  gcm_profile_service_->driver()->RemoveAppHandler(kTestAppID);
135}
136
137void GCMProfileServiceTest::CreateGCMProfileService() {
138  gcm_profile_service_ = static_cast<GCMProfileService*>(
139      GCMProfileServiceFactory::GetInstance()->SetTestingFactoryAndUse(
140          profile_.get(),
141          &BuildGCMProfileService));
142  gcm_profile_service_->driver()->AddAppHandler(
143      kTestAppID, gcm_app_handler_.get());
144}
145
146void GCMProfileServiceTest::SignIn() {
147  FakeSigninManager* signin_manager = static_cast<FakeSigninManager*>(
148      SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
149  signin_manager->SignIn(kTestAccountID);
150  base::RunLoop().RunUntilIdle();
151}
152
153void GCMProfileServiceTest::SignOut() {
154  FakeSigninManager* signin_manager = static_cast<FakeSigninManager*>(
155      SigninManagerFactory::GetInstance()->GetForProfile(profile_.get()));
156  signin_manager->SignOut(signin_metrics::SIGNOUT_TEST);
157  base::RunLoop().RunUntilIdle();
158}
159
160void GCMProfileServiceTest::RegisterAndWaitForCompletion(
161    const std::vector<std::string>& sender_ids) {
162  base::RunLoop run_loop;
163  gcm_profile_service_->driver()->Register(
164      kTestAppID,
165      sender_ids,
166      base::Bind(&GCMProfileServiceTest::RegisterCompleted,
167                 base::Unretained(this),
168                 run_loop.QuitClosure()));
169  run_loop.Run();
170}
171
172void GCMProfileServiceTest::UnregisterAndWaitForCompletion() {
173  base::RunLoop run_loop;
174  gcm_profile_service_->driver()->Unregister(
175      kTestAppID,
176      base::Bind(&GCMProfileServiceTest::UnregisterCompleted,
177                 base::Unretained(this),
178                 run_loop.QuitClosure()));
179  run_loop.Run();
180}
181
182void GCMProfileServiceTest::SendAndWaitForCompletion(
183    const GCMClient::OutgoingMessage& message) {
184  base::RunLoop run_loop;
185  gcm_profile_service_->driver()->Send(
186      kTestAppID,
187      kUserID,
188      message,
189      base::Bind(&GCMProfileServiceTest::SendCompleted,
190                 base::Unretained(this),
191                 run_loop.QuitClosure()));
192  run_loop.Run();
193}
194
195void GCMProfileServiceTest::RegisterCompleted(
196     const base::Closure& callback,
197     const std::string& registration_id,
198     GCMClient::Result result) {
199  registration_id_ = registration_id;
200  registration_result_ = result;
201  callback.Run();
202}
203
204void GCMProfileServiceTest::UnregisterCompleted(
205    const base::Closure& callback,
206    GCMClient::Result result) {
207  unregistration_result_ = result;
208  callback.Run();
209}
210
211void GCMProfileServiceTest::SendCompleted(
212    const base::Closure& callback,
213    const std::string& message_id,
214    GCMClient::Result result) {
215  send_message_id_ = message_id;
216  send_result_ = result;
217  callback.Run();
218}
219
220TEST_F(GCMProfileServiceTest, CreateGCMProfileServiceBeforeSignIn) {
221  CreateGCMProfileService();
222  EXPECT_FALSE(driver()->IsStarted());
223
224  SignIn();
225  EXPECT_TRUE(driver()->IsStarted());
226}
227
228TEST_F(GCMProfileServiceTest, CreateGCMProfileServiceAfterSignIn) {
229  SignIn();
230  // Note that we can't check if GCM is started or not since the
231  // GCMProfileService that hosts the GCMDriver is not created yet.
232
233  CreateGCMProfileService();
234  EXPECT_TRUE(driver()->IsStarted());
235}
236
237TEST_F(GCMProfileServiceTest, SignInAgain) {
238  CreateGCMProfileService();
239  SignIn();
240  EXPECT_TRUE(driver()->IsStarted());
241
242  SignOut();
243  EXPECT_FALSE(driver()->IsStarted());
244
245  SignIn();
246  EXPECT_TRUE(driver()->IsStarted());
247}
248
249TEST_F(GCMProfileServiceTest, RegisterAndUnregister) {
250  CreateGCMProfileService();
251  SignIn();
252
253  std::vector<std::string> sender_ids;
254  sender_ids.push_back("sender");
255  RegisterAndWaitForCompletion(sender_ids);
256
257  std::string expected_registration_id =
258      GetGCMClient()->GetRegistrationIdFromSenderIds(sender_ids);
259  EXPECT_EQ(expected_registration_id, registration_id());
260  EXPECT_EQ(GCMClient::SUCCESS, registration_result());
261
262  UnregisterAndWaitForCompletion();
263  EXPECT_EQ(GCMClient::SUCCESS, unregistration_result());
264}
265
266TEST_F(GCMProfileServiceTest, Send) {
267  CreateGCMProfileService();
268  SignIn();
269
270  GCMClient::OutgoingMessage message;
271  message.id = "1";
272  message.data["key1"] = "value1";
273  SendAndWaitForCompletion( message);
274
275  EXPECT_EQ(message.id, send_message_id());
276  EXPECT_EQ(GCMClient::SUCCESS, send_result());
277}
278
279}  // namespace gcm
280