Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync_file_system / sync_file_system_service_unittest.cc
1 // Copyright (c) 2012 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 <vector>
6
7 #include "base/basictypes.h"
8 #include "base/bind.h"
9 #include "base/run_loop.h"
10 #include "base/stl_util.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
13 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
14 #include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
15 #include "chrome/browser/sync_file_system/local/mock_sync_status_observer.h"
16 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
17 #include "chrome/browser/sync_file_system/mock_remote_file_sync_service.h"
18 #include "chrome/browser/sync_file_system/sync_callbacks.h"
19 #include "chrome/browser/sync_file_system/sync_event_observer.h"
20 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
21 #include "chrome/browser/sync_file_system/sync_file_system_service.h"
22 #include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
23 #include "chrome/browser/sync_file_system/sync_status_code.h"
24 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
25 #include "chrome/test/base/testing_profile.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/test/test_browser_thread_bundle.h"
28 #include "content/public/test/test_utils.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
31 #include "third_party/leveldatabase/src/include/leveldb/env.h"
32 #include "webkit/browser/fileapi/file_system_context.h"
33
34 using content::BrowserThread;
35 using fileapi::FileSystemURL;
36 using fileapi::FileSystemURLSet;
37 using ::testing::AnyNumber;
38 using ::testing::AtLeast;
39 using ::testing::InSequence;
40 using ::testing::InvokeWithoutArgs;
41 using ::testing::Return;
42 using ::testing::StrictMock;
43 using ::testing::_;
44
45 namespace sync_file_system {
46
47 namespace {
48
49 const char kOrigin[] = "http://example.com";
50
51 template <typename R> struct AssignTrait {
52   typedef const R& ArgumentType;
53 };
54
55 template <> struct AssignTrait<SyncFileStatus> {
56   typedef SyncFileStatus ArgumentType;
57 };
58
59 template <typename R>
60 void AssignValueAndQuit(base::RunLoop* run_loop,
61                         SyncStatusCode* status_out, R* value_out,
62                         SyncStatusCode status,
63                         typename AssignTrait<R>::ArgumentType value) {
64   DCHECK(status_out);
65   DCHECK(value_out);
66   DCHECK(run_loop);
67   *status_out = status;
68   *value_out = value;
69   run_loop->Quit();
70 }
71
72 // This is called on IO thread.
73 void VerifyFileError(base::RunLoop* run_loop,
74                      base::File::Error error) {
75   DCHECK(run_loop);
76   EXPECT_EQ(base::File::FILE_OK, error);
77   run_loop->Quit();
78 }
79
80 }  // namespace
81
82 class MockSyncEventObserver : public SyncEventObserver {
83  public:
84   MockSyncEventObserver() {}
85   virtual ~MockSyncEventObserver() {}
86
87   MOCK_METHOD3(OnSyncStateUpdated,
88                void(const GURL& app_origin,
89                     SyncServiceState state,
90                     const std::string& description));
91   MOCK_METHOD4(OnFileSynced,
92                void(const fileapi::FileSystemURL& url,
93                     SyncFileStatus status,
94                     SyncAction action,
95                     SyncDirection direction));
96 };
97
98 ACTION_P3(NotifyStateAndCallback,
99           mock_remote_service, service_state, operation_status) {
100   mock_remote_service->NotifyRemoteServiceStateUpdated(
101       service_state, "Test event.");
102   base::MessageLoopProxy::current()->PostTask(
103       FROM_HERE, base::Bind(arg1, operation_status));
104 }
105
106 ACTION_P(RecordState, states) {
107   states->push_back(arg1);
108 }
109
110 ACTION_P(MockStatusCallback, status) {
111   base::MessageLoopProxy::current()->PostTask(
112       FROM_HERE, base::Bind(arg4, status));
113 }
114
115 ACTION_P2(MockSyncFileCallback, status, url) {
116   base::MessageLoopProxy::current()->PostTask(
117       FROM_HERE, base::Bind(arg0, status, url));
118 }
119
120 class SyncFileSystemServiceTest : public testing::Test {
121  protected:
122   SyncFileSystemServiceTest()
123       : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD |
124                        content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
125
126   virtual void SetUp() OVERRIDE {
127     in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
128     file_system_.reset(new CannedSyncableFileSystem(
129         GURL(kOrigin),
130         in_memory_env_.get(),
131         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
132         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
133
134     scoped_ptr<LocalFileSyncService> local_service =
135         LocalFileSyncService::CreateForTesting(&profile_, in_memory_env_.get());
136     remote_service_ = new StrictMock<MockRemoteFileSyncService>;
137     sync_service_.reset(new SyncFileSystemService(&profile_));
138
139     EXPECT_CALL(*mock_remote_service(),
140                 AddServiceObserver(_)).Times(1);
141     EXPECT_CALL(*mock_remote_service(),
142                 AddFileStatusObserver(sync_service_.get())).Times(1);
143     EXPECT_CALL(*mock_remote_service(),
144                 GetLocalChangeProcessor())
145         .WillRepeatedly(Return(&local_change_processor_));
146     EXPECT_CALL(*mock_remote_service(),
147                 SetRemoteChangeProcessor(local_service.get())).Times(1);
148
149     sync_service_->Initialize(
150         local_service.Pass(),
151         scoped_ptr<RemoteFileSyncService>(remote_service_));
152
153     // Disable auto sync by default.
154     EXPECT_CALL(*mock_remote_service(), SetSyncEnabled(false)).Times(1);
155     sync_service_->SetSyncEnabledForTesting(false);
156
157     file_system_->SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
158   }
159
160   virtual void TearDown() OVERRIDE {
161     sync_service_->Shutdown();
162     file_system_->TearDown();
163     RevokeSyncableFileSystem();
164     content::RunAllPendingInMessageLoop(BrowserThread::FILE);
165   }
166
167   void InitializeApp() {
168     base::RunLoop run_loop;
169     SyncStatusCode status = SYNC_STATUS_UNKNOWN;
170
171     EXPECT_CALL(*mock_remote_service(),
172                 RegisterOrigin(GURL(kOrigin), _)).Times(1);
173
174     // GetCurrentState may be called when a remote or local sync is scheduled
175     // by change notifications or by a timer.
176     EXPECT_CALL(*mock_remote_service(), GetCurrentState())
177         .Times(AnyNumber())
178         .WillRepeatedly(Return(REMOTE_SERVICE_OK));
179
180     sync_service_->InitializeForApp(
181         file_system_->file_system_context(),
182         GURL(kOrigin),
183         AssignAndQuitCallback(&run_loop, &status));
184     run_loop.Run();
185
186     EXPECT_EQ(SYNC_STATUS_OK, status);
187     EXPECT_EQ(base::File::FILE_OK, file_system_->OpenFileSystem());
188   }
189
190   // Calls InitializeForApp after setting up the mock remote service to
191   // perform following when RegisterOrigin is called:
192   //  1. Notify RemoteFileSyncService's observers of |state_to_notify|
193   //  2. Run the given callback with |status_to_return|.
194   //
195   // ..and verifies if following conditions are met:
196   //  1. The SyncEventObserver of the service is called with
197   //     |expected_states| service state values.
198   //  2. InitializeForApp's callback is called with |expected_status|
199   void InitializeAppForObserverTest(
200       RemoteServiceState state_to_notify,
201       SyncStatusCode status_to_return,
202       const std::vector<SyncServiceState>& expected_states,
203       SyncStatusCode expected_status) {
204     StrictMock<MockSyncEventObserver> event_observer;
205     sync_service_->AddSyncEventObserver(&event_observer);
206
207     EnableSync();
208
209     EXPECT_CALL(*mock_remote_service(), GetCurrentState())
210         .Times(AnyNumber())
211         .WillRepeatedly(Return(state_to_notify));
212
213     EXPECT_CALL(*mock_remote_service(),
214                 RegisterOrigin(GURL(kOrigin), _))
215         .WillOnce(NotifyStateAndCallback(mock_remote_service(),
216                                          state_to_notify,
217                                          status_to_return));
218
219     std::vector<SyncServiceState> actual_states;
220     EXPECT_CALL(event_observer, OnSyncStateUpdated(GURL(), _, _))
221         .WillRepeatedly(RecordState(&actual_states));
222
223     SyncStatusCode actual_status = SYNC_STATUS_UNKNOWN;
224     base::RunLoop run_loop;
225     sync_service_->InitializeForApp(
226         file_system_->file_system_context(),
227         GURL(kOrigin),
228         AssignAndQuitCallback(&run_loop, &actual_status));
229     run_loop.Run();
230
231     EXPECT_EQ(expected_status, actual_status);
232     ASSERT_EQ(expected_states.size(), actual_states.size());
233     for (size_t i = 0; i < actual_states.size(); ++i)
234       EXPECT_EQ(expected_states[i], actual_states[i]);
235
236     sync_service_->RemoveSyncEventObserver(&event_observer);
237   }
238
239   FileSystemURL URL(const std::string& path) const {
240     return file_system_->URL(path);
241   }
242
243   StrictMock<MockRemoteFileSyncService>* mock_remote_service() {
244     return remote_service_;
245   }
246
247   StrictMock<MockLocalChangeProcessor>* mock_local_change_processor() {
248     return &local_change_processor_;
249   }
250
251   void EnableSync() {
252     EXPECT_CALL(*mock_remote_service(), SetSyncEnabled(true)).Times(1);
253     sync_service_->SetSyncEnabledForTesting(true);
254   }
255
256   ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
257
258   content::TestBrowserThreadBundle thread_bundle_;
259   scoped_ptr<leveldb::Env> in_memory_env_;
260   TestingProfile profile_;
261   scoped_ptr<CannedSyncableFileSystem> file_system_;
262
263   // Their ownerships are transferred to SyncFileSystemService.
264   StrictMock<MockRemoteFileSyncService>* remote_service_;
265   StrictMock<MockLocalChangeProcessor> local_change_processor_;
266
267   scoped_ptr<SyncFileSystemService> sync_service_;
268 };
269
270 TEST_F(SyncFileSystemServiceTest, InitializeForApp) {
271   InitializeApp();
272 }
273
274 TEST_F(SyncFileSystemServiceTest, InitializeForAppSuccess) {
275   std::vector<SyncServiceState> expected_states;
276   expected_states.push_back(SYNC_SERVICE_RUNNING);
277
278   InitializeAppForObserverTest(
279       REMOTE_SERVICE_OK,
280       SYNC_STATUS_OK,
281       expected_states,
282       SYNC_STATUS_OK);
283 }
284
285 TEST_F(SyncFileSystemServiceTest, InitializeForAppWithNetworkFailure) {
286   std::vector<SyncServiceState> expected_states;
287   expected_states.push_back(SYNC_SERVICE_TEMPORARY_UNAVAILABLE);
288
289   // Notify REMOTE_SERVICE_TEMPORARY_UNAVAILABLE and callback with
290   // SYNC_STATUS_NETWORK_ERROR.  This should let the
291   // InitializeApp fail.
292   InitializeAppForObserverTest(
293       REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
294       SYNC_STATUS_NETWORK_ERROR,
295       expected_states,
296       SYNC_STATUS_NETWORK_ERROR);
297 }
298
299 TEST_F(SyncFileSystemServiceTest, InitializeForAppWithError) {
300   std::vector<SyncServiceState> expected_states;
301   expected_states.push_back(SYNC_SERVICE_DISABLED);
302
303   // Notify REMOTE_SERVICE_DISABLED and callback with
304   // SYNC_STATUS_FAILED.  This should let the InitializeApp fail.
305   InitializeAppForObserverTest(
306       REMOTE_SERVICE_DISABLED,
307       SYNC_STATUS_FAILED,
308       expected_states,
309       SYNC_STATUS_FAILED);
310 }
311
312 TEST_F(SyncFileSystemServiceTest, SimpleLocalSyncFlow) {
313   InitializeApp();
314
315   StrictMock<MockSyncStatusObserver> status_observer;
316
317   EnableSync();
318   file_system_->backend()->sync_context()->
319       set_mock_notify_changes_duration_in_sec(0);
320   file_system_->AddSyncStatusObserver(&status_observer);
321
322   // We'll test one local sync for this file.
323   const FileSystemURL kFile(file_system_->URL("foo"));
324
325   base::RunLoop run_loop;
326
327   // We should get called OnSyncEnabled and OnWriteEnabled on kFile as in:
328   // 1. OnWriteEnabled when PrepareForSync(SYNC_SHARED) is finished and
329   //    the target file is unlocked for writing
330   // 2. OnSyncEnabled x 3 times; 1) when CreateFile is finished, 2) when
331   //    file is unlocked after PrepareForSync, and 3) when the sync is
332   //    finished.
333   EXPECT_CALL(status_observer, OnWriteEnabled(kFile))
334       .Times(AtLeast(1));
335
336   {
337     ::testing::InSequence sequence;
338     EXPECT_CALL(status_observer, OnSyncEnabled(kFile))
339         .Times(AtLeast(2));
340     EXPECT_CALL(status_observer, OnSyncEnabled(kFile))
341         .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
342   }
343
344   // The local_change_processor's ApplyLocalChange should be called once
345   // with ADD_OR_UPDATE change for TYPE_FILE.
346   const FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
347                           SYNC_FILE_TYPE_FILE);
348   EXPECT_CALL(*mock_local_change_processor(),
349               ApplyLocalChange(change, _, _, kFile, _))
350       .WillOnce(MockStatusCallback(SYNC_STATUS_OK));
351
352   EXPECT_EQ(base::File::FILE_OK, file_system_->CreateFile(kFile));
353
354   run_loop.Run();
355
356   file_system_->RemoveSyncStatusObserver(&status_observer);
357 }
358
359 TEST_F(SyncFileSystemServiceTest, SimpleRemoteSyncFlow) {
360   InitializeApp();
361
362   EnableSync();
363
364   base::RunLoop run_loop;
365
366   // We expect a set of method calls for starting a remote sync.
367   EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
368       .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
369
370   // This should trigger a remote sync.
371   mock_remote_service()->NotifyRemoteChangeQueueUpdated(1);
372
373   run_loop.Run();
374 }
375
376 TEST_F(SyncFileSystemServiceTest, SimpleSyncFlowWithFileBusy) {
377   InitializeApp();
378
379   EnableSync();
380   file_system_->backend()->sync_context()->
381       set_mock_notify_changes_duration_in_sec(0);
382
383   const FileSystemURL kFile(file_system_->URL("foo"));
384
385   base::RunLoop run_loop;
386
387   {
388     InSequence sequence;
389
390     // Return with SYNC_STATUS_FILE_BUSY once.
391     EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
392         .WillOnce(MockSyncFileCallback(SYNC_STATUS_FILE_BUSY,
393                                        kFile));
394
395     // ProcessRemoteChange should be called again when the becomes
396     // not busy.
397     EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
398         .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
399   }
400
401   // We might also see an activity for local sync as we're going to make
402   // a local write operation on kFile.
403   EXPECT_CALL(*mock_local_change_processor(),
404               ApplyLocalChange(_, _, _, kFile, _))
405       .Times(AnyNumber());
406
407   // This should trigger a remote sync.
408   mock_remote_service()->NotifyRemoteChangeQueueUpdated(1);
409
410   // Start a local operation on the same file (to make it BUSY).
411   base::RunLoop verify_file_error_run_loop;
412   BrowserThread::PostTask(
413       BrowserThread::IO,
414       FROM_HERE,
415       base::Bind(&CannedSyncableFileSystem::DoCreateFile,
416                  base::Unretained(file_system_.get()),
417                  kFile, base::Bind(&VerifyFileError,
418                                    &verify_file_error_run_loop)));
419
420   run_loop.Run();
421
422   mock_remote_service()->NotifyRemoteChangeQueueUpdated(0);
423
424   verify_file_error_run_loop.Run();
425 }
426
427 #if defined(THREAD_SANITIZER)
428 // SyncFileSystemServiceTest.GetFileSyncStatus fails under ThreadSanitizer,
429 // see http://crbug.com/294904.
430 #define MAYBE_GetFileSyncStatus DISABLED_GetFileSyncStatus
431 #else
432 #define MAYBE_GetFileSyncStatus GetFileSyncStatus
433 #endif
434 TEST_F(SyncFileSystemServiceTest, MAYBE_GetFileSyncStatus) {
435   InitializeApp();
436
437   const FileSystemURL kFile(file_system_->URL("foo"));
438
439   SyncStatusCode status;
440   SyncFileStatus sync_file_status;
441
442   // 1. The file is synced state.
443   {
444     base::RunLoop run_loop;
445     status = SYNC_STATUS_UNKNOWN;
446     sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
447     sync_service_->GetFileSyncStatus(
448         kFile,
449         base::Bind(&AssignValueAndQuit<SyncFileStatus>,
450                    &run_loop, &status, &sync_file_status));
451     run_loop.Run();
452
453     EXPECT_EQ(SYNC_STATUS_OK, status);
454     EXPECT_EQ(SYNC_FILE_STATUS_SYNCED, sync_file_status);
455   }
456
457   // 2. The file has pending local changes.
458   {
459     base::RunLoop run_loop;
460     EXPECT_EQ(base::File::FILE_OK, file_system_->CreateFile(kFile));
461
462     status = SYNC_STATUS_UNKNOWN;
463     sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
464     sync_service_->GetFileSyncStatus(
465         kFile,
466         base::Bind(&AssignValueAndQuit<SyncFileStatus>,
467                    &run_loop, &status, &sync_file_status));
468     run_loop.Run();
469
470     EXPECT_EQ(SYNC_STATUS_OK, status);
471     EXPECT_EQ(SYNC_FILE_STATUS_HAS_PENDING_CHANGES, sync_file_status);
472   }
473 }
474
475 }  // namespace sync_file_system