Commit 1ee3768f authored by pavely@chromium.org's avatar pavely@chromium.org

Add AttachmentDownloader interface, change signature of AttachmentStore::Read

- AttachmentDownloader interface is similar to AttachmentUploader interface.
  No implementation yet.
- AttachmentStore::Read guarantee should be stronger. It should attempt
  to read all attachments and return list of attachment ids that can't
  be loaded locally. Those need to be downloaded from server.

R=maniscalco@chromium.org
BUG=376073

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@272585 0039d316-1c4b-4281-b951-d872f2087c98
parent c3dd3384
// Copyright 2014 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.
#include "sync/api/attachments/attachment_downloader.h"
namespace syncer {
AttachmentDownloader::~AttachmentDownloader() {
}
} // namespace syncer
// Copyright 2014 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 SYNC_API_ATTACHMENTS_ATTACHMENT_DOWNLOADER_H_
#define SYNC_API_ATTACHMENTS_ATTACHMENT_DOWNLOADER_H_
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "sync/api/attachments/attachment.h"
#include "sync/base/sync_export.h"
namespace syncer {
// AttachmentDownloader is responsible for downloading attachments from server.
class SYNC_EXPORT AttachmentDownloader {
public:
// The result of a DownloadAttachment operation.
enum DownloadResult {
DOWNLOAD_SUCCESS, // No error, attachment was downloaded
// successfully.
DOWNLOAD_UNSPECIFIED_ERROR, // An unspecified error occurred.
};
typedef base::Callback<void(const DownloadResult&, scoped_ptr<Attachment>)>
DownloadCallback;
virtual ~AttachmentDownloader();
// Download attachment referred by |attachment_id| and invoke |callback| when
// done.
//
// |callback| will receive a DownloadResult code and an Attachment object. If
// DownloadResult is not DOWNLOAD_SUCCESS then attachment pointer is NULL.
virtual void DownloadAttachment(const AttachmentId& attachment_id,
const DownloadCallback& callback) = 0;
};
} // namespace syncer
#endif // SYNC_API_ATTACHMENTS_ATTACHMENT_DOWNLOADER_H_
...@@ -95,9 +95,11 @@ void AttachmentServiceImpl::OnSyncDataUpdate( ...@@ -95,9 +95,11 @@ void AttachmentServiceImpl::OnSyncDataUpdate(
// attachments from local storage (bug 356351). // attachments from local storage (bug 356351).
} }
void AttachmentServiceImpl::ReadDone(const GetOrDownloadCallback& callback, void AttachmentServiceImpl::ReadDone(
const AttachmentStore::Result& result, const GetOrDownloadCallback& callback,
scoped_ptr<AttachmentMap> attachments) { const AttachmentStore::Result& result,
scoped_ptr<AttachmentMap> attachments,
scoped_ptr<AttachmentIdList> unavailable_attachment_ids) {
AttachmentService::GetOrDownloadResult get_result = AttachmentService::GetOrDownloadResult get_result =
AttachmentService::GET_UNSPECIFIED_ERROR; AttachmentService::GET_UNSPECIFIED_ERROR;
if (result == AttachmentStore::SUCCESS) { if (result == AttachmentStore::SUCCESS) {
......
...@@ -45,7 +45,8 @@ class SYNC_EXPORT AttachmentServiceImpl : public AttachmentService, ...@@ -45,7 +45,8 @@ class SYNC_EXPORT AttachmentServiceImpl : public AttachmentService,
private: private:
void ReadDone(const GetOrDownloadCallback& callback, void ReadDone(const GetOrDownloadCallback& callback,
const AttachmentStore::Result& result, const AttachmentStore::Result& result,
scoped_ptr<AttachmentMap> attachments); scoped_ptr<AttachmentMap> attachments,
scoped_ptr<AttachmentIdList> unavailable_attachment_ids);
void DropDone(const DropCallback& callback, void DropDone(const DropCallback& callback,
const AttachmentStore::Result& result); const AttachmentStore::Result& result);
void WriteDone(const StoreCallback& callback, void WriteDone(const StoreCallback& callback,
......
...@@ -38,17 +38,21 @@ class SYNC_EXPORT AttachmentStore { ...@@ -38,17 +38,21 @@ class SYNC_EXPORT AttachmentStore {
UNSPECIFIED_ERROR, // An unspecified error occurred for one or more items. UNSPECIFIED_ERROR, // An unspecified error occurred for one or more items.
}; };
typedef base::Callback<void(const Result&, scoped_ptr<AttachmentMap>)> typedef base::Callback<void(const Result&,
ReadCallback; scoped_ptr<AttachmentMap>,
scoped_ptr<AttachmentIdList>)> ReadCallback;
typedef base::Callback<void(const Result&)> WriteCallback; typedef base::Callback<void(const Result&)> WriteCallback;
typedef base::Callback<void(const Result&)> DropCallback; typedef base::Callback<void(const Result&)> DropCallback;
// Asynchronously reads the attachments identified by |ids|. // Asynchronously reads the attachments identified by |ids|.
// //
// |callback| will be invoked when finished. If any of the attachments do not // |callback| will be invoked when finished. AttachmentStore will attempt to
// exist or could not be read, |callback|'s Result will be UNSPECIFIED_ERROR // read all attachments specified in ids. If any of the attachments do not
// and |callback| may receive a partial result. That is, AttachmentMap may be // exist or could not be read, |callback|'s Result will be UNSPECIFIED_ERROR.
// empty or may contain the attachments that were read successfully. // Callback's AttachmentMap will contain all attachments that were
// successfully read, AttachmentIdList will contain attachment ids of
// attachments that are unavailable in attachment store, these need to be
// downloaded from server.
// //
// Reads on individual attachments are treated atomically; |callback| will not // Reads on individual attachments are treated atomically; |callback| will not
// read only part of an attachment. // read only part of an attachment.
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "sync/api/attachments/attachment.h" #include "sync/api/attachments/attachment.h"
#include "sync/base/sync_export.h" #include "sync/base/sync_export.h"
...@@ -36,7 +35,7 @@ class SYNC_EXPORT AttachmentUploader { ...@@ -36,7 +35,7 @@ class SYNC_EXPORT AttachmentUploader {
// or otherwise). // or otherwise).
// //
// |callback| will receive an UploadResult code and an updated AttachmentId // |callback| will receive an UploadResult code and an updated AttachmentId
// |containing the server address of the newly uploaded attachment. // containing the server address of the newly uploaded attachment.
virtual void UploadAttachment(const Attachment& attachment, virtual void UploadAttachment(const Attachment& attachment,
const UploadCallback& callback) = 0; const UploadCallback& callback) = 0;
}; };
......
...@@ -47,6 +47,7 @@ void FakeAttachmentStore::Backend::Read(const AttachmentIdList& ids, ...@@ -47,6 +47,7 @@ void FakeAttachmentStore::Backend::Read(const AttachmentIdList& ids,
AttachmentIdList::const_iterator id_iter = ids.begin(); AttachmentIdList::const_iterator id_iter = ids.begin();
AttachmentIdList::const_iterator id_end = ids.end(); AttachmentIdList::const_iterator id_end = ids.end();
scoped_ptr<AttachmentMap> result_map(new AttachmentMap); scoped_ptr<AttachmentMap> result_map(new AttachmentMap);
scoped_ptr<AttachmentIdList> unavailable_attachments(new AttachmentIdList);
for (; id_iter != id_end; ++id_iter) { for (; id_iter != id_end; ++id_iter) {
const AttachmentId& id = *id_iter; const AttachmentId& id = *id_iter;
syncer::AttachmentMap::iterator attachment_iter = syncer::AttachmentMap::iterator attachment_iter =
...@@ -55,12 +56,18 @@ void FakeAttachmentStore::Backend::Read(const AttachmentIdList& ids, ...@@ -55,12 +56,18 @@ void FakeAttachmentStore::Backend::Read(const AttachmentIdList& ids,
const Attachment& attachment = attachment_iter->second; const Attachment& attachment = attachment_iter->second;
result_map->insert(std::make_pair(id, attachment)); result_map->insert(std::make_pair(id, attachment));
} else { } else {
result_code = UNSPECIFIED_ERROR; unavailable_attachments->push_back(id);
break;
} }
} }
if (!unavailable_attachments->empty()) {
result_code = UNSPECIFIED_ERROR;
}
frontend_task_runner_->PostTask( frontend_task_runner_->PostTask(
FROM_HERE, base::Bind(callback, result_code, base::Passed(&result_map))); FROM_HERE,
base::Bind(callback,
result_code,
base::Passed(&result_map),
base::Passed(&unavailable_attachments)));
} }
void FakeAttachmentStore::Backend::Write(const AttachmentList& attachments, void FakeAttachmentStore::Backend::Write(const AttachmentList& attachments,
......
...@@ -23,6 +23,7 @@ class FakeAttachmentStoreTest : public testing::Test { ...@@ -23,6 +23,7 @@ class FakeAttachmentStoreTest : public testing::Test {
FakeAttachmentStore store; FakeAttachmentStore store;
AttachmentStore::Result result; AttachmentStore::Result result;
scoped_ptr<AttachmentMap> attachments; scoped_ptr<AttachmentMap> attachments;
scoped_ptr<AttachmentIdList> failed_attachment_ids;
AttachmentStore::ReadCallback read_callback; AttachmentStore::ReadCallback read_callback;
AttachmentStore::WriteCallback write_callback; AttachmentStore::WriteCallback write_callback;
...@@ -38,7 +39,8 @@ class FakeAttachmentStoreTest : public testing::Test { ...@@ -38,7 +39,8 @@ class FakeAttachmentStoreTest : public testing::Test {
read_callback = base::Bind(&FakeAttachmentStoreTest::CopyResultAttachments, read_callback = base::Bind(&FakeAttachmentStoreTest::CopyResultAttachments,
base::Unretained(this), base::Unretained(this),
&result, &result,
&attachments); &attachments,
&failed_attachment_ids);
write_callback = base::Bind( write_callback = base::Bind(
&FakeAttachmentStoreTest::CopyResult, base::Unretained(this), &result); &FakeAttachmentStoreTest::CopyResult, base::Unretained(this), &result);
drop_callback = write_callback; drop_callback = write_callback;
...@@ -59,6 +61,7 @@ class FakeAttachmentStoreTest : public testing::Test { ...@@ -59,6 +61,7 @@ class FakeAttachmentStoreTest : public testing::Test {
void Clear() { void Clear() {
result = AttachmentStore::UNSPECIFIED_ERROR; result = AttachmentStore::UNSPECIFIED_ERROR;
attachments.reset(); attachments.reset();
failed_attachment_ids.reset();
} }
void CopyResult(AttachmentStore::Result* destination_result, void CopyResult(AttachmentStore::Result* destination_result,
...@@ -66,12 +69,16 @@ class FakeAttachmentStoreTest : public testing::Test { ...@@ -66,12 +69,16 @@ class FakeAttachmentStoreTest : public testing::Test {
*destination_result = source_result; *destination_result = source_result;
} }
void CopyResultAttachments(AttachmentStore::Result* destination_result, void CopyResultAttachments(
scoped_ptr<AttachmentMap>* destination_attachments, AttachmentStore::Result* destination_result,
const AttachmentStore::Result& source_result, scoped_ptr<AttachmentMap>* destination_attachments,
scoped_ptr<AttachmentMap> source_attachments) { scoped_ptr<AttachmentIdList>* destination_failed_attachment_ids,
const AttachmentStore::Result& source_result,
scoped_ptr<AttachmentMap> source_attachments,
scoped_ptr<AttachmentIdList> source_failed_attachment_ids) {
CopyResult(destination_result, source_result); CopyResult(destination_result, source_result);
*destination_attachments = source_attachments.Pass(); *destination_attachments = source_attachments.Pass();
*destination_failed_attachment_ids = source_failed_attachment_ids.Pass();
} }
}; };
...@@ -104,6 +111,7 @@ TEST_F(FakeAttachmentStoreTest, Write_NoOverwriteNoError) { ...@@ -104,6 +111,7 @@ TEST_F(FakeAttachmentStoreTest, Write_NoOverwriteNoError) {
ClearAndPumpLoop(); ClearAndPumpLoop();
EXPECT_EQ(result, AttachmentStore::SUCCESS); EXPECT_EQ(result, AttachmentStore::SUCCESS);
EXPECT_EQ(attachments->size(), 1U); EXPECT_EQ(attachments->size(), 1U);
EXPECT_EQ(failed_attachment_ids->size(), 0U);
AttachmentMap::const_iterator a1 = attachments->find(attachment1.GetId()); AttachmentMap::const_iterator a1 = attachments->find(attachment1.GetId());
EXPECT_TRUE(a1 != attachments->end()); EXPECT_TRUE(a1 != attachments->end());
EXPECT_TRUE(attachment1.GetData()->Equals(a1->second.GetData())); EXPECT_TRUE(attachment1.GetData()->Equals(a1->second.GetData()));
...@@ -128,6 +136,7 @@ TEST_F(FakeAttachmentStoreTest, Write_RoundTrip) { ...@@ -128,6 +136,7 @@ TEST_F(FakeAttachmentStoreTest, Write_RoundTrip) {
ClearAndPumpLoop(); ClearAndPumpLoop();
EXPECT_EQ(result, AttachmentStore::SUCCESS); EXPECT_EQ(result, AttachmentStore::SUCCESS);
EXPECT_EQ(attachments->size(), 2U); EXPECT_EQ(attachments->size(), 2U);
EXPECT_EQ(failed_attachment_ids->size(), 0U);
AttachmentMap::const_iterator a1 = attachments->find(attachment1.GetId()); AttachmentMap::const_iterator a1 = attachments->find(attachment1.GetId());
EXPECT_TRUE(a1 != attachments->end()); EXPECT_TRUE(a1 != attachments->end());
...@@ -160,6 +169,7 @@ TEST_F(FakeAttachmentStoreTest, Read_OneNotFound) { ...@@ -160,6 +169,7 @@ TEST_F(FakeAttachmentStoreTest, Read_OneNotFound) {
// See that only attachment1 was read. // See that only attachment1 was read.
EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR); EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
EXPECT_EQ(attachments->size(), 1U); EXPECT_EQ(attachments->size(), 1U);
EXPECT_EQ(failed_attachment_ids->size(), 1U);
} }
// Try to drop two attachments when only one exists. Verify that no error occurs // Try to drop two attachments when only one exists. Verify that no error occurs
...@@ -187,6 +197,8 @@ TEST_F(FakeAttachmentStoreTest, Drop_DropTwoButOnlyOneExists) { ...@@ -187,6 +197,8 @@ TEST_F(FakeAttachmentStoreTest, Drop_DropTwoButOnlyOneExists) {
ClearAndPumpLoop(); ClearAndPumpLoop();
EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR); EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
EXPECT_EQ(attachments->size(), 0U); EXPECT_EQ(attachments->size(), 0U);
EXPECT_EQ(failed_attachment_ids->size(), 1U);
EXPECT_EQ((*failed_attachment_ids)[0], attachment1.GetId());
// Drop both attachment1 and attachment2. // Drop both attachment1 and attachment2.
ids.clear(); ids.clear();
...@@ -203,6 +215,8 @@ TEST_F(FakeAttachmentStoreTest, Drop_DropTwoButOnlyOneExists) { ...@@ -203,6 +215,8 @@ TEST_F(FakeAttachmentStoreTest, Drop_DropTwoButOnlyOneExists) {
ClearAndPumpLoop(); ClearAndPumpLoop();
EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR); EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
EXPECT_EQ(attachments->size(), 0U); EXPECT_EQ(attachments->size(), 0U);
EXPECT_EQ(failed_attachment_ids->size(), 1U);
EXPECT_EQ((*failed_attachment_ids)[0], attachment2.GetId());
} }
// Verify that attempting to drop an attachment that does not exist is not an // Verify that attempting to drop an attachment that does not exist is not an
...@@ -227,6 +241,8 @@ TEST_F(FakeAttachmentStoreTest, Drop_DoesNotExist) { ...@@ -227,6 +241,8 @@ TEST_F(FakeAttachmentStoreTest, Drop_DoesNotExist) {
ClearAndPumpLoop(); ClearAndPumpLoop();
EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR); EXPECT_EQ(result, AttachmentStore::UNSPECIFIED_ERROR);
EXPECT_EQ(attachments->size(), 0U); EXPECT_EQ(attachments->size(), 0U);
EXPECT_EQ(failed_attachment_ids->size(), 1U);
EXPECT_EQ((*failed_attachment_ids)[0], attachment1.GetId());
// Drop again, see that no error occurs. // Drop again, see that no error occurs.
ids.clear(); ids.clear();
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
'sources': [ 'sources': [
'api/attachments/attachment.cc', 'api/attachments/attachment.cc',
'api/attachments/attachment.h', 'api/attachments/attachment.h',
'api/attachments/attachment_downloader.cc',
'api/attachments/attachment_downloader.h',
'api/attachments/attachment_id.cc', 'api/attachments/attachment_id.cc',
'api/attachments/attachment_id.h', 'api/attachments/attachment_id.h',
'api/attachments/attachment_service.cc', 'api/attachments/attachment_service.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