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