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
3// found in the LICENSE file.
4
5#include "chrome/browser/sync_file_system/drive_backend/sync_engine.h"
6
7#include "base/files/scoped_temp_dir.h"
8#include "base/macros.h"
9#include "base/run_loop.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/sync_file_system/drive_backend/callback_helper.h"
14#include "chrome/browser/sync_file_system/drive_backend/fake_sync_worker.h"
15#include "chrome/browser/sync_file_system/drive_backend/sync_worker_interface.h"
16#include "chrome/browser/sync_file_system/remote_file_sync_service.h"
17#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
18#include "content/public/browser/browser_thread.h"
19#include "content/public/test/test_browser_thread_bundle.h"
20#include "net/url_request/url_request_context_getter.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23namespace sync_file_system {
24namespace drive_backend {
25
26class SyncEngineTest : public testing::Test,
27                       public base::SupportsWeakPtr<SyncEngineTest> {
28 public:
29  typedef RemoteFileSyncService::OriginStatusMap RemoteOriginStatusMap;
30
31  SyncEngineTest() {}
32  virtual ~SyncEngineTest() {}
33
34  virtual void SetUp() OVERRIDE {
35    ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
36
37    scoped_ptr<drive::DriveServiceInterface>
38        fake_drive_service(new drive::FakeDriveService);
39
40    worker_pool_ = new base::SequencedWorkerPool(1, "Worker");
41    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner =
42        base::ThreadTaskRunnerHandle::Get();
43    worker_task_runner_ =
44        worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
45            worker_pool_->GetSequenceToken(),
46            base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
47
48    sync_engine_.reset(new drive_backend::SyncEngine(
49        ui_task_runner.get(),
50        worker_task_runner_.get(),
51        NULL /* drive_task_runner */,
52        profile_dir_.path(),
53        NULL /* task_logger */,
54        NULL /* notification_manager */,
55        NULL /* extension_service */,
56        NULL /* signin_manager */,
57        NULL /* token_service */,
58        NULL /* request_context */,
59        scoped_ptr<SyncEngine::DriveServiceFactory>(),
60        NULL /* in_memory_env */));
61
62    sync_engine_->InitializeForTesting(
63        fake_drive_service.Pass(),
64        scoped_ptr<drive::DriveUploaderInterface>(),
65        scoped_ptr<SyncWorkerInterface>(new FakeSyncWorker));
66    sync_engine_->SetSyncEnabled(true);
67    sync_engine_->OnReadyToSendRequests();
68
69    WaitForWorkerTaskRunner();
70  }
71
72  virtual void TearDown() OVERRIDE {
73    sync_engine_.reset();
74    WaitForWorkerTaskRunner();
75    worker_pool_->Shutdown();
76
77    worker_task_runner_ = NULL;
78    worker_pool_ = NULL;
79
80    base::RunLoop().RunUntilIdle();
81  }
82
83  bool FindOriginStatus(const GURL& origin, std::string* status) {
84    scoped_ptr<RemoteOriginStatusMap> status_map;
85    sync_engine()->GetOriginStatusMap(CreateResultReceiver(&status_map));
86    WaitForWorkerTaskRunner();
87
88    RemoteOriginStatusMap::const_iterator itr = status_map->find(origin);
89    if (itr == status_map->end())
90      return false;
91
92    *status = itr->second;
93    // If an origin is uninstalled, it should not be found actually.
94    if (*status == "Uninstalled")
95      return false;
96    return true;
97  }
98
99  void PostUpdateServiceState(RemoteServiceState state,
100                              const std::string& description) {
101    worker_task_runner_->PostTask(
102        FROM_HERE,
103        base::Bind(&FakeSyncWorker::UpdateServiceState,
104                   base::Unretained(fake_sync_worker()),
105                   state,
106                   description));
107    WaitForWorkerTaskRunner();
108  }
109
110  void WaitForWorkerTaskRunner() {
111    DCHECK(worker_task_runner_.get());
112
113    base::RunLoop run_loop;
114    worker_task_runner_->PostTask(
115        FROM_HERE,
116        RelayCallbackToCurrentThread(
117            FROM_HERE, run_loop.QuitClosure()));
118    run_loop.Run();
119  }
120
121  // Accessors
122  SyncEngine* sync_engine() { return sync_engine_.get(); }
123
124  FakeSyncWorker* fake_sync_worker() {
125    return static_cast<FakeSyncWorker*>(sync_engine_->sync_worker_.get());
126  }
127
128 private:
129  content::TestBrowserThreadBundle browser_threads_;
130  base::ScopedTempDir profile_dir_;
131  scoped_ptr<drive_backend::SyncEngine> sync_engine_;
132
133  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
134  scoped_refptr<base::SequencedTaskRunner> worker_task_runner_;
135
136  DISALLOW_COPY_AND_ASSIGN(SyncEngineTest);
137};
138
139TEST_F(SyncEngineTest, OriginTest) {
140  GURL origin("chrome-extension://app_0");
141
142  SyncStatusCode sync_status;
143  std::string status;
144
145  sync_engine()->RegisterOrigin(
146      origin,
147      CreateResultReceiver(&sync_status));
148  WaitForWorkerTaskRunner();
149  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
150  ASSERT_TRUE(FindOriginStatus(origin, &status));
151  EXPECT_EQ("Registered", status);
152
153  sync_engine()->DisableOrigin(
154      origin,
155      CreateResultReceiver(&sync_status));
156  WaitForWorkerTaskRunner();
157  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
158  ASSERT_TRUE(FindOriginStatus(origin, &status));
159  EXPECT_EQ("Disabled", status);
160
161  sync_engine()->EnableOrigin(
162      origin,
163      CreateResultReceiver(&sync_status));
164  WaitForWorkerTaskRunner();
165  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
166  ASSERT_TRUE(FindOriginStatus(origin, &status));
167  EXPECT_EQ("Enabled", status);
168
169  sync_engine()->UninstallOrigin(
170      origin,
171      RemoteFileSyncService::UNINSTALL_AND_KEEP_REMOTE,
172      CreateResultReceiver(&sync_status));
173  WaitForWorkerTaskRunner();
174  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
175  EXPECT_FALSE(FindOriginStatus(origin, &status));
176  EXPECT_EQ("Uninstalled", status);
177}
178
179TEST_F(SyncEngineTest, GetOriginStatusMap) {
180  SyncStatusCode sync_status = SYNC_STATUS_UNKNOWN;
181
182  sync_engine()->RegisterOrigin(GURL("chrome-extension://app_0"),
183                                CreateResultReceiver(&sync_status));
184  WaitForWorkerTaskRunner();
185  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
186
187  sync_engine()->RegisterOrigin(GURL("chrome-extension://app_1"),
188                                CreateResultReceiver(&sync_status));
189  WaitForWorkerTaskRunner();
190  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
191
192  scoped_ptr<RemoteOriginStatusMap> status_map;
193  sync_engine()->GetOriginStatusMap(CreateResultReceiver(&status_map));
194  WaitForWorkerTaskRunner();
195  ASSERT_EQ(2u, status_map->size());
196  EXPECT_EQ("Registered", (*status_map)[GURL("chrome-extension://app_0")]);
197  EXPECT_EQ("Registered", (*status_map)[GURL("chrome-extension://app_1")]);
198
199  sync_engine()->DisableOrigin(GURL("chrome-extension://app_1"),
200                               CreateResultReceiver(&sync_status));
201  WaitForWorkerTaskRunner();
202  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
203
204  sync_engine()->GetOriginStatusMap(CreateResultReceiver(&status_map));
205  WaitForWorkerTaskRunner();
206  ASSERT_EQ(2u, status_map->size());
207  EXPECT_EQ("Registered", (*status_map)[GURL("chrome-extension://app_0")]);
208  EXPECT_EQ("Disabled", (*status_map)[GURL("chrome-extension://app_1")]);
209}
210
211TEST_F(SyncEngineTest, UpdateServiceState) {
212  struct {
213    RemoteServiceState state;
214    const char* description;
215  } test_data[] = {
216    {REMOTE_SERVICE_OK, "OK"},
217    {REMOTE_SERVICE_TEMPORARY_UNAVAILABLE, "TEMPORARY_UNAVAILABLE"},
218    {REMOTE_SERVICE_AUTHENTICATION_REQUIRED, "AUTHENTICATION_REQUIRED"},
219    {REMOTE_SERVICE_DISABLED, "DISABLED"},
220  };
221
222  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_data); ++i) {
223    PostUpdateServiceState(test_data[i].state, test_data[i].description);
224    EXPECT_EQ(test_data[i].state, sync_engine()->GetCurrentState())
225        << "Expected state: REMOTE_SERVICE_" << test_data[i].description;
226  }
227}
228
229TEST_F(SyncEngineTest, ProcessRemoteChange) {
230  SyncStatusCode sync_status;
231  storage::FileSystemURL url;
232  sync_engine()->ProcessRemoteChange(CreateResultReceiver(&sync_status, &url));
233  WaitForWorkerTaskRunner();
234  EXPECT_EQ(SYNC_STATUS_OK, sync_status);
235}
236
237}  // namespace drive_backend
238}  // namespace sync_file_system
239