blob: 0ba439c48a3771c2615d48a456ff20c90256a4e4 [file] [log] [blame]
// Copyright 2016 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.
#import "ios/chrome/test/app/sync_test_util.h"
#include <set>
#include <string>
#include "base/logging.h"
#import "base/mac/bind_objc_block.h"
#include "base/memory/ptr_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/browser_sync/profile_sync_service.h"
#include "components/history/core/browser/history_service.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/sync/engine/net/http_bridge_network_resources.h"
#include "components/sync/test/fake_server/entity_builder_factory.h"
#include "components/sync/test/fake_server/fake_server.h"
#include "components/sync/test/fake_server/fake_server_network_resources.h"
#include "components/sync/test/fake_server/fake_server_verifier.h"
#include "components/sync/test/fake_server/sessions_hierarchy.h"
#include "components/sync/test/fake_server/tombstone_entity.h"
#include "components/sync/test/fake_server/unique_client_entity.h"
#include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/history/history_service_factory.h"
#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
#include "ios/chrome/browser/sync/sync_setup_service.h"
#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
fake_server::FakeServer* gSyncFakeServer = nullptr;
NSString* const kSyncTestErrorDomain = @"SyncTestDomain";
// Overrides the network resources of the current ProfileSyncService with
// |resources|.
void OverrideSyncNetworkResources(
std::unique_ptr<syncer::NetworkResources> resources) {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
DCHECK(browser_state);
browser_sync::ProfileSyncService* service =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state);
service->OverrideNetworkResourcesForTest(std::move(resources));
}
} // namespace
namespace chrome_test_util {
void SetUpFakeSyncServer() {
DCHECK(!gSyncFakeServer);
gSyncFakeServer = new fake_server::FakeServer();
OverrideSyncNetworkResources(base::WrapUnique<syncer::NetworkResources>(
new fake_server::FakeServerNetworkResources(
gSyncFakeServer->AsWeakPtr())));
}
void TearDownFakeSyncServer() {
DCHECK(gSyncFakeServer);
delete gSyncFakeServer;
gSyncFakeServer = nullptr;
OverrideSyncNetworkResources(base::WrapUnique<syncer::NetworkResources>(
new syncer::HttpBridgeNetworkResources()));
}
void StartSync() {
DCHECK(!IsSyncInitialized());
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
SyncSetupService* sync_setup_service =
SyncSetupServiceFactory::GetForBrowserState(browser_state);
sync_setup_service->SetSyncEnabled(true);
}
void StopSync() {
DCHECK(IsSyncInitialized());
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
SyncSetupService* sync_setup_service =
SyncSetupServiceFactory::GetForBrowserState(browser_state);
sync_setup_service->SetSyncEnabled(false);
}
void TriggerSyncCycle(syncer::ModelType type) {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
browser_sync::ProfileSyncService* profile_sync_service =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state);
const syncer::ModelTypeSet types(type);
profile_sync_service->RefreshTypesForTest(types);
}
void ClearSyncServerData() {
DCHECK(gSyncFakeServer);
gSyncFakeServer->ClearServerData();
}
int GetNumberOfSyncEntities(syncer::ModelType type) {
DCHECK(gSyncFakeServer);
std::unique_ptr<base::DictionaryValue> entities =
gSyncFakeServer->GetEntitiesAsDictionaryValue();
std::string model_type_string = ModelTypeToString(type);
base::ListValue* entity_list = NULL;
if (!entities->GetList(model_type_string, &entity_list)) {
return 0;
}
return entity_list->GetSize();
}
BOOL VerifyNumberOfSyncEntitiesWithName(syncer::ModelType type,
std::string name,
size_t count,
NSError** error) {
DCHECK(gSyncFakeServer);
fake_server::FakeServerVerifier verifier(gSyncFakeServer);
testing::AssertionResult result =
verifier.VerifyEntityCountByTypeAndName(count, type, name);
if (result != testing::AssertionSuccess() && error != nil) {
NSDictionary* errorInfo = @{
NSLocalizedDescriptionKey : base::SysUTF8ToNSString(result.message())
};
*error = [NSError errorWithDomain:kSyncTestErrorDomain
code:0
userInfo:errorInfo];
return NO;
}
return result == testing::AssertionSuccess();
}
void InjectBookmarkOnFakeSyncServer(std::string url, std::string title) {
DCHECK(gSyncFakeServer);
fake_server::EntityBuilderFactory entity_builder_factory;
fake_server::BookmarkEntityBuilder bookmark_builder =
entity_builder_factory.NewBookmarkEntityBuilder(title);
gSyncFakeServer->InjectEntity(bookmark_builder.BuildBookmark(GURL(url)));
}
bool IsSyncInitialized() {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
DCHECK(browser_state);
syncer::SyncService* syncService =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state);
return syncService->IsEngineInitialized();
}
std::string GetSyncCacheGuid() {
DCHECK(IsSyncInitialized());
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
browser_sync::ProfileSyncService* profile_sync_service =
IOSChromeProfileSyncServiceFactory::GetForBrowserState(browser_state);
syncer::LocalDeviceInfoProvider* info_provider =
profile_sync_service->GetLocalDeviceInfoProvider();
return info_provider->GetLocalSyncCacheGUID();
}
void InjectAutofillProfileOnFakeSyncServer(std::string guid,
std::string full_name) {
DCHECK(gSyncFakeServer);
sync_pb::EntitySpecifics entity_specifics;
sync_pb::AutofillProfileSpecifics* autofill_profile =
entity_specifics.mutable_autofill_profile();
autofill_profile->add_name_full(full_name);
autofill_profile->set_guid(guid);
std::unique_ptr<fake_server::FakeServerEntity> entity =
fake_server::UniqueClientEntity::CreateForInjection(guid,
entity_specifics);
gSyncFakeServer->InjectEntity(std::move(entity));
}
void DeleteAutofillProfileOnFakeSyncServer(std::string guid) {
DCHECK(gSyncFakeServer);
std::vector<sync_pb::SyncEntity> autofill_profiles =
gSyncFakeServer->GetSyncEntitiesByModelType(syncer::AUTOFILL_PROFILE);
std::string entity_id;
for (const sync_pb::SyncEntity& autofill_profile : autofill_profiles) {
if (autofill_profile.specifics().autofill_profile().guid() == guid) {
entity_id = autofill_profile.id_string();
break;
}
}
// Delete the entity if it exists.
if (!entity_id.empty()) {
std::unique_ptr<fake_server::FakeServerEntity> entity;
entity = fake_server::TombstoneEntity::Create(entity_id, std::string());
gSyncFakeServer->InjectEntity(std::move(entity));
}
}
bool IsAutofillProfilePresent(std::string guid, std::string full_name) {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
autofill::PersonalDataManager* personal_data_manager =
autofill::PersonalDataManagerFactory::GetForBrowserState(browser_state);
autofill::AutofillProfile* autofill_profile =
personal_data_manager->GetProfileByGUID(guid);
if (autofill_profile) {
std::string actual_full_name =
base::UTF16ToUTF8(autofill_profile->GetRawInfo(autofill::NAME_FULL));
return actual_full_name == full_name;
}
return false;
}
void ClearAutofillProfile(std::string guid) {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
autofill::PersonalDataManager* personal_data_manager =
autofill::PersonalDataManagerFactory::GetForBrowserState(browser_state);
personal_data_manager->RemoveByGUID(guid);
}
BOOL VerifySessionsOnSyncServer(const std::multiset<std::string>& expected_urls,
NSError** error) {
DCHECK(gSyncFakeServer);
fake_server::SessionsHierarchy expected_sessions;
expected_sessions.AddWindow(expected_urls);
fake_server::FakeServerVerifier verifier(gSyncFakeServer);
testing::AssertionResult result = verifier.VerifySessions(expected_sessions);
if (result != testing::AssertionSuccess() && error != nil) {
NSDictionary* errorInfo = @{
NSLocalizedDescriptionKey : base::SysUTF8ToNSString(result.message())
};
*error = [NSError errorWithDomain:kSyncTestErrorDomain
code:0
userInfo:errorInfo];
return NO;
}
return result == testing::AssertionSuccess();
}
void AddTypedURLOnClient(const GURL& url) {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
history::HistoryService* historyService =
ios::HistoryServiceFactory::GetForBrowserState(
browser_state, ServiceAccessType::EXPLICIT_ACCESS);
historyService->AddPage(url, base::Time::Now(), nullptr, 1, GURL(),
history::RedirectList(), ui::PAGE_TRANSITION_TYPED,
history::SOURCE_BROWSED, false);
}
void InjectTypedURLOnFakeSyncServer(const std::string& url) {
DCHECK(gSyncFakeServer);
sync_pb::EntitySpecifics entitySpecifics;
sync_pb::TypedUrlSpecifics* typedUrl = entitySpecifics.mutable_typed_url();
typedUrl->set_url(url);
typedUrl->set_title(url);
typedUrl->add_visits(base::Time::Max().ToInternalValue());
typedUrl->add_visit_transitions(sync_pb::SyncEnums::TYPED);
std::unique_ptr<fake_server::FakeServerEntity> entity =
fake_server::UniqueClientEntity::CreateForInjection(url, entitySpecifics);
gSyncFakeServer->InjectEntity(std::move(entity));
}
BOOL IsTypedUrlPresentOnClient(const GURL& url,
BOOL expect_present,
NSError** error) {
// Call the history service.
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
history::HistoryService* history_service =
ios::HistoryServiceFactory::GetForBrowserState(
browser_state, ServiceAccessType::EXPLICIT_ACCESS);
const GURL block_safe_url(url);
std::set<GURL> origins;
origins.insert(block_safe_url);
__block bool history_service_callback_called = false;
__block int count = 0;
using history::OriginCountAndLastVisitMap;
history_service->GetCountsAndLastVisitForOrigins(
origins, base::BindBlockArc(^(const OriginCountAndLastVisitMap& result) {
auto iter = result.find(block_safe_url);
if (iter != result.end())
count = iter->second.first;
history_service_callback_called = true;
}));
NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:4.0];
while (!history_service_callback_called &&
[[NSDate date] compare:deadline] != NSOrderedDescending) {
base::test::ios::SpinRunLoopWithMaxDelay(
base::TimeDelta::FromSecondsD(0.1));
}
NSString* error_message = nil;
if (!history_service_callback_called) {
error_message = @"History::GetCountsAndLastVisitForOrigins callback never "
"called, app will probably crash later.";
} else if (count == 0 && expect_present) {
error_message = @"Typed URL isn't found in HistoryService.";
} else if (count > 0 && !expect_present) {
error_message = @"Typed URL isn't supposed to be in HistoryService.";
}
if (error_message != nil && error != nil) {
NSDictionary* error_info = @{NSLocalizedDescriptionKey : error_message};
*error = [NSError errorWithDomain:kSyncTestErrorDomain
code:0
userInfo:error_info];
return NO;
}
return error_message == nil;
}
void DeleteTypedUrlFromClient(const GURL& url) {
ios::ChromeBrowserState* browser_state =
chrome_test_util::GetOriginalBrowserState();
history::HistoryService* history_service =
ios::HistoryServiceFactory::GetForBrowserState(
browser_state, ServiceAccessType::EXPLICIT_ACCESS);
history_service->DeleteURL(url);
}
void DeleteTypedUrlFromFakeSyncServer(std::string url) {
DCHECK(gSyncFakeServer);
std::vector<sync_pb::SyncEntity> typed_urls =
gSyncFakeServer->GetSyncEntitiesByModelType(syncer::TYPED_URLS);
std::string entity_id;
for (const sync_pb::SyncEntity& typed_url : typed_urls) {
if (typed_url.specifics().typed_url().url() == url) {
entity_id = typed_url.id_string();
break;
}
}
if (!entity_id.empty()) {
std::unique_ptr<fake_server::FakeServerEntity> entity;
entity = fake_server::TombstoneEntity::Create(entity_id, std::string());
gSyncFakeServer->InjectEntity(std::move(entity));
}
}
} // namespace chrome_test_util