sync_file_system_service_unittest.cc revision a3f7b4e666c476898878fa745f637129375cd889
16762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver// Copyright (c) 2012 The Chromium Authors. All rights reserved.
26762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver// Use of this source code is governed by a BSD-style license that can be
36762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver// found in the LICENSE file.
46762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
56762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include <vector>
66762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
76762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "base/basictypes.h"
86762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "base/bind.h"
96762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "base/run_loop.h"
106762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "base/stl_util.h"
116762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "base/synchronization/waitable_event.h"
126762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "chrome/browser/sync_file_system/local_file_sync_service.h"
136762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "chrome/browser/sync_file_system/mock_remote_file_sync_service.h"
146762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "chrome/browser/sync_file_system/sync_event_observer.h"
156762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "chrome/browser/sync_file_system/sync_file_system_service.h"
166762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "chrome/browser/sync_file_system/sync_file_system_test_util.h"
176762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "chrome/test/base/testing_profile.h"
186762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "content/public/browser/browser_thread.h"
196762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "content/public/test/test_browser_thread_bundle.h"
206762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "content/public/test/test_utils.h"
216762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "testing/gtest/include/gtest/gtest.h"
226762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/file_system_context.h"
236762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/canned_syncable_file_system.h"
246762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/local_file_sync_context.h"
256762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/mock_sync_status_observer.h"
266762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/sync_callbacks.h"
276762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/sync_file_metadata.h"
286762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/sync_status_code.h"
296762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver#include "webkit/browser/fileapi/syncable/syncable_file_system_util.h"
306762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
316762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing content::BrowserThread;
326762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing fileapi::FileSystemURL;
336762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing fileapi::FileSystemURLSet;
346762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::AnyNumber;
356762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::AtLeast;
366762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::InSequence;
376762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::InvokeWithoutArgs;
386762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::Return;
396762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::StrictMock;
406762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverusing ::testing::_;
416762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
426762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvernamespace sync_file_system {
436762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
446762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvernamespace {
456762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
466762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverconst char kOrigin[] = "http://example.com";
476762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
486762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvertemplate <typename R> struct AssignTrait {
496762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  typedef const R& ArgumentType;
506762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver};
516762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
526762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvertemplate <> struct AssignTrait<SyncFileStatus> {
536762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  typedef SyncFileStatus ArgumentType;
546762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver};
556762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
566762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvertemplate <typename R>
576762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvervoid AssignValueAndQuit(base::RunLoop* run_loop,
586762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                        SyncStatusCode* status_out, R* value_out,
596762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                        SyncStatusCode status,
606762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                        typename AssignTrait<R>::ArgumentType value) {
616762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  DCHECK(status_out);
626762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  DCHECK(value_out);
636762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  DCHECK(run_loop);
646762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  *status_out = status;
656762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  *value_out = value;
666762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  run_loop->Quit();
676762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver}
686762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
696762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver// This is called on IO thread.
706762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruvervoid VerifyFileError(base::RunLoop* run_loop,
716762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                     base::PlatformFileError error) {
726762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  DCHECK(run_loop);
736762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  EXPECT_EQ(base::PLATFORM_FILE_OK, error);
746762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  run_loop->Quit();
756762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver}
766762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
776762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver}  // namespace
786762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
796762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruverclass MockSyncEventObserver : public SyncEventObserver {
806762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver public:
816762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  MockSyncEventObserver() {}
826762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  virtual ~MockSyncEventObserver() {}
836762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
846762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  MOCK_METHOD3(OnSyncStateUpdated,
856762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver               void(const GURL& app_origin,
866762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                    SyncServiceState state,
876762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                    const std::string& description));
886762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  MOCK_METHOD4(OnFileSynced,
896762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver               void(const fileapi::FileSystemURL& url,
906762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                    SyncFileStatus status,
916762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                    SyncAction action,
926762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver                    SyncDirection direction));
936762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver};
946762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
956762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben GruverACTION_P3(NotifyStateAndCallback,
966762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver          mock_remote_service, service_state, operation_status) {
976762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  mock_remote_service->NotifyRemoteServiceStateUpdated(
986762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver      service_state, "Test event.");
996762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  base::MessageLoopProxy::current()->PostTask(
1006762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver      FROM_HERE, base::Bind(arg1, operation_status));
1016762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver}
1026762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver
1036762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben GruverACTION_P(RecordState, states) {
1046762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver  states->push_back(arg1);
1056762350ca0e11ca69ecb2c7bcf78cbafa2103ad6Ben Gruver}
106
107ACTION_P(MockStatusCallback, status) {
108  base::MessageLoopProxy::current()->PostTask(
109      FROM_HERE, base::Bind(arg4, status));
110}
111
112ACTION_P2(MockSyncFileCallback, status, url) {
113  base::MessageLoopProxy::current()->PostTask(
114      FROM_HERE, base::Bind(arg0, status, url));
115}
116
117class SyncFileSystemServiceTest : public testing::Test {
118 protected:
119  SyncFileSystemServiceTest()
120      : thread_bundle_(content::TestBrowserThreadBundle::REAL_FILE_THREAD |
121                       content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
122
123  virtual void SetUp() OVERRIDE {
124    file_system_.reset(new CannedSyncableFileSystem(
125        GURL(kOrigin),
126        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
127        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
128
129    local_service_ = new LocalFileSyncService(&profile_);
130    remote_service_ = new StrictMock<MockRemoteFileSyncService>;
131    sync_service_.reset(new SyncFileSystemService(&profile_));
132
133    EXPECT_CALL(*mock_remote_service(),
134                AddServiceObserver(sync_service_.get())).Times(1);
135    EXPECT_CALL(*mock_remote_service(),
136                AddFileStatusObserver(sync_service_.get())).Times(1);
137    EXPECT_CALL(*mock_remote_service(),
138                GetLocalChangeProcessor())
139        .WillOnce(Return(&local_change_processor_));
140    EXPECT_CALL(*mock_remote_service(),
141                SetRemoteChangeProcessor(local_service_)).Times(1);
142
143    sync_service_->Initialize(
144        make_scoped_ptr(local_service_),
145        scoped_ptr<RemoteFileSyncService>(remote_service_));
146
147    // Disable auto sync by default.
148    EXPECT_CALL(*mock_remote_service(), SetSyncEnabled(false)).Times(1);
149    sync_service_->SetSyncEnabledForTesting(false);
150
151    file_system_->SetUp();
152  }
153
154  virtual void TearDown() OVERRIDE {
155    sync_service_->Shutdown();
156    file_system_->TearDown();
157    RevokeSyncableFileSystem();
158    content::RunAllPendingInMessageLoop(BrowserThread::FILE);
159  }
160
161  void InitializeApp() {
162    base::RunLoop run_loop;
163    SyncStatusCode status = SYNC_STATUS_UNKNOWN;
164
165    EXPECT_CALL(*mock_remote_service(),
166                RegisterOriginForTrackingChanges(GURL(kOrigin), _)).Times(1);
167
168    sync_service_->InitializeForApp(
169        file_system_->file_system_context(),
170        GURL(kOrigin),
171        AssignAndQuitCallback(&run_loop, &status));
172    run_loop.Run();
173
174    EXPECT_EQ(SYNC_STATUS_OK, status);
175    EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->OpenFileSystem());
176  }
177
178  // Calls InitializeForApp after setting up the mock remote service to
179  // perform following when RegisterOriginForTrackingChanges is called:
180  //  1. Notify RemoteFileSyncService's observers of |state_to_notify|
181  //  2. Run the given callback with |status_to_return|.
182  //
183  // ..and verifies if following conditions are met:
184  //  1. The SyncEventObserver of the service is called with
185  //     |expected_states| service state values.
186  //  2. InitializeForApp's callback is called with |expected_status|
187  //  3. GetCurrentState() is called at least |expected_current_state_calls|
188  //     times (which means that the sync service tried to start sync).
189  void InitializeAppForObserverTest(
190      RemoteServiceState state_to_notify,
191      SyncStatusCode status_to_return,
192      const std::vector<SyncServiceState> expected_states,
193      SyncStatusCode expected_status) {
194    StrictMock<MockSyncEventObserver> event_observer;
195    sync_service_->AddSyncEventObserver(&event_observer);
196
197    EnableSync();
198
199    EXPECT_CALL(*mock_remote_service(),
200                RegisterOriginForTrackingChanges(GURL(kOrigin), _))
201        .WillOnce(NotifyStateAndCallback(mock_remote_service(),
202                                         state_to_notify,
203                                         status_to_return));
204
205    std::vector<SyncServiceState> actual_states;
206    EXPECT_CALL(event_observer, OnSyncStateUpdated(GURL(), _, _))
207        .WillRepeatedly(RecordState(&actual_states));
208
209    SyncStatusCode actual_status = SYNC_STATUS_UNKNOWN;
210    base::RunLoop run_loop;
211    sync_service_->InitializeForApp(
212        file_system_->file_system_context(),
213        GURL(kOrigin),
214        AssignAndQuitCallback(&run_loop, &actual_status));
215    run_loop.Run();
216
217    EXPECT_EQ(expected_status, actual_status);
218    ASSERT_EQ(expected_states.size(), actual_states.size());
219    for (size_t i = 0; i < actual_states.size(); ++i)
220      EXPECT_EQ(expected_states[i], actual_states[i]);
221  }
222
223  FileSystemURL URL(const std::string& path) const {
224    return file_system_->URL(path);
225  }
226
227  StrictMock<MockRemoteFileSyncService>* mock_remote_service() {
228    return remote_service_;
229  }
230
231  StrictMock<MockLocalChangeProcessor>* mock_local_change_processor() {
232    return &local_change_processor_;
233  }
234
235  void EnableSync() {
236    EXPECT_CALL(*mock_remote_service(), SetSyncEnabled(true)).Times(1);
237    sync_service_->SetSyncEnabledForTesting(true);
238  }
239
240  ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
241
242  content::TestBrowserThreadBundle thread_bundle_;
243  TestingProfile profile_;
244  scoped_ptr<CannedSyncableFileSystem> file_system_;
245
246  // Their ownerships are transferred to SyncFileSystemService.
247  LocalFileSyncService* local_service_;
248  StrictMock<MockRemoteFileSyncService>* remote_service_;
249  StrictMock<MockLocalChangeProcessor> local_change_processor_;
250
251  scoped_ptr<SyncFileSystemService> sync_service_;
252};
253
254TEST_F(SyncFileSystemServiceTest, InitializeForApp) {
255  InitializeApp();
256}
257
258TEST_F(SyncFileSystemServiceTest, InitializeForAppSuccess) {
259  std::vector<SyncServiceState> expected_states;
260  expected_states.push_back(SYNC_SERVICE_RUNNING);
261
262  InitializeAppForObserverTest(
263      REMOTE_SERVICE_OK,
264      SYNC_STATUS_OK,
265      expected_states,
266      SYNC_STATUS_OK);
267}
268
269TEST_F(SyncFileSystemServiceTest, InitializeForAppWithNetworkFailure) {
270  std::vector<SyncServiceState> expected_states;
271  expected_states.push_back(SYNC_SERVICE_TEMPORARY_UNAVAILABLE);
272
273  // Notify REMOTE_SERVICE_TEMPORARY_UNAVAILABLE and callback with
274  // SYNC_STATUS_NETWORK_ERROR.  This should let the
275  // InitializeApp fail.
276  InitializeAppForObserverTest(
277      REMOTE_SERVICE_TEMPORARY_UNAVAILABLE,
278      SYNC_STATUS_NETWORK_ERROR,
279      expected_states,
280      SYNC_STATUS_NETWORK_ERROR);
281}
282
283TEST_F(SyncFileSystemServiceTest, InitializeForAppWithError) {
284  std::vector<SyncServiceState> expected_states;
285  expected_states.push_back(SYNC_SERVICE_DISABLED);
286
287  // Notify REMOTE_SERVICE_DISABLED and callback with
288  // SYNC_STATUS_FAILED.  This should let the InitializeApp fail.
289  InitializeAppForObserverTest(
290      REMOTE_SERVICE_DISABLED,
291      SYNC_STATUS_FAILED,
292      expected_states,
293      SYNC_STATUS_FAILED);
294}
295
296// Flaky.  http://crbug.com/237710
297TEST_F(SyncFileSystemServiceTest, DISABLED_SimpleLocalSyncFlow) {
298  InitializeApp();
299
300  StrictMock<MockSyncStatusObserver> status_observer;
301
302  EnableSync();
303  file_system_->file_system_context()->sync_context()->
304      set_mock_notify_changes_duration_in_sec(0);
305  file_system_->AddSyncStatusObserver(&status_observer);
306
307  // We'll test one local sync for this file.
308  const FileSystemURL kFile(file_system_->URL("foo"));
309
310  base::RunLoop run_loop;
311
312  // We should get called OnSyncEnabled and OnWriteEnabled on kFile.
313  // (We quit the run loop when OnWriteEnabled is called on kFile)
314  EXPECT_CALL(status_observer, OnSyncEnabled(kFile))
315      .Times(AtLeast(1));
316  EXPECT_CALL(status_observer, OnWriteEnabled(kFile))
317      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
318
319  // We expect a set of method calls for starting a local sync.
320  EXPECT_CALL(*mock_remote_service(), GetCurrentState())
321      .Times(AtLeast(2))
322      .WillRepeatedly(Return(REMOTE_SERVICE_OK));
323
324  // The local_change_processor's ApplyLocalChange should be called once
325  // with ADD_OR_UPDATE change for TYPE_FILE.
326  const FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
327                          SYNC_FILE_TYPE_FILE);
328  EXPECT_CALL(*mock_local_change_processor(),
329              ApplyLocalChange(change, _, _, kFile, _))
330      .WillOnce(MockStatusCallback(SYNC_STATUS_OK));
331
332  EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->CreateFile(kFile));
333
334  run_loop.Run();
335}
336
337TEST_F(SyncFileSystemServiceTest, SimpleRemoteSyncFlow) {
338  InitializeApp();
339
340  EnableSync();
341
342  base::RunLoop run_loop;
343
344  // We expect a set of method calls for starting a remote sync.
345  EXPECT_CALL(*mock_remote_service(), GetCurrentState())
346      .Times(AtLeast(1))
347      .WillRepeatedly(Return(REMOTE_SERVICE_OK));
348  EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
349      .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
350
351  // This should trigger a remote sync.
352  mock_remote_service()->NotifyRemoteChangeQueueUpdated(1);
353
354  run_loop.Run();
355}
356
357TEST_F(SyncFileSystemServiceTest, SimpleSyncFlowWithFileBusy) {
358  InitializeApp();
359
360  EnableSync();
361  file_system_->file_system_context()->sync_context()->
362      set_mock_notify_changes_duration_in_sec(0);
363
364  const FileSystemURL kFile(file_system_->URL("foo"));
365
366  base::RunLoop run_loop;
367
368  // We expect a set of method calls for starting a remote sync.
369  EXPECT_CALL(*mock_remote_service(), GetCurrentState())
370      .Times(AtLeast(3))
371      .WillRepeatedly(Return(REMOTE_SERVICE_OK));
372
373  {
374    InSequence sequence;
375
376    // Return with SYNC_STATUS_FILE_BUSY once.
377    EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
378        .WillOnce(MockSyncFileCallback(SYNC_STATUS_FILE_BUSY,
379                                       kFile));
380
381    // ProcessRemoteChange should be called again when the becomes
382    // not busy.
383    EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_))
384        .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
385  }
386
387  // We might also see an activity for local sync as we're going to make
388  // a local write operation on kFile.
389  EXPECT_CALL(*mock_local_change_processor(),
390              ApplyLocalChange(_, _, _, kFile, _))
391      .Times(AnyNumber());
392
393  // This should trigger a remote sync.
394  mock_remote_service()->NotifyRemoteChangeQueueUpdated(1);
395
396  // Start a local operation on the same file (to make it BUSY).
397  base::RunLoop verify_file_error_run_loop;
398  BrowserThread::PostTask(
399      BrowserThread::IO,
400      FROM_HERE,
401      base::Bind(&CannedSyncableFileSystem::DoCreateFile,
402                 base::Unretained(file_system_.get()),
403                 kFile, base::Bind(&VerifyFileError,
404                                   &verify_file_error_run_loop)));
405
406  run_loop.Run();
407
408  mock_remote_service()->NotifyRemoteChangeQueueUpdated(0);
409
410  verify_file_error_run_loop.Run();
411}
412
413TEST_F(SyncFileSystemServiceTest, GetFileSyncStatus) {
414  InitializeApp();
415
416  const FileSystemURL kFile(file_system_->URL("foo"));
417
418  SyncStatusCode status;
419  SyncFileStatus sync_file_status;
420
421  // 1. The file is not in conflicting nor in pending change state.
422  {
423    base::RunLoop run_loop;
424    EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
425        .WillOnce(Return(false));
426
427    status = SYNC_STATUS_UNKNOWN;
428    sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
429    sync_service_->GetFileSyncStatus(
430        kFile,
431        base::Bind(&AssignValueAndQuit<SyncFileStatus>,
432                   &run_loop, &status, &sync_file_status));
433    run_loop.Run();
434
435    EXPECT_EQ(SYNC_STATUS_OK, status);
436    EXPECT_EQ(SYNC_FILE_STATUS_SYNCED, sync_file_status);
437  }
438
439  // 2. Conflicting case.
440  {
441    base::RunLoop run_loop;
442    EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
443        .WillOnce(Return(true));
444
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_CONFLICTING, sync_file_status);
455  }
456
457  // 3. The file has pending local changes.
458  {
459    EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->CreateFile(kFile));
460
461    base::RunLoop run_loop;
462    EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
463        .WillOnce(Return(false));
464
465    status = SYNC_STATUS_UNKNOWN;
466    sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
467    sync_service_->GetFileSyncStatus(
468        kFile,
469        base::Bind(&AssignValueAndQuit<SyncFileStatus>,
470                   &run_loop, &status, &sync_file_status));
471    run_loop.Run();
472
473    EXPECT_EQ(SYNC_STATUS_OK, status);
474    EXPECT_EQ(SYNC_FILE_STATUS_HAS_PENDING_CHANGES, sync_file_status);
475  }
476
477  // 4. The file has a conflict and pending local changes. In this case
478  // we return SYNC_FILE_STATUS_CONFLICTING.
479  {
480    EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->TruncateFile(kFile, 1U));
481
482    base::RunLoop run_loop;
483    EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
484        .WillOnce(Return(true));
485
486    status = SYNC_STATUS_UNKNOWN;
487    sync_file_status = SYNC_FILE_STATUS_UNKNOWN;
488    sync_service_->GetFileSyncStatus(
489        kFile,
490        base::Bind(&AssignValueAndQuit<SyncFileStatus>,
491                   &run_loop, &status, &sync_file_status));
492    run_loop.Run();
493
494    EXPECT_EQ(SYNC_STATUS_OK, status);
495    EXPECT_EQ(SYNC_FILE_STATUS_CONFLICTING, sync_file_status);
496  }
497}
498
499}  // namespace sync_file_system
500