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