1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/sync/sessions/sync_session.h" 6 7 #include "base/memory/ref_counted.h" 8 #include "chrome/browser/sync/engine/conflict_resolver.h" 9 #include "chrome/browser/sync/engine/mock_model_safe_workers.h" 10 #include "chrome/browser/sync/engine/syncer_types.h" 11 #include "chrome/browser/sync/engine/syncer_util.h" 12 #include "chrome/browser/sync/syncable/directory_manager.h" 13 #include "chrome/browser/sync/syncable/model_type.h" 14 #include "chrome/browser/sync/syncable/syncable.h" 15 #include "chrome/test/sync/engine/test_directory_setter_upper.h" 16 #include "testing/gtest/include/gtest/gtest.h" 17 18 using syncable::WriteTransaction; 19 20 namespace browser_sync { 21 namespace sessions { 22 namespace { 23 24 class SyncSessionTest : public testing::Test, 25 public SyncSession::Delegate, 26 public ModelSafeWorkerRegistrar { 27 public: 28 SyncSessionTest() : controller_invocations_allowed_(false) { 29 GetModelSafeRoutingInfo(&routes_); 30 } 31 32 SyncSession* MakeSession() { 33 return new SyncSession(context_.get(), this, SyncSourceInfo(), routes_, 34 std::vector<ModelSafeWorker*>()); 35 } 36 37 virtual void SetUp() { 38 context_.reset(new SyncSessionContext(NULL, NULL, this, 39 std::vector<SyncEngineEventListener*>())); 40 routes_.clear(); 41 routes_[syncable::BOOKMARKS] = GROUP_UI; 42 routes_[syncable::AUTOFILL] = GROUP_UI; 43 session_.reset(MakeSession()); 44 } 45 virtual void TearDown() { 46 session_.reset(); 47 context_.reset(); 48 } 49 50 virtual void OnSilencedUntil(const base::TimeTicks& silenced_until) { 51 FailControllerInvocationIfDisabled("OnSilencedUntil"); 52 } 53 virtual bool IsSyncingCurrentlySilenced() { 54 FailControllerInvocationIfDisabled("IsSyncingCurrentlySilenced"); 55 return false; 56 } 57 virtual void OnReceivedLongPollIntervalUpdate( 58 const base::TimeDelta& new_interval) { 59 FailControllerInvocationIfDisabled("OnReceivedLongPollIntervalUpdate"); 60 } 61 virtual void OnReceivedShortPollIntervalUpdate( 62 const base::TimeDelta& new_interval) { 63 FailControllerInvocationIfDisabled("OnReceivedShortPollIntervalUpdate"); 64 } 65 virtual void OnShouldStopSyncingPermanently() { 66 FailControllerInvocationIfDisabled("OnShouldStopSyncingPermanently"); 67 } 68 69 // ModelSafeWorkerRegistrar implementation. 70 virtual void GetWorkers(std::vector<ModelSafeWorker*>* out) {} 71 virtual void GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) { 72 out->swap(routes_); 73 } 74 75 StatusController* status() { return session_->status_controller(); } 76 protected: 77 void FailControllerInvocationIfDisabled(const std::string& msg) { 78 if (!controller_invocations_allowed_) 79 FAIL() << msg; 80 } 81 82 syncable::ModelTypeBitSet ParamsMeaningAllEnabledTypes() { 83 syncable::ModelTypeBitSet request_params; 84 request_params[syncable::BOOKMARKS] = true; 85 request_params[syncable::AUTOFILL] = true; 86 return request_params; 87 } 88 89 syncable::ModelTypeBitSet ParamsMeaningJustOneEnabledType() { 90 syncable::ModelTypeBitSet request_params; 91 request_params[syncable::AUTOFILL] = true; 92 return request_params; 93 } 94 95 bool controller_invocations_allowed_; 96 scoped_ptr<SyncSession> session_; 97 scoped_ptr<SyncSessionContext> context_; 98 ModelSafeRoutingInfo routes_; 99 }; 100 101 TEST_F(SyncSessionTest, ScopedContextHelpers) { 102 ConflictResolver resolver; 103 EXPECT_FALSE(context_->resolver()); 104 { 105 ScopedSessionContextConflictResolver s_resolver(context_.get(), &resolver); 106 EXPECT_EQ(&resolver, context_->resolver()); 107 } 108 EXPECT_FALSE(context_->resolver()); 109 } 110 111 TEST_F(SyncSessionTest, SetWriteTransaction) { 112 TestDirectorySetterUpper db; 113 db.SetUp(); 114 session_.reset(); 115 context_.reset(new SyncSessionContext(NULL, db.manager(), this, 116 std::vector<SyncEngineEventListener*>())); 117 session_.reset(MakeSession()); 118 context_->set_account_name(db.name()); 119 syncable::ScopedDirLookup dir(context_->directory_manager(), 120 context_->account_name()); 121 ASSERT_TRUE(dir.good()); 122 123 scoped_ptr<SyncSession> session(MakeSession()); 124 EXPECT_TRUE(NULL == session->write_transaction()); 125 { 126 WriteTransaction trans(dir, syncable::UNITTEST, __FILE__, __LINE__); 127 sessions::ScopedSetSessionWriteTransaction set_trans(session.get(), &trans); 128 EXPECT_TRUE(&trans == session->write_transaction()); 129 } 130 db.TearDown(); 131 } 132 133 TEST_F(SyncSessionTest, MoreToSyncIfUnsyncedGreaterThanCommitted) { 134 // If any forward progress was made during the session, and the number of 135 // unsynced handles still exceeds the number of commit ids we added, there is 136 // more to sync. For example, this occurs if we had more commit ids 137 // than could fit in a single commit batch. 138 EXPECT_FALSE(session_->HasMoreToSync()); 139 OrderedCommitSet commit_set(routes_); 140 commit_set.AddCommitItem(0, syncable::Id(), syncable::BOOKMARKS); 141 status()->set_commit_set(commit_set); 142 EXPECT_FALSE(session_->HasMoreToSync()); 143 144 std::vector<int64> unsynced_handles; 145 unsynced_handles.push_back(1); 146 unsynced_handles.push_back(2); 147 status()->set_unsynced_handles(unsynced_handles); 148 EXPECT_FALSE(session_->HasMoreToSync()); 149 status()->increment_num_successful_commits(); 150 EXPECT_TRUE(session_->HasMoreToSync()); 151 } 152 153 TEST_F(SyncSessionTest, MoreToSyncIfConflictSetsBuilt) { 154 // If we built conflict sets, then we need to loop back and try 155 // to get updates & commit again. 156 status()->update_conflict_sets_built(true); 157 EXPECT_TRUE(session_->HasMoreToSync()); 158 } 159 160 TEST_F(SyncSessionTest, MoreToDownloadIfDownloadFailed) { 161 status()->set_updates_request_types(ParamsMeaningAllEnabledTypes()); 162 163 // When DownloadUpdatesCommand fails, these should be false. 164 EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload()); 165 EXPECT_FALSE(status()->download_updates_succeeded()); 166 167 // Download updates has its own loop in the syncer; it shouldn't factor 168 // into HasMoreToSync. 169 EXPECT_FALSE(session_->HasMoreToSync()); 170 } 171 172 TEST_F(SyncSessionTest, MoreToDownloadIfGotChangesRemaining) { 173 status()->set_updates_request_types(ParamsMeaningAllEnabledTypes()); 174 175 // When the server returns changes_remaining, that means there's 176 // more to download. 177 status()->mutable_updates_response()->mutable_get_updates() 178 ->set_changes_remaining(1000L); 179 EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload()); 180 EXPECT_TRUE(status()->download_updates_succeeded()); 181 182 // Download updates has its own loop in the syncer; it shouldn't factor 183 // into HasMoreToSync. 184 EXPECT_FALSE(session_->HasMoreToSync()); 185 } 186 187 TEST_F(SyncSessionTest, MoreToDownloadIfGotNoChangesRemaining) { 188 status()->set_updates_request_types(ParamsMeaningAllEnabledTypes()); 189 190 // When the server returns a timestamp, that means we're up to date. 191 status()->mutable_updates_response()->mutable_get_updates() 192 ->set_changes_remaining(0); 193 EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload()); 194 EXPECT_TRUE(status()->download_updates_succeeded()); 195 196 // Download updates has its own loop in the syncer; it shouldn't factor 197 // into HasMoreToSync. 198 EXPECT_FALSE(session_->HasMoreToSync()); 199 } 200 201 TEST_F(SyncSessionTest, MoreToDownloadIfGotNoChangesRemainingForSubset) { 202 status()->set_updates_request_types(ParamsMeaningJustOneEnabledType()); 203 204 // When the server returns a timestamp, that means we're up to date for that 205 // type. But there may still be more to download if there are other 206 // datatypes that we didn't request on this go-round. 207 status()->mutable_updates_response()->mutable_get_updates() 208 ->set_changes_remaining(0); 209 210 EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload()); 211 EXPECT_TRUE(status()->download_updates_succeeded()); 212 213 // Download updates has its own loop in the syncer; it shouldn't factor 214 // into HasMoreToSync. 215 EXPECT_FALSE(session_->HasMoreToSync()); 216 } 217 218 TEST_F(SyncSessionTest, MoreToDownloadIfGotChangesRemainingAndEntries) { 219 status()->set_updates_request_types(ParamsMeaningAllEnabledTypes()); 220 // The actual entry count should not factor into the HasMoreToSync 221 // determination. 222 status()->mutable_updates_response()->mutable_get_updates()->add_entries(); 223 status()->mutable_updates_response()->mutable_get_updates() 224 ->set_changes_remaining(1000000L);; 225 EXPECT_FALSE(status()->ServerSaysNothingMoreToDownload()); 226 EXPECT_TRUE(status()->download_updates_succeeded()); 227 228 // Download updates has its own loop in the syncer; it shouldn't factor 229 // into HasMoreToSync. 230 EXPECT_FALSE(session_->HasMoreToSync()); 231 } 232 233 TEST_F(SyncSessionTest, MoreToDownloadIfGotNoChangesRemainingAndEntries) { 234 status()->set_updates_request_types(ParamsMeaningAllEnabledTypes()); 235 // The actual entry count should not factor into the HasMoreToSync 236 // determination. 237 status()->mutable_updates_response()->mutable_get_updates()->add_entries(); 238 status()->mutable_updates_response()->mutable_get_updates() 239 ->set_changes_remaining(0); 240 EXPECT_TRUE(status()->ServerSaysNothingMoreToDownload()); 241 EXPECT_TRUE(status()->download_updates_succeeded()); 242 243 // Download updates has its own loop in the syncer; it shouldn't factor 244 // into HasMoreToSync. 245 EXPECT_FALSE(session_->HasMoreToSync()); 246 } 247 248 TEST_F(SyncSessionTest, MoreToSyncIfConflictsResolved) { 249 // Conflict resolution happens after get updates and commit, 250 // so we need to loop back and get updates / commit again now 251 // that we have made forward progress. 252 status()->update_conflicts_resolved(true); 253 EXPECT_TRUE(session_->HasMoreToSync()); 254 } 255 256 TEST_F(SyncSessionTest, ResetTransientState) { 257 status()->update_conflicts_resolved(true); 258 status()->increment_num_successful_commits(); 259 EXPECT_TRUE(session_->HasMoreToSync()); 260 session_->ResetTransientState(); 261 EXPECT_FALSE(status()->conflicts_resolved()); 262 EXPECT_FALSE(session_->HasMoreToSync()); 263 EXPECT_FALSE(status()->TestAndClearIsDirty()); 264 } 265 266 TEST_F(SyncSessionTest, Coalesce) { 267 std::vector<ModelSafeWorker*> workers_one, workers_two; 268 ModelSafeRoutingInfo routes_one, routes_two; 269 syncable::ModelTypePayloadMap one_type = 270 syncable::ModelTypePayloadMapFromBitSet( 271 ParamsMeaningJustOneEnabledType(), 272 std::string()); 273 syncable::ModelTypePayloadMap all_types = 274 syncable::ModelTypePayloadMapFromBitSet( 275 ParamsMeaningAllEnabledTypes(), 276 std::string()); 277 SyncSourceInfo source_one(sync_pb::GetUpdatesCallerInfo::PERIODIC, one_type); 278 SyncSourceInfo source_two(sync_pb::GetUpdatesCallerInfo::LOCAL, all_types); 279 280 scoped_refptr<MockDBModelWorker> db_worker(new MockDBModelWorker()); 281 scoped_refptr<MockUIModelWorker> ui_worker(new MockUIModelWorker()); 282 workers_one.push_back(db_worker); 283 workers_two.push_back(db_worker); 284 workers_two.push_back(ui_worker); 285 routes_one[syncable::AUTOFILL] = GROUP_DB; 286 routes_two[syncable::AUTOFILL] = GROUP_DB; 287 routes_two[syncable::BOOKMARKS] = GROUP_UI; 288 SyncSession one(context_.get(), this, source_one, routes_one, workers_one); 289 SyncSession two(context_.get(), this, source_two, routes_two, workers_two); 290 291 one.Coalesce(two); 292 293 EXPECT_EQ(two.source().updates_source, one.source().updates_source); 294 EXPECT_EQ(all_types, one.source().types); 295 std::vector<ModelSafeWorker*>::const_iterator it_db = 296 std::find(one.workers().begin(), one.workers().end(), db_worker); 297 std::vector<ModelSafeWorker*>::const_iterator it_ui = 298 std::find(one.workers().begin(), one.workers().end(), ui_worker); 299 EXPECT_NE(it_db, one.workers().end()); 300 EXPECT_NE(it_ui, one.workers().end()); 301 EXPECT_EQ(routes_two, one.routing_info()); 302 } 303 304 TEST_F(SyncSessionTest, MakeTypePayloadMapFromBitSet) { 305 syncable::ModelTypeBitSet types; 306 std::string payload = "test"; 307 syncable::ModelTypePayloadMap types_with_payloads = 308 syncable::ModelTypePayloadMapFromBitSet(types, 309 payload); 310 EXPECT_TRUE(types_with_payloads.empty()); 311 312 types[syncable::BOOKMARKS] = true; 313 types[syncable::PASSWORDS] = true; 314 types[syncable::AUTOFILL] = true; 315 payload = "test2"; 316 types_with_payloads = syncable::ModelTypePayloadMapFromBitSet(types, payload); 317 318 ASSERT_EQ(3U, types_with_payloads.size()); 319 EXPECT_EQ(types_with_payloads[syncable::BOOKMARKS], payload); 320 EXPECT_EQ(types_with_payloads[syncable::PASSWORDS], payload); 321 EXPECT_EQ(types_with_payloads[syncable::AUTOFILL], payload); 322 } 323 324 TEST_F(SyncSessionTest, MakeTypePayloadMapFromRoutingInfo) { 325 std::string payload = "test"; 326 syncable::ModelTypePayloadMap types_with_payloads 327 = syncable::ModelTypePayloadMapFromRoutingInfo(routes_, payload); 328 ASSERT_EQ(routes_.size(), types_with_payloads.size()); 329 for (ModelSafeRoutingInfo::iterator iter = routes_.begin(); 330 iter != routes_.end(); 331 ++iter) { 332 EXPECT_EQ(payload, types_with_payloads[iter->first]); 333 } 334 } 335 336 TEST_F(SyncSessionTest, CoalescePayloads) { 337 syncable::ModelTypePayloadMap original; 338 std::string empty_payload; 339 std::string payload1 = "payload1"; 340 std::string payload2 = "payload2"; 341 std::string payload3 = "payload3"; 342 original[syncable::BOOKMARKS] = empty_payload; 343 original[syncable::PASSWORDS] = payload1; 344 original[syncable::AUTOFILL] = payload2; 345 original[syncable::THEMES] = payload3; 346 347 syncable::ModelTypePayloadMap update; 348 update[syncable::BOOKMARKS] = empty_payload; // Same. 349 update[syncable::PASSWORDS] = empty_payload; // Overwrite with empty. 350 update[syncable::AUTOFILL] = payload1; // Overwrite with non-empty. 351 update[syncable::SESSIONS] = payload2; // New. 352 // Themes untouched. 353 354 CoalescePayloads(&original, update); 355 ASSERT_EQ(5U, original.size()); 356 EXPECT_EQ(empty_payload, original[syncable::BOOKMARKS]); 357 EXPECT_EQ(payload1, original[syncable::PASSWORDS]); 358 EXPECT_EQ(payload1, original[syncable::AUTOFILL]); 359 EXPECT_EQ(payload2, original[syncable::SESSIONS]); 360 EXPECT_EQ(payload3, original[syncable::THEMES]); 361 } 362 363 } // namespace 364 } // namespace sessions 365 } // namespace browser_sync 366