blob: 775bcb38221aae97fab36ac8160116a2c9116171 [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 "chrome/browser/supervised_user/legacy/supervised_user_registration_utility.h"
#include <stdint.h>
#include <utility>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_refresh_token_fetcher.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_factory.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 "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "testing/gtest/include/gtest/gtest.h"
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 {
const char kSupervisedUserToken[] = "supervisedusertoken";
class MockChangeProcessor : public SyncChangeProcessor {
public:
MockChangeProcessor() {}
~MockChangeProcessor() override {}
// SyncChangeProcessor implementation:
SyncError ProcessSyncChanges(const base::Location& from_here,
const SyncChangeList& change_list) override;
SyncDataList GetAllSyncData(syncer::ModelType type) const override {
return SyncDataList();
}
const SyncChangeList& changes() const { return change_list_; }
private:
SyncChangeList change_list_;
};
SyncError MockChangeProcessor::ProcessSyncChanges(
const base::Location& from_here,
const SyncChangeList& change_list) {
change_list_ = change_list;
return SyncError();
}
class MockSupervisedUserRefreshTokenFetcher
: public SupervisedUserRefreshTokenFetcher {
public:
MockSupervisedUserRefreshTokenFetcher() {}
~MockSupervisedUserRefreshTokenFetcher() override {}
// SupervisedUserRefreshTokenFetcher implementation:
void Start(const std::string& supervised_user_id,
const std::string& device_name,
const TokenCallback& callback) override {
GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
callback.Run(error, kSupervisedUserToken);
}
};
} // namespace
class SupervisedUserRegistrationUtilityTest : public ::testing::Test {
public:
SupervisedUserRegistrationUtilityTest();
~SupervisedUserRegistrationUtilityTest() override;
void TearDown() override;
protected:
std::unique_ptr<SyncChangeProcessor> CreateChangeProcessor();
std::unique_ptr<SyncErrorFactory> CreateErrorFactory();
SyncData CreateRemoteData(const std::string& id, const std::string& name);
SyncMergeResult StartInitialSync();
SupervisedUserRegistrationUtility::RegistrationCallback
GetRegistrationCallback();
SupervisedUserRegistrationUtility* GetRegistrationUtility();
void Acknowledge();
PrefService* prefs() { return profile_.GetTestingPrefService(); }
SupervisedUserSyncService* service() { return service_; }
SupervisedUserSharedSettingsService* shared_settings_service() {
return shared_settings_service_;
}
MockChangeProcessor* change_processor() { return change_processor_; }
bool received_callback() const { return received_callback_; }
const GoogleServiceAuthError& error() const { return error_; }
const std::string& token() const { return token_; }
private:
void OnSupervisedUserRegistered(const GoogleServiceAuthError& error,
const std::string& token);
content::TestBrowserThreadBundle thread_bundle_;
base::RunLoop run_loop_;
TestingProfile profile_;
SupervisedUserSyncService* service_;
SupervisedUserSharedSettingsService* shared_settings_service_;
std::unique_ptr<SupervisedUserRegistrationUtility> registration_utility_;
// Owned by the SupervisedUserSyncService.
MockChangeProcessor* change_processor_;
// A unique ID for creating "remote" Sync data.
int64_t sync_data_id_;
// Whether OnSupervisedUserRegistered has been called.
bool received_callback_;
// Hold the registration result (either an error, or a token).
GoogleServiceAuthError error_;
std::string token_;
base::WeakPtrFactory<SupervisedUserRegistrationUtilityTest> weak_ptr_factory_;
};
SupervisedUserRegistrationUtilityTest::SupervisedUserRegistrationUtilityTest()
: change_processor_(NULL),
sync_data_id_(0),
received_callback_(false),
error_(GoogleServiceAuthError::NUM_STATES),
weak_ptr_factory_(this) {
service_ = SupervisedUserSyncServiceFactory::GetForProfile(&profile_);
shared_settings_service_ =
SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
&profile_);
}
SupervisedUserRegistrationUtilityTest::
~SupervisedUserRegistrationUtilityTest() {
EXPECT_FALSE(weak_ptr_factory_.HasWeakPtrs());
}
void SupervisedUserRegistrationUtilityTest::TearDown() {
content::RunAllTasksUntilIdle();
}
std::unique_ptr<SyncChangeProcessor>
SupervisedUserRegistrationUtilityTest::CreateChangeProcessor() {
EXPECT_FALSE(change_processor_);
change_processor_ = new MockChangeProcessor();
return std::unique_ptr<SyncChangeProcessor>(change_processor_);
}
std::unique_ptr<SyncErrorFactory>
SupervisedUserRegistrationUtilityTest::CreateErrorFactory() {
return std::unique_ptr<SyncErrorFactory>(new syncer::SyncErrorFactoryMock());
}
SyncMergeResult SupervisedUserRegistrationUtilityTest::StartInitialSync() {
SyncDataList initial_sync_data;
SyncMergeResult result =
service()->MergeDataAndStartSyncing(SUPERVISED_USERS,
initial_sync_data,
CreateChangeProcessor(),
CreateErrorFactory());
EXPECT_FALSE(result.error().IsSet());
return result;
}
SupervisedUserRegistrationUtility::RegistrationCallback
SupervisedUserRegistrationUtilityTest::GetRegistrationCallback() {
return base::Bind(
&SupervisedUserRegistrationUtilityTest::OnSupervisedUserRegistered,
weak_ptr_factory_.GetWeakPtr());
}
SupervisedUserRegistrationUtility*
SupervisedUserRegistrationUtilityTest::GetRegistrationUtility() {
if (registration_utility_.get())
return registration_utility_.get();
std::unique_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher(
new MockSupervisedUserRefreshTokenFetcher);
registration_utility_.reset(SupervisedUserRegistrationUtility::CreateImpl(
prefs(), std::move(token_fetcher), service(), shared_settings_service()));
return registration_utility_.get();
}
void SupervisedUserRegistrationUtilityTest::Acknowledge() {
SyncChangeList new_changes;
for (const SyncChange& sync_change : change_processor()->changes()) {
EXPECT_EQ(SyncChange::ACTION_ADD, sync_change.change_type());
::sync_pb::EntitySpecifics specifics =
sync_change.sync_data().GetSpecifics();
EXPECT_FALSE(specifics.managed_user().acknowledged());
specifics.mutable_managed_user()->set_acknowledged(true);
new_changes.push_back(
SyncChange(FROM_HERE,
SyncChange::ACTION_UPDATE,
SyncData::CreateRemoteData(
++sync_data_id_,
specifics,
base::Time(),
syncer::AttachmentIdList(),
syncer::AttachmentServiceProxyForTest::Create())));
}
service()->ProcessSyncChanges(FROM_HERE, new_changes);
run_loop_.Run();
}
void SupervisedUserRegistrationUtilityTest::OnSupervisedUserRegistered(
const GoogleServiceAuthError& error,
const std::string& token) {
received_callback_ = true;
error_ = error;
token_ = token;
run_loop_.Quit();
}
TEST_F(SupervisedUserRegistrationUtilityTest, Register) {
StartInitialSync();
GetRegistrationUtility()->Register(
SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId(),
SupervisedUserRegistrationInfo(base::ASCIIToUTF16("Dug"), 0),
GetRegistrationCallback());
EXPECT_EQ(1u, prefs()->GetDictionary(prefs::kSupervisedUsers)->size());
Acknowledge();
EXPECT_TRUE(received_callback());
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_FALSE(token().empty());
}
TEST_F(SupervisedUserRegistrationUtilityTest, RegisterBeforeInitialSync) {
GetRegistrationUtility()->Register(
SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId(),
SupervisedUserRegistrationInfo(base::ASCIIToUTF16("Nemo"), 5),
GetRegistrationCallback());
EXPECT_EQ(1u, prefs()->GetDictionary(prefs::kSupervisedUsers)->size());
StartInitialSync();
Acknowledge();
EXPECT_TRUE(received_callback());
EXPECT_EQ(GoogleServiceAuthError::NONE, error().state());
EXPECT_FALSE(token().empty());
}
TEST_F(SupervisedUserRegistrationUtilityTest,
SyncServiceShutdownBeforeRegFinish) {
StartInitialSync();
GetRegistrationUtility()->Register(
SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId(),
SupervisedUserRegistrationInfo(base::ASCIIToUTF16("Remy"), 12),
GetRegistrationCallback());
EXPECT_EQ(1u, prefs()->GetDictionary(prefs::kSupervisedUsers)->size());
service()->Shutdown();
EXPECT_EQ(0u, prefs()->GetDictionary(prefs::kSupervisedUsers)->size());
EXPECT_TRUE(received_callback());
EXPECT_EQ(GoogleServiceAuthError::REQUEST_CANCELED, error().state());
EXPECT_EQ(std::string(), token());
}
TEST_F(SupervisedUserRegistrationUtilityTest, StopSyncingBeforeRegFinish) {
StartInitialSync();
GetRegistrationUtility()->Register(
SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId(),
SupervisedUserRegistrationInfo(base::ASCIIToUTF16("Mike"), 17),
GetRegistrationCallback());
EXPECT_EQ(1u, prefs()->GetDictionary(prefs::kSupervisedUsers)->size());
service()->StopSyncing(SUPERVISED_USERS);
EXPECT_EQ(0u, prefs()->GetDictionary(prefs::kSupervisedUsers)->size());
EXPECT_TRUE(received_callback());
EXPECT_EQ(GoogleServiceAuthError::REQUEST_CANCELED, error().state());
EXPECT_EQ(std::string(), token());
}