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 <string>
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "base/prefs/scoped_user_pref_update.h"
10#include "base/strings/stringprintf.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/threading/sequenced_worker_pool.h"
13#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
14#include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
15#include "chrome/common/pref_names.h"
16#include "chrome/test/base/testing_profile.h"
17#include "sync/api/attachments/attachment_id.h"
18#include "sync/api/sync_change.h"
19#include "sync/api/sync_error_factory_mock.h"
20#include "sync/internal_api/public/attachments/attachment_service_proxy_for_test.h"
21#include "sync/protocol/sync.pb.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24#if defined(OS_CHROMEOS)
25#include "components/user_manager/user_image/default_user_images.h"
26#endif
27
28using sync_pb::ManagedUserSpecifics;
29using syncer::SUPERVISED_USERS;
30using syncer::SyncChange;
31using syncer::SyncChangeList;
32using syncer::SyncChangeProcessor;
33using syncer::SyncData;
34using syncer::SyncDataList;
35using syncer::SyncError;
36using syncer::SyncErrorFactory;
37using syncer::SyncMergeResult;
38
39namespace {
40
41class MockChangeProcessor : public SyncChangeProcessor {
42 public:
43  MockChangeProcessor() {}
44  virtual ~MockChangeProcessor() {}
45
46  // SyncChangeProcessor implementation:
47  virtual SyncError ProcessSyncChanges(
48      const tracked_objects::Location& from_here,
49      const SyncChangeList& change_list) OVERRIDE;
50
51  virtual SyncDataList GetAllSyncData(syncer::ModelType type) const
52      OVERRIDE {
53    return SyncDataList();
54  }
55
56  const SyncChangeList& changes() const { return change_list_; }
57  SyncChange GetChange(const std::string& id) const;
58
59 private:
60  SyncChangeList change_list_;
61};
62
63SyncError MockChangeProcessor::ProcessSyncChanges(
64    const tracked_objects::Location& from_here,
65    const SyncChangeList& change_list) {
66  change_list_ = change_list;
67  return SyncError();
68}
69
70SyncChange MockChangeProcessor::GetChange(const std::string& id) const {
71  for (SyncChangeList::const_iterator it = change_list_.begin();
72       it != change_list_.end(); ++it) {
73    if (it->sync_data().GetSpecifics().managed_user().id() == id)
74      return *it;
75  }
76  return SyncChange();
77}
78
79// Callback for SupervisedUserSyncService::GetSupervisedUsersAsync().
80void GetSupervisedUsersCallback(const base::DictionaryValue** dict,
81                                const base::DictionaryValue* supervised_users) {
82  *dict = supervised_users;
83}
84
85}  // namespace
86
87class SupervisedUserSyncServiceTest : public ::testing::Test {
88 public:
89  SupervisedUserSyncServiceTest();
90  virtual ~SupervisedUserSyncServiceTest();
91
92 protected:
93  scoped_ptr<SyncChangeProcessor> CreateChangeProcessor();
94  scoped_ptr<SyncErrorFactory> CreateErrorFactory();
95  SyncData CreateRemoteData(const std::string& id,
96                            const std::string& name,
97                            const std::string& avatar);
98
99  PrefService* prefs() { return profile_.GetPrefs(); }
100  SupervisedUserSyncService* service() { return service_; }
101  MockChangeProcessor* change_processor() { return change_processor_; }
102
103 private:
104  base::MessageLoop message_loop;
105  TestingProfile profile_;
106  SupervisedUserSyncService* service_;
107
108  // Owned by the SupervisedUserSyncService.
109  MockChangeProcessor* change_processor_;
110
111  // A unique ID for creating "remote" Sync data.
112  int64 sync_data_id_;
113};
114
115SupervisedUserSyncServiceTest::SupervisedUserSyncServiceTest()
116    : change_processor_(NULL),
117      sync_data_id_(0) {
118  service_ = SupervisedUserSyncServiceFactory::GetForProfile(&profile_);
119}
120
121SupervisedUserSyncServiceTest::~SupervisedUserSyncServiceTest() {}
122
123scoped_ptr<SyncChangeProcessor>
124SupervisedUserSyncServiceTest::CreateChangeProcessor() {
125  EXPECT_FALSE(change_processor_);
126  change_processor_ = new MockChangeProcessor();
127  return scoped_ptr<SyncChangeProcessor>(change_processor_);
128}
129
130scoped_ptr<SyncErrorFactory>
131SupervisedUserSyncServiceTest::CreateErrorFactory() {
132  return scoped_ptr<SyncErrorFactory>(new syncer::SyncErrorFactoryMock());
133}
134
135SyncData SupervisedUserSyncServiceTest::CreateRemoteData(
136    const std::string& id,
137    const std::string& name,
138    const std::string& chrome_avatar) {
139  ::sync_pb::EntitySpecifics specifics;
140  specifics.mutable_managed_user()->set_id(id);
141  specifics.mutable_managed_user()->set_name(name);
142  specifics.mutable_managed_user()->set_acknowledged(true);
143  if (!chrome_avatar.empty())
144    specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
145
146  return SyncData::CreateRemoteData(
147      ++sync_data_id_,
148      specifics,
149      base::Time(),
150      syncer::AttachmentIdList(),
151      syncer::AttachmentServiceProxyForTest::Create());
152}
153
154TEST_F(SupervisedUserSyncServiceTest, MergeEmpty) {
155  SyncMergeResult result =
156      service()->MergeDataAndStartSyncing(SUPERVISED_USERS,
157                                          SyncDataList(),
158                                          CreateChangeProcessor(),
159                                          CreateErrorFactory());
160  EXPECT_FALSE(result.error().IsSet());
161  EXPECT_EQ(0, result.num_items_added());
162  EXPECT_EQ(0, result.num_items_modified());
163  EXPECT_EQ(0, result.num_items_deleted());
164  EXPECT_EQ(0, result.num_items_before_association());
165  EXPECT_EQ(0, result.num_items_after_association());
166  EXPECT_EQ(0u, service()->GetSupervisedUsers()->size());
167  EXPECT_EQ(0u, change_processor()->changes().size());
168
169  service()->StopSyncing(SUPERVISED_USERS);
170  service()->Shutdown();
171}
172
173TEST_F(SupervisedUserSyncServiceTest, MergeExisting) {
174  const char kNameKey[] = "name";
175  const char kAcknowledgedKey[] = "acknowledged";
176  const char kChromeAvatarKey[] = "chromeAvatar";
177
178  const char kUserId1[] = "aaaaa";
179  const char kUserId2[] = "bbbbb";
180  const char kUserId3[] = "ccccc";
181  const char kUserId4[] = "ddddd";
182  const char kName1[] = "Anchor";
183  const char kName2[] = "Buzz";
184  const char kName3[] = "Crush";
185  const char kName4[] = "Dory";
186  const char kAvatar1[] = "";
187#if defined(OS_CHROMEOS)
188  const char kAvatar2[] = "chromeos-avatar-index:0";
189  const char kAvatar3[] = "chromeos-avatar-index:20";
190#else
191  const char kAvatar2[] = "chrome-avatar-index:0";
192  const char kAvatar3[] = "chrome-avatar-index:20";
193#endif
194  const char kAvatar4[] = "";
195  {
196    DictionaryPrefUpdate update(prefs(), prefs::kSupervisedUsers);
197    base::DictionaryValue* supervised_users = update.Get();
198    base::DictionaryValue* dict = new base::DictionaryValue;
199    dict->SetString(kNameKey, kName1);
200    supervised_users->Set(kUserId1, dict);
201    dict = new base::DictionaryValue;
202    dict->SetString(kNameKey, kName2);
203    dict->SetBoolean(kAcknowledgedKey, true);
204    supervised_users->Set(kUserId2, dict);
205  }
206
207  const base::DictionaryValue* async_supervised_users = NULL;
208  service()->GetSupervisedUsersAsync(
209      base::Bind(&GetSupervisedUsersCallback, &async_supervised_users));
210
211  SyncDataList initial_sync_data;
212  initial_sync_data.push_back(CreateRemoteData(kUserId2, kName2, kAvatar2));
213  initial_sync_data.push_back(CreateRemoteData(kUserId3, kName3, kAvatar3));
214  initial_sync_data.push_back(CreateRemoteData(kUserId4, kName4, kAvatar4));
215
216  SyncMergeResult result =
217      service()->MergeDataAndStartSyncing(SUPERVISED_USERS,
218                                          initial_sync_data,
219                                          CreateChangeProcessor(),
220                                          CreateErrorFactory());
221  EXPECT_FALSE(result.error().IsSet());
222  EXPECT_EQ(2, result.num_items_added());
223  EXPECT_EQ(1, result.num_items_modified());
224  EXPECT_EQ(0, result.num_items_deleted());
225  EXPECT_EQ(2, result.num_items_before_association());
226  EXPECT_EQ(4, result.num_items_after_association());
227
228  const base::DictionaryValue* supervised_users =
229      service()->GetSupervisedUsers();
230  EXPECT_EQ(4u, supervised_users->size());
231  EXPECT_TRUE(async_supervised_users);
232  EXPECT_TRUE(supervised_users->Equals(async_supervised_users));
233
234  {
235    const base::DictionaryValue* supervised_user = NULL;
236    ASSERT_TRUE(supervised_users->GetDictionary(kUserId2, &supervised_user));
237    ASSERT_TRUE(supervised_user);
238    std::string name;
239    EXPECT_TRUE(supervised_user->GetString(kNameKey, &name));
240    EXPECT_EQ(kName2, name);
241    bool acknowledged = false;
242    EXPECT_TRUE(supervised_user->GetBoolean(kAcknowledgedKey, &acknowledged));
243    EXPECT_TRUE(acknowledged);
244    std::string avatar;
245    EXPECT_TRUE(supervised_user->GetString(kChromeAvatarKey, &avatar));
246    EXPECT_EQ(kAvatar2, avatar);
247  }
248  {
249    const base::DictionaryValue* supervised_user = NULL;
250    ASSERT_TRUE(supervised_users->GetDictionary(kUserId3, &supervised_user));
251    ASSERT_TRUE(supervised_user);
252    std::string name;
253    EXPECT_TRUE(supervised_user->GetString(kNameKey, &name));
254    EXPECT_EQ(kName3, name);
255    bool acknowledged = false;
256    EXPECT_TRUE(supervised_user->GetBoolean(kAcknowledgedKey, &acknowledged));
257    EXPECT_TRUE(acknowledged);
258    std::string avatar;
259    EXPECT_TRUE(supervised_user->GetString(kChromeAvatarKey, &avatar));
260    EXPECT_EQ(kAvatar3, avatar);
261  }
262  {
263    const base::DictionaryValue* supervised_user = NULL;
264    ASSERT_TRUE(supervised_users->GetDictionary(kUserId4, &supervised_user));
265    ASSERT_TRUE(supervised_user);
266    std::string name;
267    EXPECT_TRUE(supervised_user->GetString(kNameKey, &name));
268    EXPECT_EQ(kName4, name);
269    bool acknowledged = false;
270    EXPECT_TRUE(supervised_user->GetBoolean(kAcknowledgedKey, &acknowledged));
271    EXPECT_TRUE(acknowledged);
272    std::string avatar;
273    EXPECT_TRUE(supervised_user->GetString(kChromeAvatarKey, &avatar));
274    EXPECT_EQ(kAvatar4, avatar);
275  }
276
277  EXPECT_EQ(1u, change_processor()->changes().size());
278  {
279    SyncChange change = change_processor()->GetChange(kUserId1);
280    ASSERT_TRUE(change.IsValid());
281    EXPECT_EQ(SyncChange::ACTION_ADD, change.change_type());
282    const ManagedUserSpecifics& supervised_user =
283        change.sync_data().GetSpecifics().managed_user();
284    EXPECT_EQ(kName1, supervised_user.name());
285    EXPECT_FALSE(supervised_user.acknowledged());
286    EXPECT_EQ(kAvatar1, supervised_user.chrome_avatar());
287  }
288}
289
290TEST_F(SupervisedUserSyncServiceTest, GetAvatarIndex) {
291  int avatar = 100;
292  EXPECT_TRUE(SupervisedUserSyncService::GetAvatarIndex(std::string(),
293                                                        &avatar));
294  EXPECT_EQ(SupervisedUserSyncService::kNoAvatar, avatar);
295
296  int avatar_index = 4;
297#if defined(OS_CHROMEOS)
298  avatar_index += user_manager::kFirstDefaultImageIndex;
299#endif
300  std::string avatar_str =
301      SupervisedUserSyncService::BuildAvatarString(avatar_index);
302#if defined(OS_CHROMEOS)
303  EXPECT_EQ(base::StringPrintf("chromeos-avatar-index:%d", avatar_index),
304            avatar_str);
305#else
306  EXPECT_EQ(base::StringPrintf("chrome-avatar-index:%d", avatar_index),
307            avatar_str);
308#endif
309  EXPECT_TRUE(SupervisedUserSyncService::GetAvatarIndex(avatar_str, &avatar));
310  EXPECT_EQ(avatar_index, avatar);
311
312  avatar_index = 0;
313#if defined(OS_CHROMEOS)
314  avatar_index += user_manager::kFirstDefaultImageIndex;
315#endif
316  avatar_str = SupervisedUserSyncService::BuildAvatarString(avatar_index);
317#if defined(OS_CHROMEOS)
318  EXPECT_EQ(base::StringPrintf("chromeos-avatar-index:%d", avatar_index),
319            avatar_str);
320#else
321  EXPECT_EQ(base::StringPrintf("chrome-avatar-index:%d", avatar_index),
322            avatar_str);
323#endif
324  EXPECT_TRUE(SupervisedUserSyncService::GetAvatarIndex(avatar_str, &avatar));
325  EXPECT_EQ(avatar_index, avatar);
326
327  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex("wrong-prefix:5",
328                                                         &avatar));
329#if defined(OS_CHROMEOS)
330  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
331      "chromeos-avatar-indes:2",
332      &avatar));
333
334  EXPECT_FALSE(
335      SupervisedUserSyncService::GetAvatarIndex("chromeos-avatar-indexxx:2",
336                                                &avatar));
337
338  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
339      "chromeos-avatar-index:",
340      &avatar));
341
342  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
343      "chromeos-avatar-index:x",
344      &avatar));
345
346  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
347      "chrome-avatar-index:5",
348      &avatar));
349#else
350  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
351      "chrome-avatar-indes:2",
352      &avatar));
353
354  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
355      "chrome-avatar-indexxx:2",
356      &avatar));
357
358  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
359      "chrome-avatar-index:",
360      &avatar));
361
362  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
363      "chrome-avatar-index:x",
364      &avatar));
365
366  EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
367      "chromeos-avatar-index:5",
368      &avatar));
369#endif
370}
371