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 25 using sync_driver::DeviceInfo; 26 using sync_driver::DeviceInfoTracker; 27 using testing::Return; 28 29 namespace extensions { 30 31 class 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 73 TEST(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 135 class 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 146 KeyedService* CreateProfileSyncServiceMock(content::BrowserContext* profile) { 147 return new ProfileSyncServiceMockForExtensionTests( 148 Profile::FromBrowserContext(profile)); 149 } 150 151 class ExtensionSignedInDevicesTest : public ExtensionApiUnittest { 152 public: 153 virtual void SetUp() { 154 ExtensionApiUnittest::SetUp(); 155 156 ProfileSyncServiceFactory::GetInstance()->SetTestingFactory( 157 profile(), CreateProfileSyncServiceMock); 158 } 159 }; 160 161 std::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 170 void 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 179 base::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 189 TEST_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 235 TEST_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