Commit afef1535 authored by kinuko@chromium.org's avatar kinuko@chromium.org

Implement SyncFileSystemService::GetFileSyncStatus method

- The method takes FileSystemURL and returns a new enum: fileapi::SyncFileStatus, which takes one of either: UNKNOWN, SYNCED, HAS_PENDING_CHANGES or CONFLICTING

BUG=163860
TEST=SyncFileSystemService.GetFileSyncStatus

Review URL: https://codereview.chromium.org/11421197

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170886 0039d316-1c4b-4281-b951-d872f2087c98
parent 1aa5f6a6
......@@ -359,6 +359,17 @@ LocalChangeProcessor* DriveFileSyncService::GetLocalChangeProcessor() {
return this;
}
bool DriveFileSyncService::IsConflicting(const fileapi::FileSystemURL& url) {
DriveMetadata metadata;
const fileapi::SyncStatusCode status =
metadata_store_->ReadEntry(url, &metadata);
if (status != fileapi::SYNC_STATUS_OK) {
DCHECK_EQ(fileapi::SYNC_DATABASE_ERROR_NOT_FOUND, status);
return false;
}
return metadata.conflicted();
}
void DriveFileSyncService::GetConflictFiles(
const GURL& origin,
const fileapi::SyncFileSetCallback& callback) {
......
......@@ -69,6 +69,7 @@ class DriveFileSyncService
RemoteChangeProcessor* processor,
const fileapi::SyncOperationCallback& callback) OVERRIDE;
virtual LocalChangeProcessor* GetLocalChangeProcessor() OVERRIDE;
virtual bool IsConflicting(const fileapi::FileSystemURL& url) OVERRIDE;
virtual void GetConflictFiles(
const GURL& origin,
const fileapi::SyncFileSetCallback& callback) OVERRIDE;
......
......@@ -140,6 +140,14 @@ void LocalFileSyncService::ProcessLocalChange(
AsWeakPtr(), processor));
}
void LocalFileSyncService::HasPendingLocalChanges(
const fileapi::FileSystemURL& url,
const HasPendingLocalChangeCallback& callback) {
DCHECK(ContainsKey(origin_to_contexts_, url.origin()));
sync_context_->HasPendingLocalChanges(
origin_to_contexts_[url.origin()], url, callback);
}
void LocalFileSyncService::GetLocalFileMetadata(
const fileapi::FileSystemURL& url,
const SyncFileMetadataCallback& callback) {
......
......@@ -52,6 +52,9 @@ class LocalFileSyncService
DISALLOW_COPY_AND_ASSIGN(Observer);
};
typedef base::Callback<void(bool has_pending_changes)>
HasPendingLocalChangeCallback;
LocalFileSyncService();
virtual ~LocalFileSyncService();
......@@ -80,6 +83,12 @@ class LocalFileSyncService
void ProcessLocalChange(LocalChangeProcessor* processor,
const fileapi::SyncFileCallback& callback);
// Returns true via |callback| if the given file |url| has local pending
// changes.
void HasPendingLocalChanges(
const fileapi::FileSystemURL& url,
const HasPendingLocalChangeCallback& callback);
// Returns the metadata of a remote file pointed by |url|.
virtual void GetLocalFileMetadata(
const fileapi::FileSystemURL& url,
......
......@@ -32,6 +32,8 @@ MockRemoteFileSyncService::MockRemoteFileSyncService() {
.WillByDefault(Invoke(this, &self::ProcessRemoteChangeStub));
ON_CALL(*this, GetLocalChangeProcessor())
.WillByDefault(Return(&mock_local_change_processor_));
ON_CALL(*this, IsConflicting(_))
.WillByDefault(Return(false));
ON_CALL(*this, GetConflictFiles(_, _))
.WillByDefault(Invoke(this, &self::GetConflictFilesStub));
ON_CALL(*this, GetRemoteFileMetadata(_, _))
......
......@@ -37,6 +37,7 @@ class MockRemoteFileSyncService : public RemoteFileSyncService {
void(RemoteChangeProcessor* processor,
const fileapi::SyncOperationCallback& callback));
MOCK_METHOD0(GetLocalChangeProcessor, LocalChangeProcessor*());
MOCK_METHOD1(IsConflicting, bool(const fileapi::FileSystemURL& url));
MOCK_METHOD2(GetConflictFiles,
void(const GURL& origin,
const fileapi::SyncFileSetCallback& callback));
......
......@@ -108,6 +108,11 @@ class RemoteFileSyncService {
// storage backed by this service.
virtual LocalChangeProcessor* GetLocalChangeProcessor() = 0;
// Returns true if the file |url| is marked conflicted in the remote service.
virtual bool IsConflicting(const fileapi::FileSystemURL& url) = 0;
// TODO(kinuko,tzik): Clean up unused interface methods when we fix
// the manual conflict resolution API.
// Returns a list of conflicting files for the given origin.
virtual void GetConflictFiles(
const GURL& origin,
......
......@@ -214,6 +214,36 @@ void SyncFileSystemService::GetConflictFileInfo(
url, callback_runner->CreateAssignAndRunCallback(remote_metadata));
}
void SyncFileSystemService::GetFileSyncStatus(
const fileapi::FileSystemURL& url,
const fileapi::SyncFileStatusCallback& callback) {
DCHECK(local_file_service_);
DCHECK(remote_file_service_);
if (!ContainsKey(initialized_app_origins_, url.origin())) {
base::MessageLoopProxy::current()->PostTask(
FROM_HERE,
base::Bind(callback,
fileapi::SYNC_STATUS_NOT_INITIALIZED,
fileapi::SYNC_FILE_STATUS_UNKNOWN));
return;
}
if (remote_file_service_->IsConflicting(url)) {
base::MessageLoopProxy::current()->PostTask(
FROM_HERE,
base::Bind(callback,
fileapi::SYNC_STATUS_OK,
fileapi::SYNC_FILE_STATUS_CONFLICTING));
return;
}
local_file_service_->HasPendingLocalChanges(
url,
base::Bind(&SyncFileSystemService::DidGetLocalChangeStatus,
AsWeakPtr(), callback));
}
void SyncFileSystemService::AddSyncEventObserver(SyncEventObserver* observer) {
observers_.AddObserver(observer);
}
......@@ -397,6 +427,15 @@ void SyncFileSystemService::DidProcessLocalChange(
AsWeakPtr()));
}
void SyncFileSystemService::DidGetLocalChangeStatus(
const fileapi::SyncFileStatusCallback& callback,
bool has_pending_local_changes) {
callback.Run(
fileapi::SYNC_STATUS_OK,
has_pending_local_changes ? fileapi::SYNC_FILE_STATUS_HAS_PENDING_CHANGES
: fileapi::SYNC_FILE_STATUS_SYNCED);
}
void SyncFileSystemService::OnSyncEnabledForRemoteSync() {
is_waiting_remote_sync_enabled_ = false;
MaybeStartRemoteSync();
......
......@@ -57,6 +57,11 @@ class SyncFileSystemService
const fileapi::FileSystemURL& url,
const fileapi::ConflictFileInfoCallback& callback);
// Returns the file |url|'s sync status.
void GetFileSyncStatus(
const fileapi::FileSystemURL& url,
const fileapi::SyncFileStatusCallback& callback);
void AddSyncEventObserver(SyncEventObserver* observer);
void RemoveSyncEventObserver(SyncEventObserver* observer);
......@@ -111,6 +116,9 @@ class SyncFileSystemService
void DidProcessLocalChange(fileapi::SyncStatusCode status,
const fileapi::FileSystemURL& url);
void DidGetLocalChangeStatus(const fileapi::SyncFileStatusCallback& callback,
bool has_pending_local_changes);
void OnSyncEnabledForRemoteSync();
// RemoteFileSyncService::Observer overrides.
......
......@@ -44,10 +44,19 @@ namespace {
const char kOrigin[] = "http://example.com";
const char kServiceName[] = "test";
template <typename R> struct AssignTrait {
typedef const R& ArgumentType;
};
template <> struct AssignTrait<fileapi::SyncFileStatus> {
typedef fileapi::SyncFileStatus ArgumentType;
};
template <typename R>
void AssignValueAndQuit(base::RunLoop* run_loop,
SyncStatusCode* status_out, R* value_out,
SyncStatusCode status, const R& value) {
SyncStatusCode status,
typename AssignTrait<R>::ArgumentType value) {
DCHECK(status_out);
DCHECK(value_out);
DCHECK(run_loop);
......@@ -507,8 +516,7 @@ TEST_F(SyncFileSystemServiceTest, SimpleSyncFlowWithFileBusy) {
EXPECT_CALL(*mock_remote_service(), ProcessRemoteChange(_, _))
.WillOnce(MockSyncOperationCallback(fileapi::SYNC_STATUS_FILE_BUSY,
kFile,
fileapi::SYNC_OPERATION_NONE))
.RetiresOnSaturation();
fileapi::SYNC_OPERATION_NONE));
// ProcessRemoteChange should be called again when the becomes
// not busy.
......@@ -538,4 +546,90 @@ TEST_F(SyncFileSystemServiceTest, SimpleSyncFlowWithFileBusy) {
event.Wait();
}
TEST_F(SyncFileSystemServiceTest, GetFileSyncStatus) {
InitializeApp();
const FileSystemURL kFile(file_system_->URL("foo"));
fileapi::SyncStatusCode status;
fileapi::SyncFileStatus sync_file_status;
// 1. The file is not in conflicting nor in pending change state.
{
base::RunLoop run_loop;
EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
.WillOnce(Return(false));
status = fileapi::SYNC_STATUS_UNKNOWN;
sync_file_status = fileapi::SYNC_FILE_STATUS_UNKNOWN;
sync_service_->GetFileSyncStatus(
kFile,
base::Bind(&AssignValueAndQuit<fileapi::SyncFileStatus>,
&run_loop, &status, &sync_file_status));
run_loop.Run();
EXPECT_EQ(fileapi::SYNC_STATUS_OK, status);
EXPECT_EQ(fileapi::SYNC_FILE_STATUS_SYNCED, sync_file_status);
}
// 2. Conflicting case.
{
base::RunLoop run_loop;
EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
.WillOnce(Return(true));
status = fileapi::SYNC_STATUS_UNKNOWN;
sync_file_status = fileapi::SYNC_FILE_STATUS_UNKNOWN;
sync_service_->GetFileSyncStatus(
kFile,
base::Bind(&AssignValueAndQuit<fileapi::SyncFileStatus>,
&run_loop, &status, &sync_file_status));
run_loop.Run();
EXPECT_EQ(fileapi::SYNC_STATUS_OK, status);
EXPECT_EQ(fileapi::SYNC_FILE_STATUS_CONFLICTING, sync_file_status);
}
// 3. The file has pending local changes.
{
EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->CreateFile(kFile));
base::RunLoop run_loop;
EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
.WillOnce(Return(false));
status = fileapi::SYNC_STATUS_UNKNOWN;
sync_file_status = fileapi::SYNC_FILE_STATUS_UNKNOWN;
sync_service_->GetFileSyncStatus(
kFile,
base::Bind(&AssignValueAndQuit<fileapi::SyncFileStatus>,
&run_loop, &status, &sync_file_status));
run_loop.Run();
EXPECT_EQ(fileapi::SYNC_STATUS_OK, status);
EXPECT_EQ(fileapi::SYNC_FILE_STATUS_HAS_PENDING_CHANGES, sync_file_status);
}
// 4. The file has a conflict and pending local changes. In this case
// we return SYNC_FILE_STATUS_CONFLICTING.
{
EXPECT_EQ(base::PLATFORM_FILE_OK, file_system_->TruncateFile(kFile, 1U));
base::RunLoop run_loop;
EXPECT_CALL(*mock_remote_service(), IsConflicting(kFile))
.WillOnce(Return(true));
status = fileapi::SYNC_STATUS_UNKNOWN;
sync_file_status = fileapi::SYNC_FILE_STATUS_UNKNOWN;
sync_service_->GetFileSyncStatus(
kFile,
base::Bind(&AssignValueAndQuit<fileapi::SyncFileStatus>,
&run_loop, &status, &sync_file_status));
run_loop.Run();
EXPECT_EQ(fileapi::SYNC_STATUS_OK, status);
EXPECT_EQ(fileapi::SYNC_FILE_STATUS_CONFLICTING, sync_file_status);
}
}
} // namespace sync_file_system
......@@ -232,6 +232,31 @@ void LocalFileSyncContext::GetFileMetadata(
this, callback));
}
void LocalFileSyncContext::HasPendingLocalChanges(
FileSystemContext* file_system_context,
const FileSystemURL& url,
const HasPendingLocalChangeCallback& callback) {
// This gets called on UI thread and relays the task on FILE thread.
DCHECK(file_system_context);
if (!file_system_context->task_runners()->file_task_runner()->
RunsTasksOnCurrentThread()) {
DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
file_system_context->task_runners()->file_task_runner()->PostTask(
FROM_HERE,
base::Bind(&LocalFileSyncContext::HasPendingLocalChanges,
this, make_scoped_refptr(file_system_context),
url, callback));
return;
}
DCHECK(file_system_context->change_tracker());
FileChangeList changes;
file_system_context->change_tracker()->GetChangesForURL(url, &changes);
// Fire the callback on UI thread.
ui_task_runner_->PostTask(FROM_HERE, base::Bind(callback, !changes.empty()));
}
void LocalFileSyncContext::AddOriginChangeObserver(
LocalOriginChangeObserver* observer) {
origin_change_observers_.AddObserver(observer);
......
......@@ -51,6 +51,9 @@ class WEBKIT_STORAGE_EXPORT LocalFileSyncContext
const LocalFileSyncInfo& sync_file_info)>
LocalFileSyncInfoCallback;
typedef base::Callback<void(bool has_pending_changes)>
HasPendingLocalChangeCallback;
LocalFileSyncContext(base::SingleThreadTaskRunner* ui_task_runner,
base::SingleThreadTaskRunner* io_task_runner);
......@@ -116,6 +119,13 @@ class WEBKIT_STORAGE_EXPORT LocalFileSyncContext
const FileSystemURL& url,
const SyncFileMetadataCallback& callback);
// Returns true via |callback| if the given file |url| has local pending
// changes.
void HasPendingLocalChanges(
FileSystemContext* file_system_context,
const FileSystemURL& url,
const HasPendingLocalChangeCallback& callback);
// They must be called on UI thread.
void AddOriginChangeObserver(LocalOriginChangeObserver* observer);
void RemoveOriginChangeObserver(LocalOriginChangeObserver* observer);
......
......@@ -7,6 +7,7 @@
#include "base/callback_forward.h"
#include "webkit/fileapi/file_system_url.h"
#include "webkit/fileapi/syncable/sync_file_status.h"
#include "webkit/fileapi/syncable/sync_operation_type.h"
#include "webkit/fileapi/syncable/sync_status_code.h"
......@@ -40,6 +41,10 @@ typedef base::Callback<void(SyncStatusCode status,
SyncOperationType operation_type)>
SyncOperationCallback;
typedef base::Callback<void(SyncStatusCode status,
SyncFileStatus sync_file_status)>
SyncFileStatusCallback;
} // namespace fileapi
#endif // WEBKIT_FILEAPI_SYNCABLE_SYNC_CALLBACKS_H_
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBKIT_FILEAPI_SYNCABLE_SYNC_FILE_STATUS_H_
#define WEBKIT_FILEAPI_SYNCABLE_SYNC_FILE_STATUS_H_
namespace fileapi {
enum SyncFileStatus {
// The file has unknown sync status (e.g. the file is missing or there
// was an error while retrieving the sync status for the file).
SYNC_FILE_STATUS_UNKNOWN,
// The file has no pending local changes (may have pending remote changes
// though).
SYNC_FILE_STATUS_SYNCED,
// The file has pending local changes that haven't been reflected to the
// remote side.
SYNC_FILE_STATUS_HAS_PENDING_CHANGES,
// The file is in conflicting state.
SYNC_FILE_STATUS_CONFLICTING,
};
} // namespace fileapi
#endif // WEBKIT_FILEAPI_SYNCABLE_SYNC_FILE_STATUS_H_
......@@ -90,6 +90,7 @@
'../fileapi/syncable/sync_callbacks.h',
'../fileapi/syncable/sync_file_metadata.cc',
'../fileapi/syncable/sync_file_metadata.h',
'../fileapi/syncable/sync_file_status.h',
'../fileapi/syncable/sync_file_type.h',
'../fileapi/syncable/sync_operation_type.h',
'../fileapi/syncable/sync_status_code.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment