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