diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/components/sync_sessions | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/sync_sessions')
13 files changed, 459 insertions, 108 deletions
diff --git a/chromium/components/sync_sessions/BUILD.gn b/chromium/components/sync_sessions/BUILD.gn index 74028ef9af3..9be971c755a 100644 --- a/chromium/components/sync_sessions/BUILD.gn +++ b/chromium/components/sync_sessions/BUILD.gn @@ -15,6 +15,8 @@ static_library("sync_sessions") { "open_tabs_ui_delegate.h", "open_tabs_ui_delegate_impl.cc", "open_tabs_ui_delegate_impl.h", + "proxy_tabs_data_type_controller.cc", + "proxy_tabs_data_type_controller.h", "session_model_type_controller.cc", "session_model_type_controller.h", "session_store.cc", diff --git a/chromium/components/sync_sessions/favicon_cache.cc b/chromium/components/sync_sessions/favicon_cache.cc index 9a75025a6d8..53014c5f7cd 100644 --- a/chromium/components/sync_sessions/favicon_cache.cc +++ b/chromium/components/sync_sessions/favicon_cache.cc @@ -248,10 +248,9 @@ syncer::SyncMergeResult FaviconCache::MergeDataAndStartSyncing( syncer::SyncMergeResult merge_result(type); merge_result.set_num_items_before_association(synced_favicons_.size()); std::set<GURL> unsynced_favicon_urls; - for (FaviconMap::const_iterator iter = synced_favicons_.begin(); - iter != synced_favicons_.end(); ++iter) { - if (FaviconInfoHasValidTypeData(*(iter->second), type)) - unsynced_favicon_urls.insert(iter->first); + for (const auto& url_icon_pair : synced_favicons_) { + if (FaviconInfoHasValidTypeData(*url_icon_pair.second, type)) + unsynced_favicon_urls.insert(url_icon_pair.first); } syncer::SyncChangeList local_changes; @@ -406,10 +405,9 @@ void FaviconCache::OnPageFaviconUpdated(const GURL& page_url, if (page_task_map_.find(page_url) != page_task_map_.end()) return; - PageFaviconMap::const_iterator url_iter = page_favicon_map_.find(page_url); + auto url_iter = page_favicon_map_.find(page_url); if (url_iter != page_favicon_map_.end()) { - FaviconMap::const_iterator icon_iter = - synced_favicons_.find(url_iter->second); + auto icon_iter = synced_favicons_.find(url_iter->second); // TODO(zea): consider what to do when only a subset of supported // resolutions are available. if (icon_iter != synced_favicons_.end() && @@ -536,8 +534,8 @@ base::Time FaviconCache::GetLastVisitTimeForTest( } bool FaviconCache::FaviconRecencyFunctor::operator()( - const linked_ptr<SyncedFaviconInfo>& lhs, - const linked_ptr<SyncedFaviconInfo>& rhs) const { + const SyncedFaviconInfo* lhs, + const SyncedFaviconInfo* rhs) const { // TODO(zea): incorporate bookmarked status here once we care about it. if (lhs->last_visit_time < rhs->last_visit_time) return true; @@ -622,7 +620,7 @@ void FaviconCache::UpdateSyncState( return; } - FaviconMap::const_iterator iter = synced_favicons_.find(icon_url); + auto iter = synced_favicons_.find(icon_url); DCHECK(iter != synced_favicons_.end()); const SyncedFaviconInfo* favicon_info = iter->second.get(); @@ -675,32 +673,32 @@ SyncedFaviconInfo* FaviconCache::GetFaviconInfo( // TODO(zea): implement in-memory eviction. DVLOG(1) << "Adding favicon info for " << icon_url.spec(); - SyncedFaviconInfo* favicon_info = new SyncedFaviconInfo(icon_url); - synced_favicons_[icon_url] = make_linked_ptr(favicon_info); - recent_favicons_.insert(synced_favicons_[icon_url]); + auto favicon_info = std::make_unique<SyncedFaviconInfo>(icon_url); + SyncedFaviconInfo* favicon_info_ptr = favicon_info.get(); + synced_favicons_[icon_url] = std::move(favicon_info); + recent_favicons_.insert(favicon_info_ptr); DCHECK_EQ(recent_favicons_.size(), synced_favicons_.size()); - return favicon_info; + return favicon_info_ptr; } void FaviconCache::UpdateFaviconVisitTime(const GURL& icon_url, base::Time time) { DCHECK_EQ(recent_favicons_.size(), synced_favicons_.size()); - FaviconMap::const_iterator iter = synced_favicons_.find(icon_url); + auto iter = synced_favicons_.find(icon_url); DCHECK(iter != synced_favicons_.end()); if (iter->second->last_visit_time >= time) return; // Erase, update the time, then re-insert to maintain ordering. - recent_favicons_.erase(iter->second); + recent_favicons_.erase(iter->second.get()); DVLOG(1) << "Updating " << icon_url.spec() << " visit time to " << syncer::GetTimeDebugString(time); iter->second->last_visit_time = time; - recent_favicons_.insert(iter->second); + recent_favicons_.insert(iter->second.get()); if (VLOG_IS_ON(2)) { - for (auto iter = recent_favicons_.begin(); iter != recent_favicons_.end(); - ++iter) { - DVLOG(2) << "Favicon " << iter->get()->favicon_url.spec() << ": " - << syncer::GetTimeDebugString(iter->get()->last_visit_time); + for (const auto* icon : recent_favicons_) { + DVLOG(2) << "Favicon " << icon->favicon_url.spec() << ": " + << syncer::GetTimeDebugString(icon->last_visit_time); } } DCHECK_EQ(recent_favicons_.size(), synced_favicons_.size()); @@ -717,7 +715,7 @@ void FaviconCache::ExpireFaviconsIfNecessary( // already in recency order, so just start from the beginning. // TODO(zea): to reduce thrashing, consider removing more than the minimum. while (recent_favicons_.size() > max_sync_favicon_limit_) { - linked_ptr<SyncedFaviconInfo> candidate = *recent_favicons_.begin(); + SyncedFaviconInfo* candidate = *recent_favicons_.begin(); DVLOG(1) << "Expiring favicon " << candidate->favicon_url.spec(); DeleteSyncedFavicon(synced_favicons_.find(candidate->favicon_url), image_changes, @@ -740,7 +738,7 @@ void FaviconCache::MergeSyncFavicon(const syncer::SyncData& sync_favicon, DCHECK(type == syncer::FAVICON_IMAGES || type == syncer::FAVICON_TRACKING); sync_pb::EntitySpecifics new_specifics; GURL favicon_url = GetFaviconURLFromSpecifics(sync_favicon.GetSpecifics()); - FaviconMap::const_iterator iter = synced_favicons_.find(favicon_url); + auto iter = synced_favicons_.find(favicon_url); DCHECK(iter != synced_favicons_.end()); SyncedFaviconInfo* favicon_info = iter->second.get(); if (type == syncer::FAVICON_IMAGES) { @@ -910,7 +908,7 @@ void FaviconCache::DeleteSyncedFavicon( FaviconMap::iterator favicon_iter, syncer::SyncChangeList* image_changes, syncer::SyncChangeList* tracking_changes) { - linked_ptr<SyncedFaviconInfo> favicon_info = favicon_iter->second; + SyncedFaviconInfo* favicon_info = favicon_iter->second.get(); if (FaviconInfoHasImages(*(favicon_iter->second))) { DVLOG(1) << "Deleting image for " << favicon_iter->second.get()->favicon_url; @@ -937,10 +935,9 @@ void FaviconCache::DeleteSyncedFavicon( void FaviconCache::DropSyncedFavicon(FaviconMap::iterator favicon_iter) { DVLOG(1) << "Dropping favicon " << favicon_iter->second.get()->favicon_url; const GURL& url = favicon_iter->first; - recent_favicons_.erase(favicon_iter->second); - base::EraseIf(page_favicon_map_, [url](const PageFaviconMap::value_type& kv) { - return kv.second == url; - }); + recent_favicons_.erase(favicon_iter->second.get()); + base::EraseIf(page_favicon_map_, + [url](const auto& kv) { return kv.second == url; }); synced_favicons_.erase(favicon_iter); } @@ -976,10 +973,10 @@ void FaviconCache::DropPartialFavicon(FaviconMap::iterator favicon_iter, DCHECK_EQ(type, syncer::FAVICON_TRACKING); DVLOG(1) << "Dropping favicon tracking " << favicon_iter->second.get()->favicon_url; - recent_favicons_.erase(favicon_iter->second); + recent_favicons_.erase(favicon_iter->second.get()); favicon_iter->second->last_visit_time = base::Time(); favicon_iter->second->is_bookmarked = false; - recent_favicons_.insert(favicon_iter->second); + recent_favicons_.insert(favicon_iter->second.get()); DCHECK(!FaviconInfoHasTracking(*favicon_iter->second)); } } diff --git a/chromium/components/sync_sessions/favicon_cache.h b/chromium/components/sync_sessions/favicon_cache.h index 378b15d54b8..292636af11c 100644 --- a/chromium/components/sync_sessions/favicon_cache.h +++ b/chromium/components/sync_sessions/favicon_cache.h @@ -17,7 +17,6 @@ #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "base/memory/ref_counted_memory.h" #include "base/memory/weak_ptr.h" @@ -118,19 +117,14 @@ class FaviconCache : public syncer::SyncableService, // Functor for ordering SyncedFaviconInfo objects by recency; struct FaviconRecencyFunctor { - bool operator()(const linked_ptr<SyncedFaviconInfo>& lhs, - const linked_ptr<SyncedFaviconInfo>& rhs) const; + bool operator()(const SyncedFaviconInfo* lhs, + const SyncedFaviconInfo* rhs) const; }; // Map of favicon url to favicon image. - using FaviconMap = std::map<GURL, linked_ptr<SyncedFaviconInfo>>; - using RecencySet = - std::set<linked_ptr<SyncedFaviconInfo>, FaviconRecencyFunctor>; - // Map of page url to task id (for favicon loading). - using PageTaskMap = std::map<GURL, base::CancelableTaskTracker::TaskId>; - // Map of page url to favicon url. - using PageFaviconMap = std::map<GURL, GURL>; + using FaviconMap = std::map<GURL, std::unique_ptr<SyncedFaviconInfo>>; + using RecencySet = std::set<SyncedFaviconInfo*, FaviconRecencyFunctor>; // Callback method to store a tab's favicon into its sync node once it becomes // available. Does nothing if no favicon data was available. @@ -153,8 +147,8 @@ class FaviconCache : public syncer::SyncableService, // |synced_favicons_| and |recent_favicons_| and returns it. SyncedFaviconInfo* GetFaviconInfo(const GURL& icon_url); - // Updates the last visit time for the favicon at |icon_url| to |time| (and - // correspondly updates position in |recent_favicons_|. + // Updates the last visit time for the favicon at |icon_url| to |time| and + // correspondingly updates position in |recent_favicons_|. void UpdateFaviconVisitTime(const GURL& icon_url, base::Time time); // Expiration method. Looks through |recent_favicons_| to find any favicons @@ -205,21 +199,21 @@ class FaviconCache : public syncer::SyncableService, favicon::FaviconService* favicon_service_; - // Trask tracker for loading favicons. + // Task tracker for loading favicons. base::CancelableTaskTracker cancelable_task_tracker_; - // Our actual cached favicon data. + // Our actual cached favicon data. Owns the favicons. FaviconMap synced_favicons_; // An LRU ordering of the favicons comprising |synced_favicons_| (oldest to // newest). RecencySet recent_favicons_; - // Our set of pending favicon loads, indexed by page url. - PageTaskMap page_task_map_; + // Pending favicon loads, map of page url to task id. + std::map<GURL, base::CancelableTaskTracker::TaskId> page_task_map_; - // Map of page and associated favicon urls. - PageFaviconMap page_favicon_map_; + // Map of page url to favicon url. + std::map<GURL, GURL> page_favicon_map_; // TODO(zea): consider creating a favicon handler here for fetching unsynced // favicons from the web. diff --git a/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc b/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc index 856fd9cf670..495e6a0d638 100644 --- a/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc +++ b/chromium/components/sync_sessions/lost_navigations_recorder_unittest.cc @@ -7,8 +7,8 @@ #include <memory> #include <string> -#include "base/message_loop/message_loop.h" #include "base/test/metrics/histogram_tester.h" +#include "base/test/scoped_task_environment.h" #include "components/sync/syncable/entry.h" #include "components/sync/syncable/mutable_entry.h" #include "components/sync/syncable/syncable_base_transaction.h" @@ -121,7 +121,7 @@ class LostNavigationsRecorderTest : public testing::Test { } private: - base::MessageLoop message_loop; + base::test::ScopedTaskEnvironment task_environment_; int _id; LostNavigationsRecorder recorder_; syncer::TestDirectorySetterUpper dir_maker_; diff --git a/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc new file mode 100644 index 00000000000..ca6743edc49 --- /dev/null +++ b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.cc @@ -0,0 +1,95 @@ +// 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 "components/sync_sessions/proxy_tabs_data_type_controller.h" + +#include <utility> + +#include "base/values.h" +#include "components/sync/driver/configure_context.h" +#include "components/sync/engine/model_safe_worker.h" +#include "components/sync/engine/model_type_configurer.h" +#include "components/sync/model/sync_merge_result.h" + +namespace sync_sessions { + +ProxyTabsDataTypeController::ProxyTabsDataTypeController( + const base::RepeatingCallback<void(State)>& state_changed_cb) + : DataTypeController(syncer::PROXY_TABS), + state_changed_cb_(state_changed_cb), + state_(NOT_RUNNING) {} + +ProxyTabsDataTypeController::~ProxyTabsDataTypeController() {} + +bool ProxyTabsDataTypeController::ShouldLoadModelBeforeConfigure() const { + return false; +} + +void ProxyTabsDataTypeController::BeforeLoadModels( + syncer::ModelTypeConfigurer* configurer) { + // Proxy type doesn't need to be registered with ModelTypeRegistry as it + // doesn't need update handler, client doesn't expect updates of this type + // from the server. We still need to register proxy type because + // AddClientConfigParamsToMessage decides the value of tabs_datatype_enabled + // based on presence of proxy types in the set of enabled types. + configurer->RegisterDirectoryDataType(type(), syncer::GROUP_PASSIVE); +} + +void ProxyTabsDataTypeController::LoadModels( + const syncer::ConfigureContext& configure_context, + const ModelLoadCallback& model_load_callback) { + DCHECK(CalledOnValidThread()); + DCHECK_EQ(configure_context.storage_option, syncer::STORAGE_ON_DISK); + state_ = MODEL_LOADED; + state_changed_cb_.Run(state_); + model_load_callback.Run(type(), syncer::SyncError()); +} + +void ProxyTabsDataTypeController::RegisterWithBackend( + base::OnceCallback<void(bool)> set_downloaded, + syncer::ModelTypeConfigurer* configurer) {} + +void ProxyTabsDataTypeController::StartAssociating( + StartCallback start_callback) { + DCHECK(CalledOnValidThread()); + syncer::SyncMergeResult local_merge_result(type()); + syncer::SyncMergeResult syncer_merge_result(type()); + state_ = RUNNING; + state_changed_cb_.Run(state_); + std::move(start_callback) + .Run(DataTypeController::OK, local_merge_result, syncer_merge_result); +} + +void ProxyTabsDataTypeController::Stop(syncer::ShutdownReason shutdown_reason, + StopCallback callback) { + state_ = NOT_RUNNING; + state_changed_cb_.Run(state_); + std::move(callback).Run(); +} + +syncer::DataTypeController::State ProxyTabsDataTypeController::state() const { + return state_; +} + +void ProxyTabsDataTypeController::ActivateDataType( + syncer::ModelTypeConfigurer* configurer) {} + +void ProxyTabsDataTypeController::DeactivateDataType( + syncer::ModelTypeConfigurer* configurer) { + configurer->UnregisterDirectoryDataType(type()); +} + +void ProxyTabsDataTypeController::GetAllNodes(AllNodesCallback callback) { + std::move(callback).Run(type(), std::make_unique<base::ListValue>()); +} + +void ProxyTabsDataTypeController::GetStatusCounters( + StatusCountersCallback callback) { + syncer::StatusCounters counters; + std::move(callback).Run(type(), counters); +} + +void ProxyTabsDataTypeController::RecordMemoryUsageAndCountsHistograms() {} + +} // namespace sync_sessions diff --git a/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h new file mode 100644 index 00000000000..9d31df7c331 --- /dev/null +++ b/chromium/components/sync_sessions/proxy_tabs_data_type_controller.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef COMPONENTS_SYNC_SESSIONS_PROXY_TABS_DATA_TYPE_CONTROLLER_H_ +#define COMPONENTS_SYNC_SESSIONS_PROXY_TABS_DATA_TYPE_CONTROLLER_H_ + +#include <memory> +#include <string> + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "components/sync/driver/data_type_controller.h" + +namespace sync_sessions { + +// Controller for PROXY_TABS. Proxy tabs have no representation in sync, and +// therefore processor or worker. +class ProxyTabsDataTypeController : public syncer::DataTypeController { + public: + // |state_changed_cb| can be used to listen to state changes. + explicit ProxyTabsDataTypeController( + const base::RepeatingCallback<void(State)>& state_changed_cb); + ~ProxyTabsDataTypeController() override; + + // DataTypeController interface. + bool ShouldLoadModelBeforeConfigure() const override; + void BeforeLoadModels(syncer::ModelTypeConfigurer* configurer) override; + void LoadModels(const syncer::ConfigureContext& configure_context, + const ModelLoadCallback& model_load_callback) override; + void RegisterWithBackend(base::OnceCallback<void(bool)> set_downloaded, + syncer::ModelTypeConfigurer* configurer) override; + void StartAssociating(StartCallback start_callback) override; + void Stop(syncer::ShutdownReason shutdown_reason, + StopCallback callback) override; + State state() const override; + void ActivateDataType(syncer::ModelTypeConfigurer* configurer) override; + void DeactivateDataType(syncer::ModelTypeConfigurer* configurer) override; + void GetAllNodes(AllNodesCallback callback) override; + void GetStatusCounters(StatusCountersCallback callback) override; + void RecordMemoryUsageAndCountsHistograms() override; + + private: + const base::RepeatingCallback<void(State)> state_changed_cb_; + State state_; + + DISALLOW_COPY_AND_ASSIGN(ProxyTabsDataTypeController); +}; + +} // namespace sync_sessions + +#endif // COMPONENTS_SYNC_SESSIONS_PROXY_TABS_DATA_TYPE_CONTROLLER_H_ diff --git a/chromium/components/sync_sessions/session_store.cc b/chromium/components/sync_sessions/session_store.cc index 35885a8aad2..d91625e0547 100644 --- a/chromium/components/sync_sessions/session_store.cc +++ b/chromium/components/sync_sessions/session_store.cc @@ -244,7 +244,8 @@ std::string SessionStore::WriteBatch::PutAndUpdateTracker( return PutWithoutUpdatingTracker(specifics); } -void SessionStore::WriteBatch::DeleteForeignEntityAndUpdateTracker( +std::vector<std::string> +SessionStore::WriteBatch::DeleteForeignEntityAndUpdateTracker( const std::string& storage_key) { std::string session_tag; int tab_node_id; @@ -252,11 +253,23 @@ void SessionStore::WriteBatch::DeleteForeignEntityAndUpdateTracker( DCHECK(success); DCHECK_NE(session_tag, session_tracker_->GetLocalSessionTag()); + std::vector<std::string> deleted_storage_keys; + deleted_storage_keys.push_back(storage_key); + if (tab_node_id == TabNodePool::kInvalidTabNodeID) { - // Removal of a foreign header entity. - // TODO(mastiz): This cascades with the removal of tabs too. Should we - // reflect this as batch_->DeleteData()? The old code didn't, presumably - // because we expect the rest of the removals to follow. + // Removal of a foreign header entity cascades the deletion of all tabs in + // the same session too. + for (int cascading_tab_node_id : + session_tracker_->LookupTabNodeIds(session_tag)) { + std::string tab_storage_key = + GetTabStorageKey(session_tag, cascading_tab_node_id); + // Note that DeleteForeignSession() below takes care of removing all tabs + // from the tracker, so no DeleteForeignTab() needed. + batch_->DeleteData(tab_storage_key); + deleted_storage_keys.push_back(std::move(tab_storage_key)); + } + + // Delete session itself. session_tracker_->DeleteForeignSession(session_tag); } else { // Removal of a foreign tab entity. @@ -264,6 +277,7 @@ void SessionStore::WriteBatch::DeleteForeignEntityAndUpdateTracker( } batch_->DeleteData(storage_key); + return deleted_storage_keys; } std::string SessionStore::WriteBatch::PutWithoutUpdatingTracker( diff --git a/chromium/components/sync_sessions/session_store.h b/chromium/components/sync_sessions/session_store.h index db2746332e2..80d95446476 100644 --- a/chromium/components/sync_sessions/session_store.h +++ b/chromium/components/sync_sessions/session_store.h @@ -94,10 +94,13 @@ class SessionStore { SyncedSessionTracker* session_tracker); ~WriteBatch(); - // Most mutations below return a storage key. + // Most mutations below return storage keys. std::string PutAndUpdateTracker(const sync_pb::SessionSpecifics& specifics, base::Time modification_time); - void DeleteForeignEntityAndUpdateTracker(const std::string& storage_key); + // Returns all deleted storage keys, which may be more than one if + // |storage_key| refers to a header entity. + std::vector<std::string> DeleteForeignEntityAndUpdateTracker( + const std::string& storage_key); // The functions below do not update SyncedSessionTracker and hence it is // the caller's responsibility to do so *before* calling these functions. std::string PutWithoutUpdatingTracker( diff --git a/chromium/components/sync_sessions/session_store_unittest.cc b/chromium/components/sync_sessions/session_store_unittest.cc index 2a4aab806d3..1517cce4313 100644 --- a/chromium/components/sync_sessions/session_store_unittest.cc +++ b/chromium/components/sync_sessions/session_store_unittest.cc @@ -9,9 +9,9 @@ #include <vector> #include "base/bind_helpers.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_task_environment.h" #include "components/prefs/testing_pref_service.h" #include "components/sync/base/hash_util.h" #include "components/sync/device_info/device_info.h" @@ -180,7 +180,7 @@ class SessionStoreFactoryTest : public ::testing::Test { ~SessionStoreFactoryTest() override {} - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; const syncer::DeviceInfo local_device_info_; TestingPrefServiceSimple pref_service_; SessionSyncPrefs session_sync_prefs_; @@ -497,6 +497,140 @@ TEST_F(SessionStoreTest, ShouldWriteAndRestoreForeignData) { /*urls=*/_))))); } +TEST_F(SessionStoreTest, ShouldDeleteForeignData) { + const std::string kForeignSessionTag = "SomeForeignTag"; + const int kWindowId = 5; + const int kTabId1 = 7; + const int kTabId2 = 8; + const int kTabNodeId1 = 1; + const int kTabNodeId2 = 2; + + EXPECT_CALL(mock_restored_foreign_tab_callback_, Run(_, _)).Times(0); + + const std::string local_header_storage_key = + SessionStore::GetHeaderStorageKey(kLocalSessionTag); + + // Local session is automatically created. + ASSERT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()), + ElementsAre(Pair(local_header_storage_key, _))); + ASSERT_THAT(ReadAllPersistedDataFrom(underlying_store_.get()), IsEmpty()); + + // Populate with foreign data: one header entity and two tabs. + SessionSpecifics header; + header.set_session_tag(kForeignSessionTag); + header.mutable_header()->add_window()->set_window_id(kWindowId); + header.mutable_header()->mutable_window(0)->add_tab(kTabId1); + header.mutable_header()->mutable_window(0)->add_tab(kTabId2); + ASSERT_TRUE(SessionStore::AreValidSpecifics(header)); + + SessionSpecifics tab1; + tab1.set_session_tag(kForeignSessionTag); + tab1.set_tab_node_id(kTabNodeId1); + tab1.mutable_tab()->set_window_id(kWindowId); + tab1.mutable_tab()->set_tab_id(kTabId1); + ASSERT_TRUE(SessionStore::AreValidSpecifics(tab1)); + + SessionSpecifics tab2; + tab2.set_session_tag(kForeignSessionTag); + tab2.set_tab_node_id(kTabNodeId2); + tab2.mutable_tab()->set_window_id(kWindowId); + tab2.mutable_tab()->set_tab_id(kTabId2); + ASSERT_TRUE(SessionStore::AreValidSpecifics(tab2)); + + const std::string header_storage_key = + SessionStore::GetHeaderStorageKey(kForeignSessionTag); + const std::string tab_storage_key1 = + SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId1); + const std::string tab_storage_key2 = + SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId2); + + // Write data and update the tracker. + { + std::unique_ptr<SessionStore::WriteBatch> batch = + session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing()); + ASSERT_THAT(batch, NotNull()); + batch->PutAndUpdateTracker(header, base::Time::Now()); + batch->PutAndUpdateTracker(tab1, base::Time::Now()); + batch->PutAndUpdateTracker(tab2, base::Time::Now()); + + sync_pb::EntityMetadata header_metadata; + header_metadata.set_server_id("someserverid1"); + batch->GetMetadataChangeList()->UpdateMetadata(header_storage_key, + header_metadata); + + sync_pb::EntityMetadata tab1_metadata; + tab1_metadata.set_server_id("someserverid2"); + batch->GetMetadataChangeList()->UpdateMetadata(tab_storage_key1, + tab1_metadata); + + sync_pb::EntityMetadata tab2_metadata; + tab2_metadata.set_server_id("someserverid3"); + batch->GetMetadataChangeList()->UpdateMetadata(tab_storage_key2, + tab2_metadata); + SessionStore::WriteBatch::Commit(std::move(batch)); + } + + // Verify the underlying storage contains the data. + ASSERT_THAT( + ReadAllPersistedDataFrom(underlying_store_.get()), + UnorderedElementsAre( + Pair(header_storage_key, + MatchesHeader(kForeignSessionTag, {kWindowId}, + {kTabId1, kTabId2})), + Pair(tab_storage_key1, + MatchesTab(kForeignSessionTag, kWindowId, kTabId1, kTabNodeId1, + /*urls=*/_)), + Pair(tab_storage_key2, + MatchesTab(kForeignSessionTag, kWindowId, kTabId2, kTabNodeId2, + /*urls=*/_)))); + + // Verify tracker exposes the foreign tabs. + ASSERT_THAT(session_store()->tracker()->LookupAllForeignSessions( + SyncedSessionTracker::RAW), + ElementsAre(MatchesSyncedSession( + kForeignSessionTag, + {{kWindowId, std::vector<int>{kTabId1, kTabId2}}}))); + + // Mimic receiving a tab deletion for |tab1|, which should only affect that + // entity. + { + std::unique_ptr<SessionStore::WriteBatch> batch = + session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing()); + + EXPECT_THAT(batch->DeleteForeignEntityAndUpdateTracker(tab_storage_key1), + ElementsAre(tab_storage_key1)); + + SessionStore::WriteBatch::Commit(std::move(batch)); + } + + EXPECT_THAT( + ReadAllPersistedDataFrom(underlying_store_.get()), + UnorderedElementsAre( + Pair(header_storage_key, + MatchesHeader(kForeignSessionTag, {kWindowId}, + {kTabId1, kTabId2})), + Pair(tab_storage_key2, + MatchesTab(kForeignSessionTag, kWindowId, kTabId2, kTabNodeId2, + /*urls=*/_)))); + + // Mimic receiving a header deletion (which should delete all remaining + // entities for that session). + { + std::unique_ptr<SessionStore::WriteBatch> batch = + session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing()); + + EXPECT_THAT(batch->DeleteForeignEntityAndUpdateTracker(header_storage_key), + ElementsAre(header_storage_key, tab_storage_key2)); + + SessionStore::WriteBatch::Commit(std::move(batch)); + } + + EXPECT_THAT(session_store()->tracker()->LookupAllForeignSessions( + SyncedSessionTracker::RAW), + IsEmpty()); + EXPECT_THAT(ReadAllPersistedDataFrom(underlying_store_.get()), IsEmpty()); +} + TEST_F(SessionStoreTest, ShouldReturnForeignUnmappedTabs) { const std::string kForeignSessionTag = "SomeForeignTag"; const int kWindowId = 5; diff --git a/chromium/components/sync_sessions/session_sync_bridge.cc b/chromium/components/sync_sessions/session_sync_bridge.cc index 68b83d5b8ed..b9956b5b004 100644 --- a/chromium/components/sync_sessions/session_sync_bridge.cc +++ b/chromium/components/sync_sessions/session_sync_bridge.cc @@ -211,7 +211,16 @@ base::Optional<syncer::ModelError> SessionSyncBridge::ApplySyncChanges( << "local navigation event."; syncing_->local_data_out_of_sync = true; } else { - batch->DeleteForeignEntityAndUpdateTracker(change.storage_key()); + // Deleting an entity (if it's a header entity) may cascade other + // deletions, so let's assume that whoever initiated remote deletions + // must have taken care of deleting them all. We don't have to commit + // these deletions, simply delete all local sync metadata (untrack). + for (const std::string& deleted_storage_key : + batch->DeleteForeignEntityAndUpdateTracker( + change.storage_key())) { + change_processor()->UntrackEntityForStorageKey(deleted_storage_key); + metadata_change_list->ClearMetadata(deleted_storage_key); + } } break; case syncer::EntityChange::ACTION_ADD: @@ -434,21 +443,14 @@ void SessionSyncBridge::DeleteForeignSessionWithBatch( return; } - // Delete tabs. - for (int tab_node_id : - syncing_->store->tracker()->LookupTabNodeIds(session_tag)) { - const std::string tab_storage_key = - SessionStore::GetTabStorageKey(session_tag, tab_node_id); - batch->DeleteForeignEntityAndUpdateTracker(tab_storage_key); - change_processor()->Delete(tab_storage_key, batch->GetMetadataChangeList()); - } - - // Delete header. + // Deleting the header entity cascades the deletions of tabs as well. const std::string header_storage_key = SessionStore::GetHeaderStorageKey(session_tag); - batch->DeleteForeignEntityAndUpdateTracker(header_storage_key); - change_processor()->Delete(header_storage_key, - batch->GetMetadataChangeList()); + for (const std::string& deleted_storage_key : + batch->DeleteForeignEntityAndUpdateTracker(header_storage_key)) { + change_processor()->Delete(deleted_storage_key, + batch->GetMetadataChangeList()); + } notify_foreign_session_updated_cb_.Run(); } diff --git a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc index c9ac15f2213..47a81ffcf9d 100644 --- a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc +++ b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc @@ -11,11 +11,11 @@ #include "base/bind_helpers.h" #include "base/json/json_writer.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "base/test/bind_test_util.h" #include "base/test/mock_callback.h" +#include "base/test/scoped_task_environment.h" #include "components/prefs/testing_pref_service.h" #include "components/sync/base/hash_util.h" #include "components/sync/base/sync_prefs.h" @@ -323,8 +323,10 @@ class SessionSyncBridgeTest : public ::testing::Test { return real_processor_.get(); } + syncer::ModelTypeStore* underlying_store() { return store_.get(); } + private: - base::MessageLoop message_loop_; + base::test::ScopedTaskEnvironment task_environment_; const syncer::DeviceInfo local_device_info_; const std::unique_ptr<syncer::ModelTypeStore> store_; @@ -1139,6 +1141,17 @@ TEST_F(SessionSyncBridgeTest, ShouldHandleRemoteDeletion) { kForeignTabNodeId, "http://baz.com/"); StartSyncing({foreign_header, foreign_tab}); + sync_pb::ModelTypeState state; + state.set_initial_sync_done(true); + + // Mimic receiving a commit ack for the local header entity, to later be able + // to verify HasLocalChangesForTest() without interferences from the local + // session. + ASSERT_TRUE(real_processor()->HasLocalChangesForTest()); + real_processor()->OnCommitCompleted( + state, {CreateSuccessResponse(kLocalSessionTag)}); + ASSERT_FALSE(real_processor()->HasLocalChangesForTest()); + const sessions::SessionTab* foreign_session_tab = nullptr; ASSERT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetForeignTab( kForeignSessionTag, SessionID::FromSerializedValue(kForeignTabId), @@ -1152,11 +1165,13 @@ TEST_F(SessionSyncBridgeTest, ShouldHandleRemoteDeletion) { kForeignSessionTag, {{kForeignWindowId, std::vector<int>{kForeignTabId}}}))); ASSERT_TRUE(real_processor()->IsTrackingMetadata()); + ASSERT_TRUE(real_processor()->IsTrackingEntityForTest( + SessionStore::GetHeaderStorageKey(kForeignSessionTag))); + ASSERT_TRUE(real_processor()->IsTrackingEntityForTest( + SessionStore::GetTabStorageKey(kForeignSessionTag, kForeignTabNodeId))); + ASSERT_FALSE(real_processor()->HasLocalChangesForTest()); // Mimic receiving a remote deletion of the foreign session. - sync_pb::ModelTypeState state; - state.set_initial_sync_done(true); - EXPECT_CALL(mock_foreign_session_updated_cb(), Run()); real_processor()->OnUpdateReceived( state, {CreateTombstone(SessionStore::GetClientTag(foreign_header))}); @@ -1168,6 +1183,51 @@ TEST_F(SessionSyncBridgeTest, ShouldHandleRemoteDeletion) { EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions( &foreign_sessions)); + + EXPECT_FALSE(real_processor()->HasLocalChangesForTest()); + + const std::string header_storage_key = + SessionStore::GetHeaderStorageKey(kForeignSessionTag); + const std::string tab_storage_key = + SessionStore::GetTabStorageKey(kForeignSessionTag, kForeignTabNodeId); + + EXPECT_FALSE(real_processor()->IsTrackingEntityForTest(header_storage_key)); + EXPECT_FALSE(real_processor()->IsTrackingEntityForTest(tab_storage_key)); + + // Verify that both entities have been deleted from storage. + { + base::RunLoop loop; + underlying_store()->ReadData( + {header_storage_key, tab_storage_key}, + base::BindLambdaForTesting( + [&](const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::ModelTypeStore::RecordList> + data_records, + std::unique_ptr<syncer::ModelTypeStore::IdList> + missing_id_list) { + EXPECT_THAT(data_records, Pointee(IsEmpty())); + EXPECT_THAT( + missing_id_list, + Pointee(ElementsAre(header_storage_key, tab_storage_key))); + loop.Quit(); + })); + loop.Run(); + } + + // Verify that the sync metadata for both entities have been deleted too. + { + base::RunLoop loop; + underlying_store()->ReadAllMetadata(base::BindLambdaForTesting( + [&](const base::Optional<syncer::ModelError>& error, + std::unique_ptr<syncer::MetadataBatch> metadata_batch) { + syncer::EntityMetadataMap entity_metadata_map = + metadata_batch->TakeAllMetadata(); + EXPECT_EQ(0U, entity_metadata_map.count(header_storage_key)); + EXPECT_EQ(0U, entity_metadata_map.count(tab_storage_key)); + loop.Quit(); + })); + loop.Run(); + } } TEST_F(SessionSyncBridgeTest, ShouldIgnoreRemoteDeletionOfLocalTab) { diff --git a/chromium/components/sync_sessions/session_sync_test_helper.cc b/chromium/components/sync_sessions/session_sync_test_helper.cc index 205364e8d16..8d301b723a4 100644 --- a/chromium/components/sync_sessions/session_sync_test_helper.cc +++ b/chromium/components/sync_sessions/session_sync_test_helper.cc @@ -88,23 +88,22 @@ void SessionSyncTestHelper::VerifySyncedSession( } } -void SessionSyncTestHelper::BuildTabSpecifics( +sync_pb::SessionSpecifics SessionSyncTestHelper::BuildTabSpecifics( const std::string& tag, SessionID window_id, - SessionID tab_id, - sync_pb::SessionSpecifics* tab_base) { - BuildTabSpecifics(tag, window_id, tab_id, ++max_tab_node_id_, tab_base); + SessionID tab_id) { + return BuildTabSpecifics(tag, window_id, tab_id, ++max_tab_node_id_); } -void SessionSyncTestHelper::BuildTabSpecifics( +sync_pb::SessionSpecifics SessionSyncTestHelper::BuildTabSpecifics( const std::string& tag, SessionID window_id, SessionID tab_id, - int tab_node_id, - sync_pb::SessionSpecifics* tab_base) { - tab_base->set_session_tag(tag); - tab_base->set_tab_node_id(tab_node_id); - sync_pb::SessionTab* tab = tab_base->mutable_tab(); + int tab_node_id) { + sync_pb::SessionSpecifics specifics; + specifics.set_session_tag(tag); + specifics.set_tab_node_id(tab_node_id); + sync_pb::SessionTab* tab = specifics.mutable_tab(); tab->set_tab_id(tab_id.id()); tab->set_tab_visual_index(1); tab->set_current_navigation_index(0); @@ -115,6 +114,7 @@ void SessionSyncTestHelper::BuildTabSpecifics( navigation->set_referrer(kReferrer); navigation->set_title(kTitle); navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED); + return specifics; } void SessionSyncTestHelper::Reset() { @@ -125,19 +125,19 @@ sync_pb::SessionSpecifics SessionSyncTestHelper::BuildForeignSession( const std::string& tag, const std::vector<SessionID>& tab_list, std::vector<sync_pb::SessionSpecifics>* tabs) { - sync_pb::SessionSpecifics meta; - BuildSessionSpecifics(tag, &meta); - AddWindowSpecifics(SessionID::FromSerializedValue(1), tab_list, &meta); - std::vector<sync_pb::SessionSpecifics> tabs1; - tabs1.resize(tab_list.size()); - for (size_t i = 0; i < tab_list.size(); ++i) { - BuildTabSpecifics(tag, SessionID::FromSerializedValue(1), tab_list[i], - &tabs1[i]); + const SessionID window_id = SessionID::FromSerializedValue(1); + sync_pb::SessionSpecifics header; + BuildSessionSpecifics(tag, &header); + AddWindowSpecifics(window_id, tab_list, &header); + + if (tabs) { + tabs->clear(); + for (SessionID tab_id : tab_list) { + tabs->push_back(BuildTabSpecifics(tag, window_id, tab_id)); + } } - if (tabs) - tabs->swap(tabs1); - return meta; + return header; } } // namespace sync_sessions diff --git a/chromium/components/sync_sessions/session_sync_test_helper.h b/chromium/components/sync_sessions/session_sync_test_helper.h index 97360aafa22..e5068c3dc64 100644 --- a/chromium/components/sync_sessions/session_sync_test_helper.h +++ b/chromium/components/sync_sessions/session_sync_test_helper.h @@ -38,18 +38,16 @@ class SessionSyncTestHelper { // Build a SessionSpecifics object with a tab and sample data. Uses a // monotonically increasing variable to generate tab_node_ids and avoid // conflicts. - void BuildTabSpecifics(const std::string& tag, - SessionID window_id, - SessionID tab_id, - sync_pb::SessionSpecifics* tab_base); + sync_pb::SessionSpecifics BuildTabSpecifics(const std::string& tag, + SessionID window_id, + SessionID tab_id); // Overload of BuildTabSpecifics to allow forcing a specific tab_node_id. // Typically only useful to test reusing tab_node_ids. - void BuildTabSpecifics(const std::string& tag, - SessionID window_id, - SessionID tab_id, - int tab_node_id, - sync_pb::SessionSpecifics* tab_base); + sync_pb::SessionSpecifics BuildTabSpecifics(const std::string& tag, + SessionID window_id, + SessionID tab_id, + int tab_node_id); sync_pb::SessionSpecifics BuildForeignSession( const std::string& tag, |