| // Copyright 2013 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/sync/test/integration/sync_app_list_helper.h" |
| |
| #include <map> |
| #include <vector> |
| |
| #include "base/strings/stringprintf.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/sync/test/integration/sync_datatype_helper.h" |
| #include "chrome/browser/sync/test/integration/sync_test.h" |
| #include "chrome/browser/ui/app_list/app_list_syncable_service.h" |
| #include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h" |
| #include "chrome/browser/ui/app_list/chrome_app_list_item.h" |
| #include "chrome/browser/ui/app_list/chrome_app_list_model_updater.h" |
| #include "chrome/common/extensions/sync_helper.h" |
| #include "extensions/browser/app_sorting.h" |
| #include "extensions/browser/extension_system.h" |
| |
| using app_list::AppListSyncableService; |
| using app_list::AppListSyncableServiceFactory; |
| |
| SyncAppListHelper* SyncAppListHelper::GetInstance() { |
| SyncAppListHelper* instance = base::Singleton<SyncAppListHelper>::get(); |
| instance->SetupIfNecessary(sync_datatype_helper::test()); |
| return instance; |
| } |
| |
| SyncAppListHelper::SyncAppListHelper() |
| : test_(nullptr), setup_completed_(false) {} |
| |
| SyncAppListHelper::~SyncAppListHelper() {} |
| |
| void SyncAppListHelper::SetupIfNecessary(SyncTest* test) { |
| if (setup_completed_) { |
| DCHECK_EQ(test, test_); |
| return; |
| } |
| test_ = test; |
| for (auto* profile : test_->GetAllProfiles()) { |
| extensions::ExtensionSystem::Get(profile)->InitForRegularProfile( |
| true /* extensions_enabled */); |
| if (test_->use_verifier() && profile == test_->verifier()) { |
| // The default page break items are only installed for first-time users. |
| // The verifier() profile doesn't get initialized with remote sync data, |
| // and hence the default page breaks are not installed for it. We have to |
| // install them manually to avoid a mismatch when comparing the verifier() |
| // against other client profiles. |
| app_list::AppListSyncableServiceFactory::GetForProfile(profile) |
| ->InstallDefaultPageBreaksForTest(); |
| } |
| } |
| |
| setup_completed_ = true; |
| } |
| |
| bool SyncAppListHelper::AppListMatch(Profile* profile1, Profile* profile2) { |
| AppListSyncableService* service1 = |
| AppListSyncableServiceFactory::GetForProfile(profile1); |
| AppListSyncableService* service2 = |
| AppListSyncableServiceFactory::GetForProfile(profile2); |
| // Note: sync item entries may not exist in verifier, but item lists should |
| // match. |
| if (service1->GetModelUpdater()->ItemCount() != |
| service2->GetModelUpdater()->ItemCount()) { |
| LOG(ERROR) << "Model item count: " |
| << service1->GetModelUpdater()->ItemCount() |
| << " != " << service2->GetModelUpdater()->ItemCount(); |
| return false; |
| } |
| bool res = true; |
| for (size_t i = 0; i < service1->GetModelUpdater()->ItemCount(); ++i) { |
| ChromeAppListItem* item1 = service1->GetModelUpdater()->ItemAtForTest(i); |
| size_t index2; |
| if (!service2->GetModelUpdater()->FindItemIndexForTest(item1->id(), |
| &index2)) { |
| LOG(ERROR) << " Item(" << i << ") in profile1: " << item1->ToDebugString() |
| << " Not in profile2."; |
| res = false; |
| continue; |
| } |
| |
| ChromeAppListItem* item2 = |
| service2->GetModelUpdater()->ItemAtForTest(index2); |
| if (item1->CompareForTest(item2)) |
| continue; |
| |
| LOG(ERROR) << "Item(" << i << ") in profile1: " << item1->ToDebugString() |
| << " != " |
| << "Item(" << i << ") in profile2: " << item2->ToDebugString(); |
| res = false; |
| } |
| return res; |
| } |
| |
| bool SyncAppListHelper::AllProfilesHaveSameAppList() { |
| const auto& profiles = test_->GetAllProfiles(); |
| for (auto* profile : profiles) { |
| if (profile != profiles.front() && |
| !AppListMatch(profiles.front(), profile)) { |
| DVLOG(1) << "Profile1: " |
| << AppListSyncableServiceFactory::GetForProfile(profile); |
| PrintAppList(profile); |
| DVLOG(1) << "Profile2: " << |
| AppListSyncableServiceFactory::GetForProfile(profiles.front()); |
| PrintAppList(profiles.front()); |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void SyncAppListHelper::MoveAppToFolder(Profile* profile, |
| const std::string& id, |
| const std::string& folder_id) { |
| AppListSyncableService* service = |
| AppListSyncableServiceFactory::GetForProfile(profile); |
| service->GetModelUpdater()->MoveItemToFolder(id, folder_id); |
| } |
| |
| void SyncAppListHelper::MoveAppFromFolder(Profile* profile, |
| const std::string& id, |
| const std::string& folder_id) { |
| AppListSyncableService* service = |
| AppListSyncableServiceFactory::GetForProfile(profile); |
| ChromeAppListItem* folder = |
| service->GetModelUpdater()->FindFolderItem(folder_id); |
| if (!folder) { |
| LOG(ERROR) << "Folder not found: " << folder_id; |
| return; |
| } |
| service->GetModelUpdater()->MoveItemToFolder(id, ""); |
| } |
| |
| void SyncAppListHelper::PrintAppList(Profile* profile) { |
| AppListSyncableService* service = |
| AppListSyncableServiceFactory::GetForProfile(profile); |
| // Build a map from each folder item's id to a list of its child items. |
| std::map<const std::string, std::vector<ChromeAppListItem*>> children; |
| for (size_t i = 0; i < service->GetModelUpdater()->ItemCount(); ++i) { |
| ChromeAppListItem* item = service->GetModelUpdater()->ItemAtForTest(i); |
| if (!item->folder_id().empty()) |
| children[item->folder_id()].push_back(item); |
| } |
| for (size_t i = 0; i < service->GetModelUpdater()->ItemCount(); ++i) { |
| ChromeAppListItem* item = service->GetModelUpdater()->ItemAtForTest(i); |
| // Skip if it's not a top level item. |
| if (!item->folder_id().empty()) |
| continue; |
| std::string label = base::StringPrintf("Item(%d): ", static_cast<int>(i)); |
| PrintItem(profile, item, label); |
| // Print children if it has any. |
| if (children.count(item->id())) { |
| DCHECK(item->is_folder()); |
| auto& child_items = children[item->folder_id()]; |
| for (size_t j = 0; j < child_items.size(); ++j) { |
| ChromeAppListItem* child_item = child_items[j]; |
| std::string child_label = |
| base::StringPrintf(" Folder Item(%d): ", static_cast<int>(j)); |
| PrintItem(profile, child_item, child_label); |
| } |
| } |
| } |
| } |
| |
| void SyncAppListHelper::PrintItem(Profile* profile, |
| ChromeAppListItem* item, |
| const std::string& label) { |
| extensions::AppSorting* s = |
| extensions::ExtensionSystem::Get(profile)->app_sorting(); |
| std::string id = item->id(); |
| DVLOG(1) << label << item->ToDebugString() |
| << " Page: " << s->GetPageOrdinal(id).ToDebugString().substr(0, 8) |
| << " Item: " |
| << s->GetAppLaunchOrdinal(id).ToDebugString().substr(0, 8); |
| } |