OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/sync/glue/sync_backend_host.h" | 5 #include "chrome/browser/sync/glue/sync_backend_host.h" |
6 | 6 |
7 #include <cstddef> | 7 #include <cstddef> |
8 | 8 |
9 #include "base/memory/scoped_ptr.h" | 9 #include "base/memory/scoped_ptr.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
| 11 #include "base/synchronization/waitable_event.h" |
| 12 #include "base/test/test_timeouts.h" |
11 #include "chrome/browser/sync/invalidations/invalidator_storage.h" | 13 #include "chrome/browser/sync/invalidations/invalidator_storage.h" |
12 #include "chrome/browser/sync/sync_prefs.h" | 14 #include "chrome/browser/sync/sync_prefs.h" |
13 #include "chrome/test/base/testing_profile.h" | 15 #include "chrome/test/base/testing_profile.h" |
14 #include "content/public/test/test_browser_thread.h" | 16 #include "content/public/test/test_browser_thread.h" |
15 #include "googleurl/src/gurl.h" | 17 #include "googleurl/src/gurl.h" |
16 #include "net/url_request/test_url_fetcher_factory.h" | 18 #include "net/url_request/test_url_fetcher_factory.h" |
17 #include "sync/internal_api/public/base/model_type.h" | 19 #include "sync/internal_api/public/base/model_type.h" |
18 #include "sync/internal_api/public/engine/model_safe_worker.h" | 20 #include "sync/internal_api/public/engine/model_safe_worker.h" |
| 21 #include "sync/internal_api/public/sync_manager_factory.h" |
| 22 #include "sync/internal_api/public/test/fake_sync_manager.h" |
19 #include "sync/internal_api/public/util/experiments.h" | 23 #include "sync/internal_api/public/util/experiments.h" |
20 #include "sync/protocol/encryption.pb.h" | 24 #include "sync/protocol/encryption.pb.h" |
21 #include "sync/protocol/sync_protocol_error.h" | 25 #include "sync/protocol/sync_protocol_error.h" |
22 #include "sync/util/test_unrecoverable_error_handler.h" | 26 #include "sync/util/test_unrecoverable_error_handler.h" |
23 #include "testing/gmock/include/gmock/gmock.h" | 27 #include "testing/gmock/include/gmock/gmock.h" |
24 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
25 | 29 |
26 using content::BrowserThread; | 30 using content::BrowserThread; |
| 31 using syncer::FakeSyncManager; |
| 32 using syncer::SyncManager; |
| 33 using ::testing::InvokeWithoutArgs; |
| 34 using ::testing::_; |
27 | 35 |
28 namespace browser_sync { | 36 namespace browser_sync { |
29 | 37 |
30 namespace { | 38 namespace { |
31 | 39 |
| 40 ACTION_P(Signal, event) { |
| 41 event->Signal(); |
| 42 } |
| 43 |
| 44 void SignalEvent(base::WaitableEvent* event) { |
| 45 event->Signal(); |
| 46 } |
| 47 |
| 48 static void QuitMessageLoop() { |
| 49 MessageLoop::current()->Quit(); |
| 50 } |
| 51 |
32 class MockSyncFrontend : public SyncFrontend { | 52 class MockSyncFrontend : public SyncFrontend { |
33 public: | 53 public: |
34 virtual ~MockSyncFrontend() {} | 54 virtual ~MockSyncFrontend() {} |
35 | 55 |
36 MOCK_METHOD2(OnBackendInitialized, | 56 MOCK_METHOD2(OnBackendInitialized, |
37 void(const syncer::WeakHandle<syncer::JsBackend>&, bool)); | 57 void(const syncer::WeakHandle<syncer::JsBackend>&, bool)); |
38 MOCK_METHOD0(OnSyncCycleCompleted, void()); | 58 MOCK_METHOD0(OnSyncCycleCompleted, void()); |
39 MOCK_METHOD1(OnConnectionStatusChange, | 59 MOCK_METHOD1(OnConnectionStatusChange, |
40 void(syncer::ConnectionStatus status)); | 60 void(syncer::ConnectionStatus status)); |
41 MOCK_METHOD0(OnStopSyncingPermanently, void()); | 61 MOCK_METHOD0(OnStopSyncingPermanently, void()); |
42 MOCK_METHOD0(OnClearServerDataSucceeded, void()); | 62 MOCK_METHOD0(OnClearServerDataSucceeded, void()); |
43 MOCK_METHOD0(OnClearServerDataFailed, void()); | 63 MOCK_METHOD0(OnClearServerDataFailed, void()); |
44 MOCK_METHOD2(OnPassphraseRequired, | 64 MOCK_METHOD2(OnPassphraseRequired, |
45 void(syncer::PassphraseRequiredReason, | 65 void(syncer::PassphraseRequiredReason, |
46 const sync_pb::EncryptedData&)); | 66 const sync_pb::EncryptedData&)); |
47 MOCK_METHOD0(OnPassphraseAccepted, void()); | 67 MOCK_METHOD0(OnPassphraseAccepted, void()); |
48 MOCK_METHOD2(OnEncryptedTypesChanged, | 68 MOCK_METHOD2(OnEncryptedTypesChanged, |
49 void(syncer::ModelTypeSet, bool)); | 69 void(syncer::ModelTypeSet, bool)); |
50 MOCK_METHOD0(OnEncryptionComplete, void()); | 70 MOCK_METHOD0(OnEncryptionComplete, void()); |
51 MOCK_METHOD1(OnMigrationNeededForTypes, void(syncer::ModelTypeSet)); | 71 MOCK_METHOD1(OnMigrationNeededForTypes, void(syncer::ModelTypeSet)); |
52 MOCK_METHOD1(OnExperimentsChanged, | 72 MOCK_METHOD1(OnExperimentsChanged, |
53 void(const syncer::Experiments&)); | 73 void(const syncer::Experiments&)); |
54 MOCK_METHOD1(OnActionableError, | 74 MOCK_METHOD1(OnActionableError, |
55 void(const syncer::SyncProtocolError& sync_error)); | 75 void(const syncer::SyncProtocolError& sync_error)); |
56 MOCK_METHOD0(OnSyncConfigureRetry, void()); | 76 MOCK_METHOD0(OnSyncConfigureRetry, void()); |
57 }; | 77 }; |
58 | 78 |
59 } // namespace | 79 class FakeSyncManagerFactory : public syncer::SyncManagerFactory { |
| 80 public: |
| 81 FakeSyncManagerFactory() : manager_(NULL) {} |
| 82 virtual ~FakeSyncManagerFactory() {} |
| 83 |
| 84 // Takes ownership of |manager|. |
| 85 void SetSyncManager(FakeSyncManager* manager) { |
| 86 DCHECK(!manager_.get()); |
| 87 manager_.reset(manager); |
| 88 } |
| 89 |
| 90 // Passes ownership of |manager_|. |
| 91 // SyncManagerFactory implementation. |
| 92 virtual scoped_ptr<SyncManager> CreateSyncManager(std::string name) OVERRIDE { |
| 93 DCHECK(manager_.get()); |
| 94 return manager_.Pass(); |
| 95 } |
| 96 |
| 97 private: |
| 98 scoped_ptr<SyncManager> manager_; |
| 99 }; |
| 100 |
| 101 class TestSyncBackendHost : public SyncBackendHost { |
| 102 public: |
| 103 TestSyncBackendHost( |
| 104 const std::string& name, |
| 105 Profile* profile, |
| 106 const base::WeakPtr<SyncPrefs>& sync_prefs, |
| 107 const base::WeakPtr<InvalidatorStorage>& invalidator_storage) |
| 108 : SyncBackendHost(name, profile, sync_prefs, invalidator_storage) { |
| 109 StartSyncThread(); |
| 110 } |
| 111 virtual ~TestSyncBackendHost() {} |
| 112 |
| 113 void PumpSyncLoop() { |
| 114 DCHECK(sync_loop()); |
| 115 base::WaitableEvent done(true, false); |
| 116 sync_loop()->PostTask(FROM_HERE, base::Bind(&SignalEvent, &done)); |
| 117 done.TimedWait(base::TimeDelta::FromMilliseconds( |
| 118 TestTimeouts::action_timeout_ms())); |
| 119 if (!done.IsSignaled()) |
| 120 FAIL() << "Timed out waiting for sync loop."; |
| 121 } |
| 122 |
| 123 void PostToSyncLoop(const base::Closure& closure) { |
| 124 DCHECK(sync_loop()); |
| 125 sync_loop()->PostTask(FROM_HERE, closure); |
| 126 } |
| 127 }; |
60 | 128 |
61 class SyncBackendHostTest : public testing::Test { | 129 class SyncBackendHostTest : public testing::Test { |
62 protected: | 130 protected: |
63 SyncBackendHostTest() | 131 SyncBackendHostTest() |
64 : ui_thread_(BrowserThread::UI, &ui_loop_), | 132 : ui_thread_(BrowserThread::UI, &ui_loop_), |
65 io_thread_(BrowserThread::IO) {} | 133 io_thread_(BrowserThread::IO), |
| 134 fake_manager_(NULL) {} |
66 | 135 |
67 virtual ~SyncBackendHostTest() {} | 136 virtual ~SyncBackendHostTest() {} |
68 | 137 |
69 virtual void SetUp() { | 138 virtual void SetUp() OVERRIDE { |
70 io_thread_.StartIOThread(); | 139 io_thread_.StartIOThread(); |
| 140 profile_.reset(new TestingProfile()); |
| 141 profile_->CreateRequestContext(); |
| 142 sync_prefs_.reset(new SyncPrefs(profile_->GetPrefs())); |
| 143 invalidator_storage_.reset(new InvalidatorStorage(profile_->GetPrefs())); |
| 144 backend_.reset(new TestSyncBackendHost( |
| 145 profile_->GetDebugName(), |
| 146 profile_.get(), |
| 147 sync_prefs_->AsWeakPtr(), |
| 148 invalidator_storage_->AsWeakPtr())); |
| 149 credentials_.email = "user@example.com"; |
| 150 credentials_.sync_token = "sync_token"; |
| 151 |
| 152 // The sync manager must be created on the sync loop in order to allow |
| 153 // thread safety enforcement. |
| 154 PostToSyncLoop(base::Bind(&SyncBackendHostTest::BuildSyncManager, |
| 155 base::Unretained(this))); |
| 156 PumpSyncLoop(); |
| 157 fake_sync_manager_factory_.SetSyncManager(fake_manager_); |
| 158 |
| 159 // NOTE: We can't include Passwords or Typed URLs due to the Sync Backend |
| 160 // Registrar removing them if it can't find their model workers. |
| 161 enabled_types_.Put(syncer::BOOKMARKS); |
| 162 enabled_types_.Put(syncer::NIGORI); |
| 163 enabled_types_.Put(syncer::PREFERENCES); |
| 164 enabled_types_.Put(syncer::SESSIONS); |
| 165 enabled_types_.Put(syncer::SEARCH_ENGINES); |
| 166 enabled_types_.Put(syncer::AUTOFILL); |
71 } | 167 } |
72 | 168 |
73 virtual void TearDown() { | 169 virtual void TearDown() OVERRIDE { |
| 170 backend_->StopSyncingForShutdown(); |
| 171 backend_->Shutdown(false); |
| 172 backend_.reset(); |
| 173 sync_prefs_.reset(); |
| 174 invalidator_storage_.reset(); |
| 175 profile_.reset(); |
74 // Pump messages posted by the sync core thread (which may end up | 176 // Pump messages posted by the sync core thread (which may end up |
75 // posting on the IO thread). | 177 // posting on the IO thread). |
76 ui_loop_.RunAllPending(); | 178 ui_loop_.RunAllPending(); |
77 io_thread_.Stop(); | 179 io_thread_.Stop(); |
78 // Pump any messages posted by the IO thread. | 180 // Pump any messages posted by the IO thread. |
79 ui_loop_.RunAllPending(); | 181 ui_loop_.RunAllPending(); |
80 } | 182 } |
81 | 183 |
82 private: | 184 // Synchronously initializes the backend. |
| 185 void InitializeBackend(syncer::ModelTypeSet enabled_types) { |
| 186 EXPECT_CALL(mock_frontend_, OnBackendInitialized(_, true)). |
| 187 WillOnce(InvokeWithoutArgs(QuitMessageLoop)); |
| 188 backend_->Initialize(&mock_frontend_, |
| 189 syncer::WeakHandle<syncer::JsEventHandler>(), |
| 190 GURL(""), |
| 191 enabled_types, |
| 192 credentials_, |
| 193 true, |
| 194 &fake_sync_manager_factory_, |
| 195 &handler_, |
| 196 NULL); |
| 197 ui_loop_.PostDelayedTask( |
| 198 FROM_HERE, |
| 199 ui_loop_.QuitClosure(), |
| 200 base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms())); |
| 201 ui_loop_.Run(); |
| 202 } |
| 203 |
| 204 // Synchronously configures the backend's datatypes. |
| 205 void ConfigureDataTypes(syncer::ModelTypeSet types_to_add, |
| 206 syncer::ModelTypeSet types_to_remove, |
| 207 BackendDataTypeConfigurer::NigoriState nigori_state) { |
| 208 backend_->ConfigureDataTypes( |
| 209 syncer::CONFIGURE_REASON_RECONFIGURATION, |
| 210 types_to_add, |
| 211 types_to_remove, |
| 212 nigori_state, |
| 213 base::Bind(&SyncBackendHostTest::DownloadReady, |
| 214 base::Unretained(this)), |
| 215 base::Bind(&SyncBackendHostTest::OnDownloadRetry, |
| 216 base::Unretained(this))); |
| 217 ui_loop_.PostDelayedTask( |
| 218 FROM_HERE, |
| 219 ui_loop_.QuitClosure(), |
| 220 base::TimeDelta::FromMilliseconds(TestTimeouts::action_timeout_ms())); |
| 221 ui_loop_.Run(); |
| 222 } |
| 223 |
| 224 protected: |
| 225 // Note: should run on the sync thread. |
| 226 void BuildSyncManager() { |
| 227 DCHECK(!fake_manager_); |
| 228 fake_manager_ = new FakeSyncManager("name"); |
| 229 } |
| 230 |
| 231 void PumpSyncLoop() { |
| 232 backend_->PumpSyncLoop(); |
| 233 } |
| 234 |
| 235 void PostToSyncLoop(const base::Closure& closure) { |
| 236 backend_->PostToSyncLoop(closure); |
| 237 } |
| 238 |
| 239 void DownloadReady(syncer::ModelTypeSet types) { |
| 240 MessageLoop::current()->Quit(); |
| 241 } |
| 242 |
| 243 void OnDownloadRetry() { |
| 244 NOTIMPLEMENTED(); |
| 245 } |
| 246 |
83 MessageLoop ui_loop_; | 247 MessageLoop ui_loop_; |
84 content::TestBrowserThread ui_thread_; | 248 content::TestBrowserThread ui_thread_; |
85 content::TestBrowserThread io_thread_; | 249 content::TestBrowserThread io_thread_; |
| 250 MockSyncFrontend mock_frontend_; |
| 251 syncer::SyncCredentials credentials_; |
| 252 syncer::TestUnrecoverableErrorHandler handler_; |
| 253 scoped_ptr<TestingProfile> profile_; |
| 254 scoped_ptr<SyncPrefs> sync_prefs_; |
| 255 scoped_ptr<InvalidatorStorage> invalidator_storage_; |
| 256 scoped_ptr<TestSyncBackendHost> backend_; |
| 257 FakeSyncManagerFactory fake_sync_manager_factory_; |
| 258 FakeSyncManager* fake_manager_; |
| 259 syncer::ModelTypeSet enabled_types_; |
86 }; | 260 }; |
87 | 261 |
| 262 // Test basic initialization with no initial types (first time initialization). |
| 263 // Only the nigori should be configured. |
88 TEST_F(SyncBackendHostTest, InitShutdown) { | 264 TEST_F(SyncBackendHostTest, InitShutdown) { |
89 std::string k_mock_url = "http://www.example.com"; | 265 InitializeBackend(syncer::ModelTypeSet()); |
90 net::FakeURLFetcherFactory test_factory_; | |
91 test_factory_.SetFakeResponse(k_mock_url + "/time?command=get_time", "", | |
92 false); | |
93 | 266 |
94 TestingProfile profile; | 267 EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Has(syncer::NIGORI)); |
95 profile.CreateRequestContext(); | 268 EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( |
96 | 269 syncer::ModelTypeSet(syncer::NIGORI)).Empty()); |
97 SyncPrefs sync_prefs(profile.GetPrefs()); | |
98 InvalidatorStorage invalidator_storage(profile.GetPrefs()); | |
99 SyncBackendHost backend(profile.GetDebugName(), | |
100 &profile, sync_prefs.AsWeakPtr(), | |
101 invalidator_storage.AsWeakPtr()); | |
102 | |
103 MockSyncFrontend mock_frontend; | |
104 syncer::SyncCredentials credentials; | |
105 credentials.email = "user@example.com"; | |
106 credentials.sync_token = "sync_token"; | |
107 syncer::TestUnrecoverableErrorHandler handler; | |
108 backend.Initialize(&mock_frontend, | |
109 syncer::WeakHandle<syncer::JsEventHandler>(), | |
110 GURL(k_mock_url), | |
111 syncer::ModelTypeSet(), | |
112 credentials, | |
113 true, | |
114 &handler, | |
115 NULL); | |
116 backend.StopSyncingForShutdown(); | |
117 backend.Shutdown(false); | |
118 } | 270 } |
119 | 271 |
120 // TODO(akalin): Write more SyncBackendHost unit tests. | 272 // Test first time sync scenario. All types should be properly configured. |
| 273 TEST_F(SyncBackendHostTest, FirstTimeSync) { |
| 274 InitializeBackend(syncer::ModelTypeSet()); |
| 275 ConfigureDataTypes(enabled_types_, |
| 276 syncer::ModelTypeSet(), |
| 277 BackendDataTypeConfigurer::WITH_NIGORI); |
| 278 |
| 279 EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll( |
| 280 enabled_types_)); |
| 281 EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); |
| 282 EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( |
| 283 enabled_types_).Empty()); |
| 284 } |
| 285 |
| 286 // Test the restart after setting up sync scenario. No enabled types should be |
| 287 // downloaded or cleaned. |
| 288 TEST_F(SyncBackendHostTest, Restart) { |
| 289 syncer::ModelTypeSet all_but_nigori = enabled_types_; |
| 290 fake_manager_->set_progress_marker_types( |
| 291 enabled_types_); |
| 292 fake_manager_->set_initial_sync_ended_types(enabled_types_); |
| 293 InitializeBackend(enabled_types_); |
| 294 ConfigureDataTypes(enabled_types_, |
| 295 syncer::ModelTypeSet(), |
| 296 BackendDataTypeConfigurer::WITH_NIGORI); |
| 297 |
| 298 EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Empty()); |
| 299 EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), |
| 300 enabled_types_).Empty()); |
| 301 EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); |
| 302 EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( |
| 303 enabled_types_).Empty()); |
| 304 } |
| 305 |
| 306 // Test a sync restart scenario where the nigori had never finished configuring. |
| 307 // The nigori should be cleaned up, then reconfigured properly. |
| 308 TEST_F(SyncBackendHostTest, PartialNigori) { |
| 309 // Set sync manager behavior before passing it down. All types have progress |
| 310 // markers, but nigori is missing initial sync ended. |
| 311 syncer::ModelTypeSet all_but_nigori = enabled_types_; |
| 312 all_but_nigori.Remove(syncer::NIGORI); |
| 313 fake_manager_->set_progress_marker_types( |
| 314 enabled_types_); |
| 315 fake_manager_->set_initial_sync_ended_types(all_but_nigori); |
| 316 InitializeBackend(enabled_types_); |
| 317 |
| 318 // Nigori should have been cleaned up, then configured. |
| 319 EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), |
| 320 enabled_types_). |
| 321 Equals(syncer::ModelTypeSet(syncer::NIGORI))); |
| 322 EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().Equals( |
| 323 syncer::ModelTypeSet(syncer::NIGORI))); |
| 324 EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Has(syncer::NIGORI)); |
| 325 } |
| 326 |
| 327 // Test the behavior when we lose the sync db. Although we already have types |
| 328 // enabled, we should re-download all of them because we lost their data. |
| 329 TEST_F(SyncBackendHostTest, LostDB) { |
| 330 // Don't set any progress marker or initial_sync_ended types before |
| 331 // initializing. |
| 332 InitializeBackend(enabled_types_); |
| 333 ConfigureDataTypes(enabled_types_, |
| 334 syncer::ModelTypeSet(), |
| 335 BackendDataTypeConfigurer::WITH_NIGORI); |
| 336 |
| 337 EXPECT_TRUE(fake_manager_->GetAndResetDownloadedTypes().HasAll( |
| 338 enabled_types_)); |
| 339 EXPECT_TRUE(Intersection(fake_manager_->GetAndResetCleanedTypes(), |
| 340 enabled_types_).Empty()); |
| 341 EXPECT_TRUE(fake_manager_->InitialSyncEndedTypes().Equals(enabled_types_)); |
| 342 EXPECT_TRUE(fake_manager_->GetTypesWithEmptyProgressMarkerToken( |
| 343 enabled_types_).Empty()); |
| 344 } |
| 345 |
| 346 } // namespace |
121 | 347 |
122 } // namespace browser_sync | 348 } // namespace browser_sync |
OLD | NEW |