OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "components/sync_driver/glue/sync_backend_host_impl.h" | 5 #include "components/sync_driver/glue/sync_backend_host_impl.h" |
6 | 6 |
7 #include <cstddef> | 7 #include <cstddef> |
8 | 8 |
9 #include "base/files/file_util.h" | 9 #include "base/files/file_util.h" |
| 10 #include "base/files/scoped_temp_dir.h" |
10 #include "base/location.h" | 11 #include "base/location.h" |
11 #include "base/memory/scoped_ptr.h" | 12 #include "base/memory/scoped_ptr.h" |
12 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 14 #include "base/run_loop.h" |
13 #include "base/synchronization/waitable_event.h" | 15 #include "base/synchronization/waitable_event.h" |
14 #include "base/test/test_timeouts.h" | 16 #include "base/test/test_timeouts.h" |
| 17 #include "base/thread_task_runner_handle.h" |
15 #include "base/time/time.h" | 18 #include "base/time/time.h" |
16 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h" | |
17 #include "chrome/browser/sync/profile_sync_test_util.h" | |
18 #include "chrome/test/base/testing_browser_process.h" | |
19 #include "chrome/test/base/testing_profile.h" | |
20 #include "chrome/test/base/testing_profile_manager.h" | |
21 #include "components/invalidation/impl/invalidator_storage.h" | 19 #include "components/invalidation/impl/invalidator_storage.h" |
22 #include "components/invalidation/impl/profile_invalidation_provider.h" | 20 #include "components/invalidation/impl/profile_invalidation_provider.h" |
23 #include "components/invalidation/public/invalidator_state.h" | 21 #include "components/invalidation/public/invalidator_state.h" |
24 #include "components/invalidation/public/object_id_invalidation_map.h" | 22 #include "components/invalidation/public/object_id_invalidation_map.h" |
25 #include "components/sync_driver/device_info.h" | 23 #include "components/sync_driver/device_info.h" |
26 #include "components/sync_driver/fake_sync_client.h" | 24 #include "components/sync_driver/fake_sync_client.h" |
27 #include "components/sync_driver/sync_frontend.h" | 25 #include "components/sync_driver/sync_frontend.h" |
28 #include "components/sync_driver/sync_prefs.h" | 26 #include "components/sync_driver/sync_prefs.h" |
29 #include "components/syncable_prefs/pref_service_syncable.h" | 27 #include "components/syncable_prefs/pref_service_syncable.h" |
30 #include "content/public/browser/notification_service.h" | 28 #include "components/syncable_prefs/testing_pref_service_syncable.h" |
31 #include "content/public/test/test_browser_thread_bundle.h" | |
32 #include "content/public/test/test_utils.h" | |
33 #include "google/cacheinvalidation/include/types.h" | 29 #include "google/cacheinvalidation/include/types.h" |
34 #include "google_apis/gaia/gaia_constants.h" | 30 #include "google_apis/gaia/gaia_constants.h" |
35 #include "net/url_request/test_url_fetcher_factory.h" | 31 #include "net/url_request/test_url_fetcher_factory.h" |
36 #include "net/url_request/url_request_context_getter.h" | 32 #include "net/url_request/url_request_context_getter.h" |
37 #include "sync/internal_api/public/base/model_type.h" | 33 #include "sync/internal_api/public/base/model_type.h" |
38 #include "sync/internal_api/public/engine/model_safe_worker.h" | 34 #include "sync/internal_api/public/engine/model_safe_worker.h" |
39 #include "sync/internal_api/public/engine/passive_model_worker.h" | 35 #include "sync/internal_api/public/engine/passive_model_worker.h" |
40 #include "sync/internal_api/public/http_bridge_network_resources.h" | 36 #include "sync/internal_api/public/http_bridge_network_resources.h" |
41 #include "sync/internal_api/public/network_resources.h" | 37 #include "sync/internal_api/public/network_resources.h" |
42 #include "sync/internal_api/public/sessions/commit_counters.h" | 38 #include "sync/internal_api/public/sessions/commit_counters.h" |
43 #include "sync/internal_api/public/sessions/status_counters.h" | 39 #include "sync/internal_api/public/sessions/status_counters.h" |
44 #include "sync/internal_api/public/sessions/update_counters.h" | 40 #include "sync/internal_api/public/sessions/update_counters.h" |
45 #include "sync/internal_api/public/sync_manager_factory.h" | 41 #include "sync/internal_api/public/sync_manager_factory.h" |
46 #include "sync/internal_api/public/test/fake_sync_manager.h" | 42 #include "sync/internal_api/public/test/fake_sync_manager.h" |
47 #include "sync/internal_api/public/util/experiments.h" | 43 #include "sync/internal_api/public/util/experiments.h" |
48 #include "sync/protocol/encryption.pb.h" | 44 #include "sync/protocol/encryption.pb.h" |
49 #include "sync/protocol/sync_protocol_error.h" | 45 #include "sync/protocol/sync_protocol_error.h" |
50 #include "sync/test/callback_counter.h" | 46 #include "sync/test/callback_counter.h" |
51 #include "sync/util/test_unrecoverable_error_handler.h" | 47 #include "sync/util/test_unrecoverable_error_handler.h" |
52 #include "testing/gmock/include/gmock/gmock.h" | 48 #include "testing/gmock/include/gmock/gmock.h" |
53 #include "testing/gtest/include/gtest/gtest.h" | 49 #include "testing/gtest/include/gtest/gtest.h" |
54 #include "url/gurl.h" | 50 #include "url/gurl.h" |
55 | 51 |
56 using content::BrowserThread; | |
57 using syncer::FakeSyncManager; | 52 using syncer::FakeSyncManager; |
58 using syncer::SyncManager; | 53 using syncer::SyncManager; |
59 using ::testing::InvokeWithoutArgs; | 54 using ::testing::InvokeWithoutArgs; |
60 using ::testing::StrictMock; | 55 using ::testing::StrictMock; |
61 using ::testing::_; | 56 using ::testing::_; |
62 | 57 |
63 namespace browser_sync { | 58 namespace browser_sync { |
64 | 59 |
65 namespace { | 60 namespace { |
66 | 61 |
67 const char kTestProfileName[] = "test-profile"; | |
68 | |
69 static const base::FilePath::CharType kTestSyncDir[] = | 62 static const base::FilePath::CharType kTestSyncDir[] = |
70 FILE_PATH_LITERAL("sync-test"); | 63 FILE_PATH_LITERAL("sync-test"); |
71 | 64 |
72 ACTION_P(Signal, event) { | 65 ACTION_P(Signal, event) { |
73 event->Signal(); | 66 event->Signal(); |
74 } | 67 } |
75 | 68 |
| 69 void EmptyNetworkTimeUpdate(const base::Time&, |
| 70 const base::TimeDelta&, |
| 71 const base::TimeDelta&) {} |
| 72 |
76 void QuitMessageLoop() { | 73 void QuitMessageLoop() { |
77 base::MessageLoop::current()->QuitWhenIdle(); | 74 base::MessageLoop::current()->QuitWhenIdle(); |
78 } | 75 } |
79 | 76 |
80 class MockSyncFrontend : public sync_driver::SyncFrontend { | 77 class MockSyncFrontend : public sync_driver::SyncFrontend { |
81 public: | 78 public: |
82 virtual ~MockSyncFrontend() {} | 79 virtual ~MockSyncFrontend() {} |
83 | 80 |
84 MOCK_METHOD4( | 81 MOCK_METHOD4( |
85 OnBackendInitialized, | 82 OnBackendInitialized, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 return new syncer::PassiveModelWorker(observer); | 161 return new syncer::PassiveModelWorker(observer); |
165 default: | 162 default: |
166 return nullptr; | 163 return nullptr; |
167 } | 164 } |
168 } | 165 } |
169 }; | 166 }; |
170 | 167 |
171 class SyncBackendHostTest : public testing::Test { | 168 class SyncBackendHostTest : public testing::Test { |
172 protected: | 169 protected: |
173 SyncBackendHostTest() | 170 SyncBackendHostTest() |
174 : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), | 171 : fake_manager_(NULL) { |
175 profile_manager_(TestingBrowserProcess::GetGlobal()), | 172 } |
176 fake_manager_(NULL) {} | |
177 | 173 |
178 ~SyncBackendHostTest() override {} | 174 ~SyncBackendHostTest() override {} |
179 | 175 |
180 void SetUp() override { | 176 void SetUp() override { |
181 ASSERT_TRUE(profile_manager_.SetUp()); | 177 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
182 profile_ = profile_manager_.CreateTestingProfile(kTestProfileName); | 178 |
183 sync_prefs_.reset(new sync_driver::SyncPrefs(profile_->GetPrefs())); | 179 sync_driver::SyncPrefs::RegisterProfilePrefs(pref_service_.registry()); |
| 180 |
| 181 sync_prefs_.reset(new sync_driver::SyncPrefs(&pref_service_)); |
184 backend_.reset(new SyncBackendHostImpl( | 182 backend_.reset(new SyncBackendHostImpl( |
185 profile_->GetDebugName(), &sync_client_, | 183 "dummyDebugName", &sync_client_, |
186 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), | 184 base::ThreadTaskRunnerHandle::Get(), |
187 invalidation::ProfileInvalidationProviderFactory::GetForProfile( | 185 nullptr, |
188 profile_) | |
189 ->GetInvalidationService(), | |
190 sync_prefs_->AsWeakPtr(), | 186 sync_prefs_->AsWeakPtr(), |
191 profile_->GetPath().Append(base::FilePath(kTestSyncDir)))); | 187 temp_dir_.path().Append(base::FilePath(kTestSyncDir)))); |
192 credentials_.email = "user@example.com"; | 188 credentials_.email = "user@example.com"; |
193 credentials_.sync_token = "sync_token"; | 189 credentials_.sync_token = "sync_token"; |
194 credentials_.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope); | 190 credentials_.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope); |
195 | 191 |
196 fake_manager_factory_.reset(new FakeSyncManagerFactory(&fake_manager_)); | 192 fake_manager_factory_.reset(new FakeSyncManagerFactory(&fake_manager_)); |
197 | 193 |
198 // These types are always implicitly enabled. | 194 // These types are always implicitly enabled. |
199 enabled_types_.PutAll(syncer::ControlTypes()); | 195 enabled_types_.PutAll(syncer::ControlTypes()); |
200 | 196 |
201 // NOTE: We can't include Passwords or Typed URLs due to the Sync Backend | 197 // NOTE: We can't include Passwords or Typed URLs due to the Sync Backend |
202 // Registrar removing them if it can't find their model workers. | 198 // Registrar removing them if it can't find their model workers. |
203 enabled_types_.Put(syncer::BOOKMARKS); | 199 enabled_types_.Put(syncer::BOOKMARKS); |
204 enabled_types_.Put(syncer::PREFERENCES); | 200 enabled_types_.Put(syncer::PREFERENCES); |
205 enabled_types_.Put(syncer::SESSIONS); | 201 enabled_types_.Put(syncer::SESSIONS); |
206 enabled_types_.Put(syncer::SEARCH_ENGINES); | 202 enabled_types_.Put(syncer::SEARCH_ENGINES); |
207 enabled_types_.Put(syncer::AUTOFILL); | 203 enabled_types_.Put(syncer::AUTOFILL); |
208 | 204 |
209 network_resources_.reset(new syncer::HttpBridgeNetworkResources()); | 205 network_resources_.reset(new syncer::HttpBridgeNetworkResources()); |
210 } | 206 } |
211 | 207 |
212 void TearDown() override { | 208 void TearDown() override { |
213 if (backend_) { | 209 if (backend_) { |
214 backend_->StopSyncingForShutdown(); | 210 backend_->StopSyncingForShutdown(); |
215 backend_->Shutdown(syncer::STOP_SYNC); | 211 backend_->Shutdown(syncer::STOP_SYNC); |
216 } | 212 } |
217 backend_.reset(); | 213 backend_.reset(); |
218 sync_prefs_.reset(); | 214 sync_prefs_.reset(); |
219 profile_ = NULL; | 215 // Pump messages posted by the sync thread. |
220 profile_manager_.DeleteTestingProfile(kTestProfileName); | |
221 // Pump messages posted by the sync thread (which may end up | |
222 // posting on the IO thread). | |
223 base::RunLoop().RunUntilIdle(); | |
224 content::RunAllPendingInMessageLoop(BrowserThread::IO); | |
225 // Pump any messages posted by the IO thread. | |
226 base::RunLoop().RunUntilIdle(); | 216 base::RunLoop().RunUntilIdle(); |
227 } | 217 } |
228 | 218 |
229 // Synchronously initializes the backend. | 219 // Synchronously initializes the backend. |
230 void InitializeBackend(bool expect_success) { | 220 void InitializeBackend(bool expect_success) { |
231 EXPECT_CALL(mock_frontend_, OnBackendInitialized(_, _, _, expect_success)). | 221 EXPECT_CALL(mock_frontend_, OnBackendInitialized(_, _, _, expect_success)). |
232 WillOnce(InvokeWithoutArgs(QuitMessageLoop)); | 222 WillOnce(InvokeWithoutArgs(QuitMessageLoop)); |
233 SyncBackendHost::HttpPostProviderFactoryGetter | 223 SyncBackendHost::HttpPostProviderFactoryGetter |
234 http_post_provider_factory_getter = | 224 http_post_provider_factory_getter = |
235 base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory, | 225 base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory, |
236 base::Unretained(network_resources_.get()), | 226 base::Unretained(network_resources_.get()), |
237 make_scoped_refptr(profile_->GetRequestContext()), | 227 nullptr, |
238 base::Bind(&EmptyNetworkTimeUpdate)); | 228 base::Bind(&EmptyNetworkTimeUpdate)); |
239 backend_->Initialize( | 229 backend_->Initialize( |
240 &mock_frontend_, scoped_ptr<base::Thread>(), | 230 &mock_frontend_, scoped_ptr<base::Thread>(), |
241 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB), | 231 base::ThreadTaskRunnerHandle::Get(), |
242 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | 232 base::ThreadTaskRunnerHandle::Get(), |
243 syncer::WeakHandle<syncer::JsEventHandler>(), GURL(std::string()), | 233 syncer::WeakHandle<syncer::JsEventHandler>(), GURL(std::string()), |
244 std::string(), credentials_, true, fake_manager_factory_.Pass(), | 234 std::string(), credentials_, true, fake_manager_factory_.Pass(), |
245 MakeWeakHandle(test_unrecoverable_error_handler_.GetWeakPtr()), | 235 MakeWeakHandle(test_unrecoverable_error_handler_.GetWeakPtr()), |
246 base::Closure(), http_post_provider_factory_getter, | 236 base::Closure(), http_post_provider_factory_getter, |
247 saved_nigori_state_.Pass()); | 237 saved_nigori_state_.Pass()); |
248 base::RunLoop run_loop; | 238 base::RunLoop run_loop; |
249 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, | 239 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, |
250 run_loop.QuitClosure(), | 240 run_loop.QuitClosure(), |
251 TestTimeouts::action_timeout()); | 241 TestTimeouts::action_timeout()); |
252 run_loop.Run(); | 242 run_loop.Run(); |
253 // |fake_manager_factory_|'s fake_manager() is set on the sync | 243 // |fake_manager_factory_|'s fake_manager() is set on the sync |
254 // thread, but we can rely on the message loop barriers to | 244 // thread, but we can rely on the message loop barriers to |
255 // guarantee that we see the updated value. | 245 // guarantee that we see the updated value. |
256 DCHECK(fake_manager_); | 246 DCHECK(fake_manager_); |
257 } | 247 } |
258 | 248 |
259 // Synchronously configures the backend's datatypes. | 249 // Synchronously configures the backend's datatypes. |
260 syncer::ModelTypeSet ConfigureDataTypes( | 250 syncer::ModelTypeSet ConfigureDataTypes( |
261 syncer::ModelTypeSet types_to_add, | 251 syncer::ModelTypeSet types_to_add, |
(...skipping 12 matching lines...) Expand all Loading... |
274 sync_driver::BackendDataTypeConfigurer::UNREADY, | 264 sync_driver::BackendDataTypeConfigurer::UNREADY, |
275 types_to_unapply, &config_state_map); | 265 types_to_unapply, &config_state_map); |
276 | 266 |
277 types_to_add.PutAll(syncer::ControlTypes()); | 267 types_to_add.PutAll(syncer::ControlTypes()); |
278 syncer::ModelTypeSet ready_types = backend_->ConfigureDataTypes( | 268 syncer::ModelTypeSet ready_types = backend_->ConfigureDataTypes( |
279 syncer::CONFIGURE_REASON_RECONFIGURATION, config_state_map, | 269 syncer::CONFIGURE_REASON_RECONFIGURATION, config_state_map, |
280 base::Bind(&SyncBackendHostTest::DownloadReady, base::Unretained(this)), | 270 base::Bind(&SyncBackendHostTest::DownloadReady, base::Unretained(this)), |
281 base::Bind(&SyncBackendHostTest::OnDownloadRetry, | 271 base::Bind(&SyncBackendHostTest::OnDownloadRetry, |
282 base::Unretained(this))); | 272 base::Unretained(this))); |
283 base::RunLoop run_loop; | 273 base::RunLoop run_loop; |
284 BrowserThread::PostDelayedTask(BrowserThread::UI, FROM_HERE, | 274 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE, |
285 run_loop.QuitClosure(), | 275 run_loop.QuitClosure(), |
286 TestTimeouts::action_timeout()); | 276 TestTimeouts::action_timeout()); |
287 run_loop.Run(); | 277 run_loop.Run(); |
288 return ready_types; | 278 return ready_types; |
289 } | 279 } |
290 | 280 |
291 protected: | 281 protected: |
292 void DownloadReady(syncer::ModelTypeSet succeeded_types, | 282 void DownloadReady(syncer::ModelTypeSet succeeded_types, |
293 syncer::ModelTypeSet failed_types) { | 283 syncer::ModelTypeSet failed_types) { |
294 base::MessageLoop::current()->QuitWhenIdle(); | 284 base::MessageLoop::current()->QuitWhenIdle(); |
295 } | 285 } |
296 | 286 |
297 void OnDownloadRetry() { | 287 void OnDownloadRetry() { |
298 NOTIMPLEMENTED(); | 288 NOTIMPLEMENTED(); |
299 } | 289 } |
300 | 290 |
301 content::TestBrowserThreadBundle thread_bundle_; | 291 base::MessageLoop message_loop_; |
| 292 base::ScopedTempDir temp_dir_; |
| 293 syncable_prefs::TestingPrefServiceSyncable pref_service_; |
302 StrictMock<MockSyncFrontend> mock_frontend_; | 294 StrictMock<MockSyncFrontend> mock_frontend_; |
303 syncer::SyncCredentials credentials_; | 295 syncer::SyncCredentials credentials_; |
304 TestingProfileManager profile_manager_; | |
305 TestingProfile* profile_; | |
306 BackendSyncClient sync_client_; | 296 BackendSyncClient sync_client_; |
307 syncer::TestUnrecoverableErrorHandler test_unrecoverable_error_handler_; | 297 syncer::TestUnrecoverableErrorHandler test_unrecoverable_error_handler_; |
308 scoped_ptr<sync_driver::SyncPrefs> sync_prefs_; | 298 scoped_ptr<sync_driver::SyncPrefs> sync_prefs_; |
309 scoped_ptr<SyncBackendHostImpl> backend_; | 299 scoped_ptr<SyncBackendHostImpl> backend_; |
310 scoped_ptr<FakeSyncManagerFactory> fake_manager_factory_; | 300 scoped_ptr<FakeSyncManagerFactory> fake_manager_factory_; |
311 FakeSyncManager* fake_manager_; | 301 FakeSyncManager* fake_manager_; |
312 syncer::ModelTypeSet enabled_types_; | 302 syncer::ModelTypeSet enabled_types_; |
313 scoped_ptr<syncer::NetworkResources> network_resources_; | 303 scoped_ptr<syncer::NetworkResources> network_resources_; |
314 scoped_ptr<syncer::SyncEncryptionHandler::NigoriState> saved_nigori_state_; | 304 scoped_ptr<syncer::SyncEncryptionHandler::NigoriState> saved_nigori_state_; |
315 }; | 305 }; |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
732 fake_manager_factory_->set_initial_sync_ended_types(enabled_types_); | 722 fake_manager_factory_->set_initial_sync_ended_types(enabled_types_); |
733 InitializeBackend(true); | 723 InitializeBackend(true); |
734 EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, | 724 EXPECT_EQ(syncer::CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE, |
735 fake_manager_->GetAndResetConfigureReason()); | 725 fake_manager_->GetAndResetConfigureReason()); |
736 } | 726 } |
737 | 727 |
738 // It is SyncBackendHostCore responsibility to cleanup Sync Data folder if sync | 728 // It is SyncBackendHostCore responsibility to cleanup Sync Data folder if sync |
739 // setup hasn't been completed. This test ensures that cleanup happens. | 729 // setup hasn't been completed. This test ensures that cleanup happens. |
740 TEST_F(SyncBackendHostTest, TestStartupWithOldSyncData) { | 730 TEST_F(SyncBackendHostTest, TestStartupWithOldSyncData) { |
741 const char* nonsense = "slon"; | 731 const char* nonsense = "slon"; |
742 base::FilePath temp_directory = | 732 base::FilePath temp_directory = temp_dir_.path().Append( |
743 profile_->GetPath().Append(base::FilePath(kTestSyncDir)); | 733 base::FilePath(kTestSyncDir)); |
744 base::FilePath sync_file = temp_directory.AppendASCII("SyncData.sqlite3"); | 734 base::FilePath sync_file = temp_directory.AppendASCII("SyncData.sqlite3"); |
745 ASSERT_TRUE(base::CreateDirectory(temp_directory)); | 735 ASSERT_TRUE(base::CreateDirectory(temp_directory)); |
746 ASSERT_NE(-1, base::WriteFile(sync_file, nonsense, strlen(nonsense))); | 736 ASSERT_NE(-1, base::WriteFile(sync_file, nonsense, strlen(nonsense))); |
747 | 737 |
748 InitializeBackend(true); | 738 InitializeBackend(true); |
749 | 739 |
750 EXPECT_FALSE(base::PathExists(sync_file)); | 740 EXPECT_FALSE(base::PathExists(sync_file)); |
751 } | 741 } |
752 | 742 |
753 // If bookmarks encounter an error that results in disabling without purging | 743 // If bookmarks encounter an error that results in disabling without purging |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 EXPECT_EQ(invalidation_versions.size(), | 847 EXPECT_EQ(invalidation_versions.size(), |
858 persisted_invalidation_versions.size()); | 848 persisted_invalidation_versions.size()); |
859 for (auto iter : persisted_invalidation_versions) { | 849 for (auto iter : persisted_invalidation_versions) { |
860 EXPECT_EQ(invalidation_versions[iter.first], iter.second); | 850 EXPECT_EQ(invalidation_versions[iter.first], iter.second); |
861 } | 851 } |
862 } | 852 } |
863 | 853 |
864 } // namespace | 854 } // namespace |
865 | 855 |
866 } // namespace browser_sync | 856 } // namespace browser_sync |
OLD | NEW |