1 // Copyright 2014 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_file_system/drive_backend/sync_worker.h" 6 7 #include "base/files/scoped_temp_dir.h" 8 #include "base/run_loop.h" 9 #include "base/strings/stringprintf.h" 10 #include "base/thread_task_runner_handle.h" 11 #include "chrome/browser/drive/drive_uploader.h" 12 #include "chrome/browser/drive/fake_drive_service.h" 13 #include "chrome/browser/extensions/test_extension_service.h" 14 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.h" 15 #include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h" 16 #include "chrome/browser/sync_file_system/drive_backend/sync_engine_context.h" 17 #include "chrome/browser/sync_file_system/drive_backend/sync_task.h" 18 #include "chrome/browser/sync_file_system/drive_backend/sync_task_manager.h" 19 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h" 20 #include "content/public/test/test_browser_thread_bundle.h" 21 #include "extensions/common/extension.h" 22 #include "extensions/common/extension_builder.h" 23 #include "extensions/common/extension_set.h" 24 #include "extensions/common/value_builder.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 27 #include "third_party/leveldatabase/src/include/leveldb/env.h" 28 29 namespace sync_file_system { 30 namespace drive_backend { 31 32 namespace { 33 34 const char kAppID[] = "app_id"; 35 36 void EmptyTask(SyncStatusCode status, const SyncStatusCallback& callback) { 37 base::MessageLoop::current()->PostTask( 38 FROM_HERE, base::Bind(callback, status)); 39 } 40 41 } // namespace 42 43 class MockSyncTask : public ExclusiveTask { 44 public: 45 explicit MockSyncTask(bool used_network) { 46 set_used_network(used_network); 47 } 48 virtual ~MockSyncTask() {} 49 50 virtual void RunExclusive(const SyncStatusCallback& callback) OVERRIDE { 51 callback.Run(SYNC_STATUS_OK); 52 } 53 54 private: 55 DISALLOW_COPY_AND_ASSIGN(MockSyncTask); 56 }; 57 58 class MockExtensionService : public TestExtensionService { 59 public: 60 MockExtensionService() {} 61 virtual ~MockExtensionService() {} 62 63 virtual const extensions::ExtensionSet* extensions() const OVERRIDE { 64 return &extensions_; 65 } 66 67 virtual void AddExtension(const extensions::Extension* extension) OVERRIDE { 68 extensions_.Insert(make_scoped_refptr(extension)); 69 } 70 71 virtual const extensions::Extension* GetInstalledExtension( 72 const std::string& extension_id) const OVERRIDE { 73 return extensions_.GetByID(extension_id); 74 } 75 76 virtual bool IsExtensionEnabled( 77 const std::string& extension_id) const OVERRIDE { 78 return extensions_.Contains(extension_id) && 79 !disabled_extensions_.Contains(extension_id); 80 } 81 82 void UninstallExtension(const std::string& extension_id) { 83 extensions_.Remove(extension_id); 84 disabled_extensions_.Remove(extension_id); 85 } 86 87 void DisableExtension(const std::string& extension_id) { 88 if (!IsExtensionEnabled(extension_id)) 89 return; 90 const extensions::Extension* extension = extensions_.GetByID(extension_id); 91 disabled_extensions_.Insert(make_scoped_refptr(extension)); 92 } 93 94 private: 95 extensions::ExtensionSet extensions_; 96 extensions::ExtensionSet disabled_extensions_; 97 98 DISALLOW_COPY_AND_ASSIGN(MockExtensionService); 99 }; 100 101 class SyncWorkerTest : public testing::Test, 102 public base::SupportsWeakPtr<SyncWorkerTest> { 103 public: 104 SyncWorkerTest() {} 105 virtual ~SyncWorkerTest() {} 106 107 virtual void SetUp() OVERRIDE { 108 ASSERT_TRUE(profile_dir_.CreateUniqueTempDir()); 109 in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default())); 110 111 extension_service_.reset(new MockExtensionService); 112 scoped_ptr<drive::DriveServiceInterface> 113 fake_drive_service(new drive::FakeDriveService); 114 115 scoped_ptr<SyncEngineContext> 116 sync_engine_context(new SyncEngineContext( 117 fake_drive_service.Pass(), 118 scoped_ptr<drive::DriveUploaderInterface>(), 119 NULL /* task_logger */, 120 base::ThreadTaskRunnerHandle::Get() /* ui_task_runner */, 121 base::ThreadTaskRunnerHandle::Get() /* worker_task_runner */)); 122 123 sync_worker_.reset(new SyncWorker( 124 profile_dir_.path(), 125 extension_service_->AsWeakPtr(), 126 in_memory_env_.get())); 127 sync_worker_->Initialize(sync_engine_context.Pass()); 128 129 sync_worker_->SetSyncEnabled(true); 130 base::RunLoop().RunUntilIdle(); 131 } 132 133 virtual void TearDown() OVERRIDE { 134 sync_worker_.reset(); 135 extension_service_.reset(); 136 base::RunLoop().RunUntilIdle(); 137 } 138 139 MockExtensionService* extension_service() { return extension_service_.get(); } 140 SyncWorker* sync_worker() { return sync_worker_.get(); } 141 142 void UpdateRegisteredApps() { 143 sync_worker_->UpdateRegisteredApps(); 144 } 145 146 SyncTaskManager* GetSyncTaskManager() { 147 return sync_worker_->task_manager_.get(); 148 } 149 150 void CheckServiceState(SyncStatusCode expected_sync_status, 151 RemoteServiceState expected_service_status, 152 SyncStatusCode sync_status) { 153 EXPECT_EQ(expected_sync_status, sync_status); 154 EXPECT_EQ(expected_service_status, sync_worker_->GetCurrentState()); 155 } 156 157 MetadataDatabase* metadata_database() { 158 return sync_worker_->GetMetadataDatabase(); 159 } 160 161 private: 162 content::TestBrowserThreadBundle browser_threads_; 163 base::ScopedTempDir profile_dir_; 164 scoped_ptr<leveldb::Env> in_memory_env_; 165 166 scoped_ptr<MockExtensionService> extension_service_; 167 scoped_ptr<SyncWorker> sync_worker_; 168 169 DISALLOW_COPY_AND_ASSIGN(SyncWorkerTest); 170 }; 171 172 TEST_F(SyncWorkerTest, EnableOrigin) { 173 FileTracker tracker; 174 SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN; 175 GURL origin = extensions::Extension::GetBaseURLFromExtensionId(kAppID); 176 177 sync_worker()->RegisterOrigin(origin, CreateResultReceiver(&sync_status)); 178 base::RunLoop().RunUntilIdle(); 179 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 180 ASSERT_TRUE(metadata_database()->FindAppRootTracker(kAppID, &tracker)); 181 EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind()); 182 183 sync_worker()->DisableOrigin(origin, CreateResultReceiver(&sync_status)); 184 base::RunLoop().RunUntilIdle(); 185 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 186 ASSERT_TRUE(metadata_database()->FindAppRootTracker(kAppID, &tracker)); 187 EXPECT_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker.tracker_kind()); 188 189 sync_worker()->EnableOrigin(origin, CreateResultReceiver(&sync_status)); 190 base::RunLoop().RunUntilIdle(); 191 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 192 ASSERT_TRUE(metadata_database()->FindAppRootTracker(kAppID, &tracker)); 193 EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind()); 194 195 sync_worker()->UninstallOrigin( 196 origin, 197 RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE, 198 CreateResultReceiver(&sync_status)); 199 base::RunLoop().RunUntilIdle(); 200 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 201 ASSERT_FALSE(metadata_database()->FindAppRootTracker(kAppID, &tracker)); 202 } 203 204 TEST_F(SyncWorkerTest, UpdateRegisteredApps) { 205 SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN; 206 for (int i = 0; i < 3; i++) { 207 scoped_refptr<const extensions::Extension> extension = 208 extensions::ExtensionBuilder() 209 .SetManifest(extensions::DictionaryBuilder() 210 .Set("name", "foo") 211 .Set("version", "1.0") 212 .Set("manifest_version", 2)) 213 .SetID(base::StringPrintf("app_%d", i)) 214 .Build(); 215 extension_service()->AddExtension(extension.get()); 216 GURL origin = extensions::Extension::GetBaseURLFromExtensionId( 217 extension->id()); 218 sync_status = SYNC_STATUS_UNKNOWN; 219 sync_worker()->RegisterOrigin(origin, CreateResultReceiver(&sync_status)); 220 base::RunLoop().RunUntilIdle(); 221 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 222 } 223 224 FileTracker tracker; 225 226 ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_0", &tracker)); 227 EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind()); 228 229 ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_1", &tracker)); 230 EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind()); 231 232 ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_2", &tracker)); 233 EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind()); 234 235 extension_service()->DisableExtension("app_1"); 236 extension_service()->UninstallExtension("app_2"); 237 ASSERT_FALSE(extension_service()->GetInstalledExtension("app_2")); 238 UpdateRegisteredApps(); 239 base::RunLoop().RunUntilIdle(); 240 241 ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_0", &tracker)); 242 EXPECT_EQ(TRACKER_KIND_APP_ROOT, tracker.tracker_kind()); 243 244 ASSERT_TRUE(metadata_database()->FindAppRootTracker("app_1", &tracker)); 245 EXPECT_EQ(TRACKER_KIND_DISABLED_APP_ROOT, tracker.tracker_kind()); 246 247 ASSERT_FALSE(metadata_database()->FindAppRootTracker("app_2", &tracker)); 248 } 249 250 TEST_F(SyncWorkerTest, GetOriginStatusMap) { 251 FileTracker tracker; 252 SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN; 253 GURL origin = extensions::Extension::GetBaseURLFromExtensionId(kAppID); 254 255 sync_worker()->RegisterOrigin(GURL("chrome-extension://app_0"), 256 CreateResultReceiver(&sync_status)); 257 base::RunLoop().RunUntilIdle(); 258 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 259 260 sync_worker()->RegisterOrigin(GURL("chrome-extension://app_1"), 261 CreateResultReceiver(&sync_status)); 262 base::RunLoop().RunUntilIdle(); 263 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 264 265 scoped_ptr<RemoteFileSyncService::OriginStatusMap> status_map; 266 sync_worker()->GetOriginStatusMap(CreateResultReceiver(&status_map)); 267 base::RunLoop().RunUntilIdle(); 268 ASSERT_EQ(2u, status_map->size()); 269 EXPECT_EQ("Enabled", (*status_map)[GURL("chrome-extension://app_0")]); 270 EXPECT_EQ("Enabled", (*status_map)[GURL("chrome-extension://app_1")]); 271 272 sync_worker()->DisableOrigin(GURL("chrome-extension://app_1"), 273 CreateResultReceiver(&sync_status)); 274 base::RunLoop().RunUntilIdle(); 275 EXPECT_EQ(SYNC_STATUS_OK, sync_status); 276 277 sync_worker()->GetOriginStatusMap(CreateResultReceiver(&status_map)); 278 base::RunLoop().RunUntilIdle(); 279 ASSERT_EQ(2u, status_map->size()); 280 EXPECT_EQ("Enabled", (*status_map)[GURL("chrome-extension://app_0")]); 281 EXPECT_EQ("Disabled", (*status_map)[GURL("chrome-extension://app_1")]); 282 } 283 284 TEST_F(SyncWorkerTest, UpdateServiceState) { 285 EXPECT_EQ(REMOTE_SERVICE_OK, sync_worker()->GetCurrentState()); 286 287 GetSyncTaskManager()->ScheduleTask( 288 FROM_HERE, 289 base::Bind(&EmptyTask, SYNC_STATUS_AUTHENTICATION_FAILED), 290 SyncTaskManager::PRIORITY_MED, 291 base::Bind(&SyncWorkerTest::CheckServiceState, 292 AsWeakPtr(), 293 SYNC_STATUS_AUTHENTICATION_FAILED, 294 REMOTE_SERVICE_AUTHENTICATION_REQUIRED)); 295 296 GetSyncTaskManager()->ScheduleTask( 297 FROM_HERE, 298 base::Bind(&EmptyTask, SYNC_STATUS_ACCESS_FORBIDDEN), 299 SyncTaskManager::PRIORITY_MED, 300 base::Bind(&SyncWorkerTest::CheckServiceState, 301 AsWeakPtr(), 302 SYNC_STATUS_ACCESS_FORBIDDEN, 303 REMOTE_SERVICE_ACCESS_FORBIDDEN)); 304 305 GetSyncTaskManager()->ScheduleTask( 306 FROM_HERE, 307 base::Bind(&EmptyTask, SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE), 308 SyncTaskManager::PRIORITY_MED, 309 base::Bind(&SyncWorkerTest::CheckServiceState, 310 AsWeakPtr(), 311 SYNC_STATUS_SERVICE_TEMPORARILY_UNAVAILABLE, 312 REMOTE_SERVICE_TEMPORARY_UNAVAILABLE)); 313 314 GetSyncTaskManager()->ScheduleTask( 315 FROM_HERE, 316 base::Bind(&EmptyTask, SYNC_STATUS_NETWORK_ERROR), 317 SyncTaskManager::PRIORITY_MED, 318 base::Bind(&SyncWorkerTest::CheckServiceState, 319 AsWeakPtr(), 320 SYNC_STATUS_NETWORK_ERROR, 321 REMOTE_SERVICE_TEMPORARY_UNAVAILABLE)); 322 323 GetSyncTaskManager()->ScheduleTask( 324 FROM_HERE, 325 base::Bind(&EmptyTask, SYNC_STATUS_ABORT), 326 SyncTaskManager::PRIORITY_MED, 327 base::Bind(&SyncWorkerTest::CheckServiceState, 328 AsWeakPtr(), 329 SYNC_STATUS_ABORT, 330 REMOTE_SERVICE_TEMPORARY_UNAVAILABLE)); 331 332 GetSyncTaskManager()->ScheduleTask( 333 FROM_HERE, 334 base::Bind(&EmptyTask, SYNC_STATUS_FAILED), 335 SyncTaskManager::PRIORITY_MED, 336 base::Bind(&SyncWorkerTest::CheckServiceState, 337 AsWeakPtr(), 338 SYNC_STATUS_FAILED, 339 REMOTE_SERVICE_TEMPORARY_UNAVAILABLE)); 340 341 GetSyncTaskManager()->ScheduleTask( 342 FROM_HERE, 343 base::Bind(&EmptyTask, SYNC_DATABASE_ERROR_CORRUPTION), 344 SyncTaskManager::PRIORITY_MED, 345 base::Bind(&SyncWorkerTest::CheckServiceState, 346 AsWeakPtr(), 347 SYNC_DATABASE_ERROR_CORRUPTION, 348 REMOTE_SERVICE_DISABLED)); 349 350 GetSyncTaskManager()->ScheduleTask( 351 FROM_HERE, 352 base::Bind(&EmptyTask, SYNC_DATABASE_ERROR_IO_ERROR), 353 SyncTaskManager::PRIORITY_MED, 354 base::Bind(&SyncWorkerTest::CheckServiceState, 355 AsWeakPtr(), 356 SYNC_DATABASE_ERROR_IO_ERROR, 357 REMOTE_SERVICE_DISABLED)); 358 359 GetSyncTaskManager()->ScheduleTask( 360 FROM_HERE, 361 base::Bind(&EmptyTask, SYNC_DATABASE_ERROR_FAILED), 362 SyncTaskManager::PRIORITY_MED, 363 base::Bind(&SyncWorkerTest::CheckServiceState, 364 AsWeakPtr(), 365 SYNC_DATABASE_ERROR_FAILED, 366 REMOTE_SERVICE_DISABLED)); 367 368 GetSyncTaskManager()->ScheduleSyncTask( 369 FROM_HERE, 370 scoped_ptr<SyncTask>(new MockSyncTask(false)), 371 SyncTaskManager::PRIORITY_MED, 372 base::Bind(&SyncWorkerTest::CheckServiceState, 373 AsWeakPtr(), 374 SYNC_STATUS_OK, 375 REMOTE_SERVICE_DISABLED)); 376 377 GetSyncTaskManager()->ScheduleSyncTask( 378 FROM_HERE, 379 scoped_ptr<SyncTask>(new MockSyncTask(true)), 380 SyncTaskManager::PRIORITY_MED, 381 base::Bind(&SyncWorkerTest::CheckServiceState, 382 AsWeakPtr(), 383 SYNC_STATUS_OK, 384 REMOTE_SERVICE_OK)); 385 386 base::RunLoop().RunUntilIdle(); 387 } 388 389 } // namespace drive_backend 390 } // namespace sync_file_system 391