Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / sync_file_system_service_unittest.cc
bloba6ebecef2b5675a86e95874715ec2daa66837487
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/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 "webkit/browser/fileapi/file_system_context.h"
32 using content::BrowserThread;
33 using fileapi::FileSystemURL;
34 using fileapi::FileSystemURLSet;
35 using ::testing::AnyNumber;
36 using ::testing::AtLeast;
37 using ::testing::InSequence;
38 using ::testing::InvokeWithoutArgs;
39 using ::testing::Return;
40 using ::testing::StrictMock;
41 using ::testing::_;
43 namespace sync_file_system {
45 namespace {
47 const char kOrigin[] = "http://example.com";
49 template <typename R> struct AssignTrait {
50 typedef const R& ArgumentType;
53 template <> struct AssignTrait<SyncFileStatus> {
54 typedef SyncFileStatus ArgumentType;
57 template <typename R>
58 void AssignValueAndQuit(base::RunLoop* run_loop,
59 SyncStatusCode* status_out, R* value_out,
60 SyncStatusCode status,
61 typename AssignTrait<R>::ArgumentType value) {
62 DCHECK(status_out);
63 DCHECK(value_out);
64 DCHECK(run_loop);
65 *status_out = status;
66 *value_out = value;
67 run_loop->Quit();
70 // This is called on IO thread.
71 void VerifyFileError(base::RunLoop* run_loop,
72 base::PlatformFileError error) {
73 DCHECK(run_loop);
74 EXPECT_EQ(base::PLATFORM_FILE_OK, error);
75 run_loop->Quit();
78 } // namespace
80 class MockSyncEventObserver : public SyncEventObserver {
81 public:
82 MockSyncEventObserver() {}
83 virtual ~MockSyncEventObserver() {}
85 MOCK_METHOD3(OnSyncStateUpdated,
86 void(const GURL& app_origin,
87 SyncServiceState state,
88 const std::string& description));
89 MOCK_METHOD4(OnFileSynced,
90 void(const fileapi::FileSystemURL& url,
91 SyncFileStatus status,
92 SyncAction action,
93 SyncDirection direction));
96 ACTION_P3(NotifyStateAndCallback,
97 mock_remote_service, service_state, operation_status) {
98 mock_remote_service->NotifyRemoteServiceStateUpdated(
99 service_state, "Test event.");
100 base::MessageLoopProxy::current()->PostTask(
101 FROM_HERE, base::Bind(arg1, operation_status));
104 ACTION_P(RecordState, states) {
105 states->push_back(arg1);
108 ACTION_P(MockStatusCallback, status) {
109 base::MessageLoopProxy::current()->PostTask(
110 FROM_HERE, base::Bind(arg4, status));
113 ACTION_P2(MockSyncFileCallback, status, url) {
114 base::MessageLoopProxy::current()->PostTask(
115 FROM_HERE, base::Bind(arg0, status, url));
118 class SyncFileSystemServiceTest : public testing::Test {
119 protected:
120 SyncFileSystemServiceTest()
121 : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD |
122 content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
124 virtual void SetUp() OVERRIDE {
125 file_system_.reset(new CannedSyncableFileSystem(
126 GURL(kOrigin),
127 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
128 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
130 local_service_ = new LocalFileSyncService(&profile_);
131 remote_service_ = new StrictMock<MockRemoteFileSyncService>;
132 sync_service_.reset(new SyncFileSystemService(&profile_));
134 EXPECT_CALL(*mock_remote_service(),
135 AddServiceObserver(_)).Times(1);
136 EXPECT_CALL(*mock_remote_service(),
137 AddFileStatusObserver(sync_service_.get())).Times(1);
138 EXPECT_CALL(*mock_remote_service(),
139 GetLocalChangeProcessor())
140 .WillRepeatedly(Return(&local_change_processor_));
141 EXPECT_CALL(*mock_remote_service(),
142 SetRemoteChangeProcessor(local_service_)).Times(1);
144 sync_service_->Initialize(
145 make_scoped_ptr(local_service_),
146 scoped_ptr<RemoteFileSyncService>(remote_service_));
148 // Disable auto sync by default.
149 EXPECT_CALL(*mock_remote_service(), SetSyncEnabled(false)).Times(1);
150 sync_service_->SetSyncEnabledForTesting(false);
152 file_system_->SetUp();
155 virtual void TearDown() OVERRIDE {
156 sync_service_->Shutdown();
157 file_system_->TearDown();
158 RevokeSyncableFileSystem();
159 content::RunAllPendingInMessageLoop(BrowserThread::FILE);
162 void InitializeApp() {
163 base::RunLoop run_loop;
164 SyncStatusCode status = SYNC_STATUS_UNKNOWN;
166 EXPECT_CALL(*mock_remote_service(),
167 RegisterOrigin(GURL(kOrigin), _)).Times(1);
169 // GetCurrentState may be called when a remote or local sync is scheduled
170 // by change notifications or by a timer.
171 EXPECT_CALL(*mock_remote_service(), GetCurrentState())
172 .Times(AnyNumber())
173 .WillRepeatedly(Return(REMOTE_SERVICE_OK));
175 sync_service_->InitializeForApp(
176 file_system_->file_system_context(),
177 GURL(kOrigin),
178 AssignAndQuitCallback(&run_loop, &status));
179 run_loop.Run();
181 EXPECT_EQ(SYNC_STATUS_OK, status);
182 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->OpenFileSystem());
185 // Calls InitializeForApp after setting up the mock remote service to
186 // perform following when RegisterOrigin is called:
187 // 1. Notify RemoteFileSyncService's observers of |state_to_notify|
188 // 2. Run the given callback with |status_to_return|.
190 // ..and verifies if following conditions are met:
191 // 1. The SyncEventObserver of the service is called with
192 // |expected_states| service state values.
193 // 2. InitializeForApp's callback is called with |expected_status|
194 void InitializeAppForObserverTest(
195 RemoteServiceState state_to_notify,
196 SyncStatusCode status_to_return,
197 const std::vector<SyncServiceState>& expected_states,
198 SyncStatusCode expected_status) {
199 StrictMock<MockSyncEventObserver> event_observer;
200 sync_service_->AddSyncEventObserver(&event_observer);
202 EnableSync();
204 EXPECT_CALL(*mock_remote_service(), GetCurrentState())
205 .Times(AnyNumber())
206 .WillRepeatedly(Return(state_to_notify));
208 EXPECT_CALL(*mock_remote_service(),
209 RegisterOrigin(GURL(kOrigin), _))
210 .WillOnce(NotifyStateAndCallback(mock_remote_service(),
211 state_to_notify,
212 status_to_return));
214 std::vector<SyncServiceState> actual_states;
215 EXPECT_CALL(event_observer, OnSyncStateUpdated(GURL(), _, _))
216 .WillRepeatedly(RecordState(&actual_states));
218 SyncStatusCode actual_status = SYNC_STATUS_UNKNOWN;
219 base::RunLoop run_loop;
220 sync_service_->InitializeForApp(
221 file_system_->file_system_context(),
222 GURL(kOrigin),
223 AssignAndQuitCallback(&run_loop, &actual_status));
224 run_loop.Run();
226 EXPECT_EQ(expected_status, actual_status);
227 ASSERT_EQ(expected_states.size(), actual_states.size());
228 for (size_t i = 0; i < actual_states.size(); ++i)
229 EXPECT_EQ(expected_states[i], actual_states[i]);
231 sync_service_->RemoveSyncEventObserver(&event_observer);
234 FileSystemURL URL(const std::string& path) const {
235 return file_system_->URL(path);
238 StrictMock<MockRemoteFileSyncService>* mock_remote_service() {
239 return remote_service_;
242 StrictMock<MockLocalChangeProcessor>* mock_local_change_processor() {
243 return &local_change_processor_;
246 void EnableSync() {
247 EXPECT_CALL(*mock_remote_service(), SetSyncEnabled(true)).Times(1);
248 sync_service_->SetSyncEnabledForTesting(true);
251 ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
253 content::TestBrowserThreadBundle thread_bundle_;
254 TestingProfile profile_;
255 scoped_ptr<CannedSyncableFileSystem> file_system_;
257 // Their ownerships are transferred to SyncFileSystemService.
258 LocalFileSyncService* local_service_;
259 StrictMock<MockRemoteFileSyncService>* remote_service_;
260 StrictMock<MockLocalChangeProcessor> local_change_processor_;
262 scoped_ptr<SyncFileSystemService> sync_service_;
265 TEST_F(SyncFileSystemServiceTest, InitializeForApp) {
266 InitializeApp();
269 TEST_F(SyncFileSystemServiceTest, InitializeForAppSuccess) {
270 std::vector<SyncServiceState> expected_states;
271 expected_states.push_back(SYNC_SERVICE_RUNNING);
273 InitializeAppForObserverTest(
274 REMOTE_SERVICE_OK,
275 SYNC_STATUS_OK,
276 expected_states,
277 SYNC_STATUS_OK);
280 TEST_F(SyncFileSystemServiceTest, InitializeForAppWithNetworkFailure) {
281 std::vector<SyncServiceState> expected_states;
282 expected_states.push_back(SYNC_SERVICE_TEMPORARY_UNAVAILABLE);
284 // Notify REMOTE_SERVICE_TEMPORARY_UNAVAILABLE and callback with
285 // SYNC_STATUS_NETWORK_ERROR. This should let the
286 // InitializeApp fail.
287 InitializeAppForObserverTest(
288 REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
289 SYNC_STATUS_NETWORK_ERROR,
290 expected_states,
291 SYNC_STATUS_NETWORK_ERROR);
294 TEST_F(SyncFileSystemServiceTest, InitializeForAppWithError) {
295 std::vector<SyncServiceState> expected_states;
296 expected_states.push_back(SYNC_SERVICE_DISABLED);
298 // Notify REMOTE_SERVICE_DISABLED and callback with
299 // SYNC_STATUS_FAILED. This should let the InitializeApp fail.
300 InitializeAppForObserverTest(
301 REMOTE_SERVICE_DISABLED,
302 SYNC_STATUS_FAILED,
303 expected_states,
304 SYNC_STATUS_FAILED);
307 TEST_F(SyncFileSystemServiceTest, SimpleLocalSyncFlow) {
308 InitializeApp();
310 StrictMock<MockSyncStatusObserver> status_observer;
312 EnableSync();
313 file_system_->backend()->sync_context()->
314 set_mock_notify_changes_duration_in_sec(0);
315 file_system_->AddSyncStatusObserver(&status_observer);
317 // We'll test one local sync for this file.
318 const FileSystemURL kFile(file_system_->URL("foo"));
320 base::RunLoop run_loop;
322 // We should get called OnSyncEnabled and OnWriteEnabled on kFile as in:
323 // 1. OnWriteEnabled when PrepareForSync(SYNC_SHARED) is finished and
324 // the target file is unlocked for writing
325 // 2. OnSyncEnabled x 3 times; 1) when CreateFile is finished, 2) when
326 // file is unlocked after PrepareForSync, and 3) when the sync is
327 // finished.
328 EXPECT_CALL(status_observer, OnWriteEnabled(kFile))
329 .Times(AtLeast(1));
332 ::testing::InSequence sequence;
333 EXPECT_CALL(status_observer, OnSyncEnabled(kFile))
334 .Times(AtLeast(2));
335 EXPECT_CALL(status_observer, OnSyncEnabled(kFile))
336 .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
339 // The local_change_processor's ApplyLocalChange should be called once
340 // with ADD_OR_UPDATE change for TYPE_FILE.
341 const FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
342 SYNC_FILE_TYPE_FILE);
343 EXPECT_CALL(*mock_local_change_processor(),
344 ApplyLocalChange(change, _, _, kFile, _))
345 .WillOnce(MockStatusCallback(SYNC_STATUS_OK));
347 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->CreateFile(kFile));
349 run_loop.Run();
351 file_system_->RemoveSyncStatusObserver(&status_observer);
354 TEST_F(SyncFileSystemServiceTest, SimpleRemoteSyncFlow) {
355 InitializeApp();
357 EnableSync();
359 base::RunLoop run_loop;
361 // We expect a set of method calls for starting a remote sync.
362 EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
363 .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
365 // This should trigger a remote sync.
366 mock_remote_service()->NotifyRemoteChangeQueueUpdated(1);
368 run_loop.Run();
371 TEST_F(SyncFileSystemServiceTest, SimpleSyncFlowWithFileBusy) {
372 InitializeApp();
374 EnableSync();
375 file_system_->backend()->sync_context()->
376 set_mock_notify_changes_duration_in_sec(0);
378 const FileSystemURL kFile(file_system_->URL("foo"));
380 base::RunLoop run_loop;
383 InSequence sequence;
385 // Return with SYNC_STATUS_FILE_BUSY once.
386 EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
387 .WillOnce(MockSyncFileCallback(SYNC_STATUS_FILE_BUSY,
388 kFile));
390 // ProcessRemoteChange should be called again when the becomes
391 // not busy.
392 EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
393 .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
396 // We might also see an activity for local sync as we're going to make
397 // a local write operation on kFile.
398 EXPECT_CALL(*mock_local_change_processor(),
399 ApplyLocalChange(_, _, _, kFile, _))
400 .Times(AnyNumber());
402 // This should trigger a remote sync.
403 mock_remote_service()->NotifyRemoteChangeQueueUpdated(1);
405 // Start a local operation on the same file (to make it BUSY).
406 base::RunLoop verify_file_error_run_loop;
407 BrowserThread::PostTask(
408 BrowserThread::IO,
409 FROM_HERE,
410 base::Bind(&CannedSyncableFileSystem::DoCreateFile,
411 base::Unretained(file_system_.get()),
412 kFile, base::Bind(&VerifyFileError,
413 &verify_file_error_run_loop)));
415 run_loop.Run();
417 mock_remote_service()->NotifyRemoteChangeQueueUpdated(0);
419 verify_file_error_run_loop.Run();
422 #if defined(THREAD_SANITIZER)
423 // SyncFileSystemServiceTest.GetFileSyncStatus fails under ThreadSanitizer,
424 // see http://crbug.com/294904.
425 #define MAYBE_GetFileSyncStatus DISABLED_GetFileSyncStatus
426 #else
427 #define MAYBE_GetFileSyncStatus GetFileSyncStatus
428 #endif
429 TEST_F(SyncFileSystemServiceTest, MAYBE_GetFileSyncStatus) {
430 InitializeApp();
432 const FileSystemURL kFile(file_system_->URL("foo"));
434 SyncStatusCode status;
435 SyncFileStatus sync_file_status;
437 // 1. The file is not in conflicting nor in pending change state.
439 base::RunLoop run_loop;
440 EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
441 .WillOnce(Return(false));
443 status = SYNC_STATUS_UNKNOWN;
444 sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
445 sync_service_->GetFileSyncStatus(
446 kFile,
447 base::Bind(&AssignValueAndQuit<SyncFileStatus>,
448 &run_loop, &status, &sync_file_status));
449 run_loop.Run();
451 EXPECT_EQ(SYNC_STATUS_OK, status);
452 EXPECT_EQ(SYNC_FILE_STATUS_SYNCED, sync_file_status);
455 // 2. Conflicting case.
457 base::RunLoop run_loop;
458 EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
459 .WillOnce(Return(true));
461 status = SYNC_STATUS_UNKNOWN;
462 sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
463 sync_service_->GetFileSyncStatus(
464 kFile,
465 base::Bind(&AssignValueAndQuit<SyncFileStatus>,
466 &run_loop, &status, &sync_file_status));
467 run_loop.Run();
469 EXPECT_EQ(SYNC_STATUS_OK, status);
470 EXPECT_EQ(SYNC_FILE_STATUS_CONFLICTING, sync_file_status);
473 // 3. The file has pending local changes.
475 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->CreateFile(kFile));
477 base::RunLoop run_loop;
478 EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
479 .WillOnce(Return(false));
481 status = SYNC_STATUS_UNKNOWN;
482 sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
483 sync_service_->GetFileSyncStatus(
484 kFile,
485 base::Bind(&AssignValueAndQuit<SyncFileStatus>,
486 &run_loop, &status, &sync_file_status));
487 run_loop.Run();
489 EXPECT_EQ(SYNC_STATUS_OK, status);
490 EXPECT_EQ(SYNC_FILE_STATUS_HAS_PENDING_CHANGES, sync_file_status);
493 // 4. The file has a conflict and pending local changes. In this case
494 // we return SYNC_FILE_STATUS_CONFLICTING.
496 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->TruncateFile(kFile, 1U));
498 base::RunLoop run_loop;
499 EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
500 .WillOnce(Return(true));
502 status = SYNC_STATUS_UNKNOWN;
503 sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
504 sync_service_->GetFileSyncStatus(
505 kFile,
506 base::Bind(&AssignValueAndQuit<SyncFileStatus>,
507 &run_loop, &status, &sync_file_status));
508 run_loop.Run();
510 EXPECT_EQ(SYNC_STATUS_OK, status);
511 EXPECT_EQ(SYNC_FILE_STATUS_CONFLICTING, sync_file_status);
515 } // namespace sync_file_system