blob: 7053973410bb5c5556461e78ae3bccfb890ddd0a [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_sync_service.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_sync_service_factory.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/sync/model/attachments/attachment_id.h"
#include "components/sync/model/attachments/attachment_service_proxy_for_test.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_error_factory_mock.h"
#include "components/sync/protocol/sync.pb.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/users/default_user_image/default_user_images.h"
#endif
using sync_pb::ManagedUserSpecifics;
using syncer::SUPERVISED_USERS;
using syncer::SyncChange;
using syncer::SyncChangeList;
using syncer::SyncChangeProcessor;
using syncer::SyncData;
using syncer::SyncDataList;
using syncer::SyncError;
using syncer::SyncErrorFactory;
using syncer::SyncMergeResult;
namespace {
class MockChangeProcessor : public SyncChangeProcessor {
public:
MockChangeProcessor() {}
~MockChangeProcessor() override {}
// SyncChangeProcessor implementation:
SyncError ProcessSyncChanges(const tracked_objects::Location& from_here,
const SyncChangeList& change_list) override;
SyncDataList GetAllSyncData(syncer::ModelType type) const override {
return SyncDataList();
}
const SyncChangeList& changes() const { return change_list_; }
SyncChange GetChange(const std::string& id) const;
private:
SyncChangeList change_list_;
};
SyncError MockChangeProcessor::ProcessSyncChanges(
const tracked_objects::Location& from_here,
const SyncChangeList& change_list) {
change_list_ = change_list;
return SyncError();
}
SyncChange MockChangeProcessor::GetChange(const std::string& id) const {
for (const SyncChange& sync_change : change_list_) {
if (sync_change.sync_data().GetSpecifics().managed_user().id() == id)
return sync_change;
}
return SyncChange();
}
// Callback for SupervisedUserSyncService::GetSupervisedUsersAsync().
void GetSupervisedUsersCallback(const base::DictionaryValue** dict,
const base::DictionaryValue* supervised_users) {
*dict = supervised_users;
}
} // namespace
class SupervisedUserSyncServiceTest : public ::testing::Test {
public:
SupervisedUserSyncServiceTest();
~SupervisedUserSyncServiceTest() override;
protected:
std::unique_ptr<SyncChangeProcessor> CreateChangeProcessor();
std::unique_ptr<SyncErrorFactory> CreateErrorFactory();
SyncData CreateRemoteData(const std::string& id,
const std::string& name,
const std::string& avatar);
PrefService* prefs() { return profile_.GetPrefs(); }
SupervisedUserSyncService* service() { return service_; }
MockChangeProcessor* change_processor() { return change_processor_; }
private:
content::TestBrowserThreadBundle thread_bundle_;
TestingProfile profile_;
SupervisedUserSyncService* service_;
// Owned by the SupervisedUserSyncService.
MockChangeProcessor* change_processor_;
// A unique ID for creating "remote" Sync data.
int64_t sync_data_id_;
};
SupervisedUserSyncServiceTest::SupervisedUserSyncServiceTest()
: change_processor_(NULL),
sync_data_id_(0) {
service_ = SupervisedUserSyncServiceFactory::GetForProfile(&profile_);
}
SupervisedUserSyncServiceTest::~SupervisedUserSyncServiceTest() {}
std::unique_ptr<SyncChangeProcessor>
SupervisedUserSyncServiceTest::CreateChangeProcessor() {
EXPECT_FALSE(change_processor_);
change_processor_ = new MockChangeProcessor();
return std::unique_ptr<SyncChangeProcessor>(change_processor_);
}
std::unique_ptr<SyncErrorFactory>
SupervisedUserSyncServiceTest::CreateErrorFactory() {
return std::unique_ptr<SyncErrorFactory>(new syncer::SyncErrorFactoryMock());
}
SyncData SupervisedUserSyncServiceTest::CreateRemoteData(
const std::string& id,
const std::string& name,
const std::string& chrome_avatar) {
::sync_pb::EntitySpecifics specifics;
specifics.mutable_managed_user()->set_id(id);
specifics.mutable_managed_user()->set_name(name);
specifics.mutable_managed_user()->set_acknowledged(true);
if (!chrome_avatar.empty())
specifics.mutable_managed_user()->set_chrome_avatar(chrome_avatar);
return SyncData::CreateRemoteData(
++sync_data_id_,
specifics,
base::Time(),
syncer::AttachmentIdList(),
syncer::AttachmentServiceProxyForTest::Create());
}
TEST_F(SupervisedUserSyncServiceTest, MergeEmpty) {
SyncMergeResult result =
service()->MergeDataAndStartSyncing(SUPERVISED_USERS,
SyncDataList(),
CreateChangeProcessor(),
CreateErrorFactory());
EXPECT_FALSE(result.error().IsSet());
EXPECT_EQ(0, result.num_items_added());
EXPECT_EQ(0, result.num_items_modified());
EXPECT_EQ(0, result.num_items_deleted());
EXPECT_EQ(0, result.num_items_before_association());
EXPECT_EQ(0, result.num_items_after_association());
EXPECT_EQ(0u, service()->GetSupervisedUsers()->size());
EXPECT_EQ(0u, change_processor()->changes().size());
service()->StopSyncing(SUPERVISED_USERS);
service()->Shutdown();
}
TEST_F(SupervisedUserSyncServiceTest, MergeExisting) {
const char kNameKey[] = "name";
const char kAcknowledgedKey[] = "acknowledged";
const char kChromeAvatarKey[] = "chromeAvatar";
const char kUserId1[] = "aaaaa";
const char kUserId2[] = "bbbbb";
const char kUserId3[] = "ccccc";
const char kUserId4[] = "ddddd";
const char kName1[] = "Anchor";
const char kName2[] = "Buzz";
const char kName3[] = "Crush";
const char kName4[] = "Dory";
const char kAvatar1[] = "";
#if defined(OS_CHROMEOS)
const char kAvatar2[] = "chromeos-avatar-index:0";
const char kAvatar3[] = "chromeos-avatar-index:20";
#else
const char kAvatar2[] = "chrome-avatar-index:0";
const char kAvatar3[] = "chrome-avatar-index:20";
#endif
const char kAvatar4[] = "";
{
DictionaryPrefUpdate update(prefs(), prefs::kSupervisedUsers);
base::DictionaryValue* supervised_users = update.Get();
auto dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString(kNameKey, kName1);
supervised_users->Set(kUserId1, std::move(dict));
dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString(kNameKey, kName2);
dict->SetBoolean(kAcknowledgedKey, true);
supervised_users->Set(kUserId2, std::move(dict));
}
const base::DictionaryValue* async_supervised_users = NULL;
service()->GetSupervisedUsersAsync(
base::Bind(&GetSupervisedUsersCallback, &async_supervised_users));
SyncDataList initial_sync_data;
initial_sync_data.push_back(CreateRemoteData(kUserId2, kName2, kAvatar2));
initial_sync_data.push_back(CreateRemoteData(kUserId3, kName3, kAvatar3));
initial_sync_data.push_back(CreateRemoteData(kUserId4, kName4, kAvatar4));
SyncMergeResult result =
service()->MergeDataAndStartSyncing(SUPERVISED_USERS,
initial_sync_data,
CreateChangeProcessor(),
CreateErrorFactory());
EXPECT_FALSE(result.error().IsSet());
EXPECT_EQ(2, result.num_items_added());
EXPECT_EQ(1, result.num_items_modified());
EXPECT_EQ(0, result.num_items_deleted());
EXPECT_EQ(2, result.num_items_before_association());
EXPECT_EQ(4, result.num_items_after_association());
const base::DictionaryValue* supervised_users =
service()->GetSupervisedUsers();
EXPECT_EQ(4u, supervised_users->size());
EXPECT_TRUE(async_supervised_users);
EXPECT_TRUE(supervised_users->Equals(async_supervised_users));
{
const base::DictionaryValue* supervised_user = NULL;
ASSERT_TRUE(supervised_users->GetDictionary(kUserId2, &supervised_user));
ASSERT_TRUE(supervised_user);
std::string name;
EXPECT_TRUE(supervised_user->GetString(kNameKey, &name));
EXPECT_EQ(kName2, name);
bool acknowledged = false;
EXPECT_TRUE(supervised_user->GetBoolean(kAcknowledgedKey, &acknowledged));
EXPECT_TRUE(acknowledged);
std::string avatar;
EXPECT_TRUE(supervised_user->GetString(kChromeAvatarKey, &avatar));
EXPECT_EQ(kAvatar2, avatar);
}
{
const base::DictionaryValue* supervised_user = NULL;
ASSERT_TRUE(supervised_users->GetDictionary(kUserId3, &supervised_user));
ASSERT_TRUE(supervised_user);
std::string name;
EXPECT_TRUE(supervised_user->GetString(kNameKey, &name));
EXPECT_EQ(kName3, name);
bool acknowledged = false;
EXPECT_TRUE(supervised_user->GetBoolean(kAcknowledgedKey, &acknowledged));
EXPECT_TRUE(acknowledged);
std::string avatar;
EXPECT_TRUE(supervised_user->GetString(kChromeAvatarKey, &avatar));
EXPECT_EQ(kAvatar3, avatar);
}
{
const base::DictionaryValue* supervised_user = NULL;
ASSERT_TRUE(supervised_users->GetDictionary(kUserId4, &supervised_user));
ASSERT_TRUE(supervised_user);
std::string name;
EXPECT_TRUE(supervised_user->GetString(kNameKey, &name));
EXPECT_EQ(kName4, name);
bool acknowledged = false;
EXPECT_TRUE(supervised_user->GetBoolean(kAcknowledgedKey, &acknowledged));
EXPECT_TRUE(acknowledged);
std::string avatar;
EXPECT_TRUE(supervised_user->GetString(kChromeAvatarKey, &avatar));
EXPECT_EQ(kAvatar4, avatar);
}
EXPECT_EQ(1u, change_processor()->changes().size());
{
SyncChange change = change_processor()->GetChange(kUserId1);
ASSERT_TRUE(change.IsValid());
EXPECT_EQ(SyncChange::ACTION_ADD, change.change_type());
const ManagedUserSpecifics& supervised_user =
change.sync_data().GetSpecifics().managed_user();
EXPECT_EQ(kName1, supervised_user.name());
EXPECT_FALSE(supervised_user.acknowledged());
EXPECT_EQ(kAvatar1, supervised_user.chrome_avatar());
}
}
TEST_F(SupervisedUserSyncServiceTest, GetAvatarIndex) {
int avatar = 100;
EXPECT_TRUE(SupervisedUserSyncService::GetAvatarIndex(std::string(),
&avatar));
EXPECT_EQ(SupervisedUserSyncService::kNoAvatar, avatar);
int avatar_index = 4;
#if defined(OS_CHROMEOS)
avatar_index += chromeos::default_user_image::kFirstDefaultImageIndex;
#endif
std::string avatar_str =
SupervisedUserSyncService::BuildAvatarString(avatar_index);
#if defined(OS_CHROMEOS)
EXPECT_EQ(base::StringPrintf("chromeos-avatar-index:%d", avatar_index),
avatar_str);
#else
EXPECT_EQ(base::StringPrintf("chrome-avatar-index:%d", avatar_index),
avatar_str);
#endif
EXPECT_TRUE(SupervisedUserSyncService::GetAvatarIndex(avatar_str, &avatar));
EXPECT_EQ(avatar_index, avatar);
avatar_index = 0;
#if defined(OS_CHROMEOS)
avatar_index += chromeos::default_user_image::kFirstDefaultImageIndex;
#endif
avatar_str = SupervisedUserSyncService::BuildAvatarString(avatar_index);
#if defined(OS_CHROMEOS)
EXPECT_EQ(base::StringPrintf("chromeos-avatar-index:%d", avatar_index),
avatar_str);
#else
EXPECT_EQ(base::StringPrintf("chrome-avatar-index:%d", avatar_index),
avatar_str);
#endif
EXPECT_TRUE(SupervisedUserSyncService::GetAvatarIndex(avatar_str, &avatar));
EXPECT_EQ(avatar_index, avatar);
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex("wrong-prefix:5",
&avatar));
#if defined(OS_CHROMEOS)
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chromeos-avatar-indes:2",
&avatar));
EXPECT_FALSE(
SupervisedUserSyncService::GetAvatarIndex("chromeos-avatar-indexxx:2",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chromeos-avatar-index:",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chromeos-avatar-index:x",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chrome-avatar-index:5",
&avatar));
#else
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chrome-avatar-indes:2",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chrome-avatar-indexxx:2",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chrome-avatar-index:",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chrome-avatar-index:x",
&avatar));
EXPECT_FALSE(SupervisedUserSyncService::GetAvatarIndex(
"chromeos-avatar-index:5",
&avatar));
#endif
}