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