1// Copyright (c) 2013 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 <string>
6
7#include <vector>
8
9#include "base/guid.h"
10#include "base/message_loop/message_loop.h"
11#include "base/prefs/pref_service.h"
12#include "base/values.h"
13#include "chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h"
14#include "chrome/browser/extensions/extension_api_unittest.h"
15#include "chrome/browser/extensions/test_extension_prefs.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/sync/profile_sync_service_factory.h"
18#include "chrome/browser/sync/profile_sync_service_mock.h"
19#include "chrome/common/pref_names.h"
20#include "components/sync_driver/device_info.h"
21#include "extensions/common/extension.h"
22#include "testing/gmock/include/gmock/gmock.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
25using sync_driver::DeviceInfo;
26using sync_driver::DeviceInfoTracker;
27using testing::Return;
28
29namespace extensions {
30
31class MockDeviceInfoTracker : public DeviceInfoTracker {
32 public:
33  virtual ~MockDeviceInfoTracker() {}
34
35  virtual scoped_ptr<DeviceInfo> GetDeviceInfo(
36      const std::string& client_id) const OVERRIDE {
37    NOTREACHED();
38    return scoped_ptr<DeviceInfo>();
39  }
40
41  static DeviceInfo* CloneDeviceInfo(const DeviceInfo* device_info) {
42    return new DeviceInfo(device_info->guid(),
43                          device_info->client_name(),
44                          device_info->chrome_version(),
45                          device_info->sync_user_agent(),
46                          device_info->device_type(),
47                          device_info->signin_scoped_device_id());
48  }
49
50  virtual ScopedVector<DeviceInfo> GetAllDeviceInfo() const OVERRIDE {
51    ScopedVector<DeviceInfo> list;
52
53    for (std::vector<const DeviceInfo*>::const_iterator iter = devices_.begin();
54         iter != devices_.end();
55         ++iter) {
56      list.push_back(CloneDeviceInfo(*iter));
57    }
58
59    return list.Pass();
60  }
61
62  virtual void AddObserver(Observer* observer) OVERRIDE { NOTREACHED(); }
63
64  virtual void RemoveObserver(Observer* observer) OVERRIDE { NOTREACHED(); }
65
66  void Add(const DeviceInfo* device) { devices_.push_back(device); }
67
68 private:
69  // DeviceInfo stored here are not owned.
70  std::vector<const DeviceInfo*> devices_;
71};
72
73TEST(SignedInDevicesAPITest, GetSignedInDevices) {
74  TestingProfile profile;
75  MockDeviceInfoTracker device_tracker;
76  base::MessageLoop message_loop_;
77  TestExtensionPrefs extension_prefs(
78      message_loop_.message_loop_proxy().get());
79
80  // Add a couple of devices and make sure we get back public ids for them.
81  std::string extension_name = "test";
82  scoped_refptr<Extension> extension_test =
83      extension_prefs.AddExtension(extension_name);
84
85  DeviceInfo device_info1(base::GenerateGUID(),
86                          "abc Device",
87                          "XYZ v1",
88                          "XYZ SyncAgent v1",
89                          sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
90                          "device_id");
91
92  DeviceInfo device_info2(base::GenerateGUID(),
93                          "def Device",
94                          "XYZ v2",
95                          "XYZ SyncAgent v2",
96                          sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
97                          "device_id");
98
99  device_tracker.Add(&device_info1);
100  device_tracker.Add(&device_info2);
101
102  ScopedVector<DeviceInfo> output1 = GetAllSignedInDevices(
103      extension_test.get()->id(), &device_tracker, extension_prefs.prefs());
104
105  std::string public_id1 = output1[0]->public_id();
106  std::string public_id2 = output1[1]->public_id();
107
108  EXPECT_FALSE(public_id1.empty());
109  EXPECT_FALSE(public_id2.empty());
110  EXPECT_NE(public_id1, public_id2);
111
112  // Add a third device and make sure the first 2 ids are retained and a new
113  // id is generated for the third device.
114  DeviceInfo device_info3(base::GenerateGUID(),
115                          "def Device",
116                          "jkl v2",
117                          "XYZ SyncAgent v2",
118                          sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
119                          "device_id");
120
121  device_tracker.Add(&device_info3);
122
123  ScopedVector<DeviceInfo> output2 = GetAllSignedInDevices(
124      extension_test.get()->id(), &device_tracker, extension_prefs.prefs());
125
126  EXPECT_EQ(output2[0]->public_id(), public_id1);
127  EXPECT_EQ(output2[1]->public_id(), public_id2);
128
129  std::string public_id3 = output2[2]->public_id();
130  EXPECT_FALSE(public_id3.empty());
131  EXPECT_NE(public_id3, public_id1);
132  EXPECT_NE(public_id3, public_id2);
133}
134
135class ProfileSyncServiceMockForExtensionTests:
136    public ProfileSyncServiceMock {
137 public:
138  explicit ProfileSyncServiceMockForExtensionTests(Profile* p)
139      : ProfileSyncServiceMock(p) {}
140  ~ProfileSyncServiceMockForExtensionTests() {}
141
142  MOCK_METHOD0(Shutdown, void());
143  MOCK_CONST_METHOD0(GetDeviceInfoTracker, DeviceInfoTracker*());
144};
145
146KeyedService* CreateProfileSyncServiceMock(content::BrowserContext* profile) {
147  return new ProfileSyncServiceMockForExtensionTests(
148      Profile::FromBrowserContext(profile));
149}
150
151class ExtensionSignedInDevicesTest : public ExtensionApiUnittest {
152 public:
153  virtual void SetUp() {
154    ExtensionApiUnittest::SetUp();
155
156    ProfileSyncServiceFactory::GetInstance()->SetTestingFactory(
157        profile(), CreateProfileSyncServiceMock);
158  }
159};
160
161std::string GetPublicId(const base::DictionaryValue* dictionary) {
162  std::string public_id;
163  if (!dictionary->GetString("id", &public_id)) {
164    ADD_FAILURE() << "Not able to find public id in the dictionary";
165  }
166
167  return public_id;
168}
169
170void VerifyDictionaryWithDeviceInfo(const base::DictionaryValue* actual_value,
171                                    DeviceInfo* device_info) {
172  std::string public_id = GetPublicId(actual_value);
173  device_info->set_public_id(public_id);
174
175  scoped_ptr<base::DictionaryValue> expected_value(device_info->ToValue());
176  EXPECT_TRUE(expected_value->Equals(actual_value));
177}
178
179base::DictionaryValue* GetDictionaryFromList(int index,
180                                             base::ListValue* value) {
181  base::DictionaryValue* dictionary;
182  if (!value->GetDictionary(index, &dictionary)) {
183    ADD_FAILURE() << "Expected a list of dictionaries";
184    return NULL;
185  }
186  return dictionary;
187}
188
189TEST_F(ExtensionSignedInDevicesTest, GetAll) {
190  ProfileSyncServiceMockForExtensionTests* pss_mock =
191      static_cast<ProfileSyncServiceMockForExtensionTests*>(
192          ProfileSyncServiceFactory::GetForProfile(profile()));
193  MockDeviceInfoTracker device_tracker;
194
195  DeviceInfo device_info1(base::GenerateGUID(),
196                          "abc Device",
197                          "XYZ v1",
198                          "XYZ SyncAgent v1",
199                          sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
200                          "device_id");
201
202  DeviceInfo device_info2(base::GenerateGUID(),
203                          "def Device",
204                          "XYZ v2",
205                          "XYZ SyncAgent v2",
206                          sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
207                          "device_id");
208
209  device_tracker.Add(&device_info1);
210  device_tracker.Add(&device_info2);
211
212  EXPECT_CALL(*pss_mock, GetDeviceInfoTracker())
213      .WillOnce(Return(&device_tracker));
214
215  EXPECT_CALL(*pss_mock, Shutdown());
216
217  scoped_ptr<base::ListValue> result(RunFunctionAndReturnList(
218      new SignedInDevicesGetFunction(), "[null]"));
219
220  // Ensure dictionary matches device info.
221  VerifyDictionaryWithDeviceInfo(GetDictionaryFromList(0, result.get()),
222                                 &device_info1);
223  VerifyDictionaryWithDeviceInfo(GetDictionaryFromList(1, result.get()),
224                                 &device_info2);
225
226  // Ensure public ids are set and unique.
227  std::string public_id1 = GetPublicId(GetDictionaryFromList(0, result.get()));
228  std::string public_id2 = GetPublicId(GetDictionaryFromList(1, result.get()));
229
230  EXPECT_FALSE(public_id1.empty());
231  EXPECT_FALSE(public_id2.empty());
232  EXPECT_NE(public_id1, public_id2);
233}
234
235TEST_F(ExtensionSignedInDevicesTest, DeviceInfoTrackerNotInitialized) {
236  ProfileSyncServiceMockForExtensionTests* pss_mock =
237      static_cast<ProfileSyncServiceMockForExtensionTests*>(
238          ProfileSyncServiceFactory::GetForProfile(profile()));
239
240  EXPECT_CALL(*pss_mock, GetDeviceInfoTracker())
241    .WillOnce(Return((DeviceInfoTracker*)NULL));
242  EXPECT_CALL(*pss_mock, Shutdown());
243
244  ScopedVector<DeviceInfo> output = GetAllSignedInDevices(
245      extension()->id(), profile());
246
247  EXPECT_TRUE(output.empty());
248}
249
250}  // namespace extensions
251