Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(831)

Unified Diff: sync/internal_api/attachments/attachment_uploader_impl_unittest.cc

Issue 278263003: Add a minimal AttachmentUploaderImpl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Apply CR feedback from pavely. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sync/internal_api/attachments/attachment_uploader_impl_unittest.cc
diff --git a/sync/internal_api/attachments/attachment_uploader_impl_unittest.cc b/sync/internal_api/attachments/attachment_uploader_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6fcfd8682532d04ea327f4a86f614bbcb0aa4b4b
--- /dev/null
+++ b/sync/internal_api/attachments/attachment_uploader_impl_unittest.cc
@@ -0,0 +1,257 @@
+// 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/internal_api/public/attachments/attachment_uploader_impl.h"
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/url_request/url_request_test_util.h"
+#include "sync/api/attachments/attachment.h"
+#include "sync/protocol/sync.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kAttachmentData[] = "some data";
+
+} // namespace
+
+namespace syncer {
+
+using net::test_server::BasicHttpResponse;
+using net::test_server::HttpRequest;
+using net::test_server::HttpResponse;
+
+class AttachmentUploaderImplTest;
pavely 2014/05/15 23:27:28 Not needed
maniscalco 2014/05/16 16:46:37 Done.
+class RequestHandler;
+
+// Text fixture for AttachmentUploaderImpl test.
+//
+// This fixture provides an embedded HTTP server for interacting with
+// AttachmentUploaderImpl.
+class AttachmentUploaderImplTest : public testing::Test,
+ public base::NonThreadSafe {
+ public:
+ void OnRequestReceived(const HttpRequest& request);
+
+ protected:
+ AttachmentUploaderImplTest();
+ virtual void SetUp();
+
+ // Run the message loop until UploadDone has been invoked |num_invocations|
+ // times.
+ void RunAndQuitAfter(int num_invocations);
+
+ scoped_ptr<AttachmentUploader>& uploader();
+ const AttachmentUploader::UploadCallback& upload_callback() const;
+ std::vector<HttpRequest>& http_requests_received();
+ std::vector<AttachmentUploader::UploadResult>& upload_results();
+ std::vector<AttachmentId>& updated_attachment_ids();
+
+ private:
+ base::MessageLoopForIO message_loop_;
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+ scoped_ptr<RequestHandler> request_handler_;
+ scoped_ptr<AttachmentUploader> uploader_;
+ AttachmentUploader::UploadCallback upload_callback_;
+ net::test_server::EmbeddedTestServer server_;
+
+ // Number of times we expect UploadDone to be invoked.
+ int invocations_remaining_;
+ std::vector<HttpRequest> http_requests_received_;
+ std::vector<AttachmentUploader::UploadResult> upload_results_;
+ std::vector<AttachmentId> updated_attachment_ids_;
+
+ private:
+ // An UploadCallback invoked by AttachmentUploaderImpl.
+ void UploadDone(const AttachmentUploader::UploadResult& result,
+ const AttachmentId& updated_attachment_id);
+
+ // Must be last data member.
+ base::WeakPtrFactory<AttachmentUploaderImplTest> weak_ptr_factory_;
+};
+
+// Handles HTTP requests received by the EmbeddedTestServer.
+class RequestHandler : public base::NonThreadSafe {
pavely 2014/05/15 23:27:28 Do you really need RequestHandler as separate clas
maniscalco 2014/05/16 16:46:37 Not strictly necessary, but I found it made it eas
+ public:
+ // Construct a RequestHandler that will PostTask to |test| using
+ // |test_task_runner|.
+ RequestHandler(
+ const scoped_refptr<base::SingleThreadTaskRunner>& test_task_runner,
+ const base::WeakPtr<AttachmentUploaderImplTest>& test);
+
+ ~RequestHandler();
+
+ scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request);
+
+ private:
+ scoped_refptr<base::SingleThreadTaskRunner> test_task_runner_;
+ base::WeakPtr<AttachmentUploaderImplTest> test_;
+};
+
+AttachmentUploaderImplTest::AttachmentUploaderImplTest()
+ : invocations_remaining_(0), weak_ptr_factory_(this) {
+}
+
+void AttachmentUploaderImplTest::OnRequestReceived(const HttpRequest& request) {
+ DCHECK(CalledOnValidThread());
+ http_requests_received_.push_back(request);
+}
+
+void AttachmentUploaderImplTest::SetUp() {
+ DCHECK(CalledOnValidThread());
+ request_handler_.reset(new RequestHandler(message_loop_.message_loop_proxy(),
+ weak_ptr_factory_.GetWeakPtr()));
+ url_request_context_getter_ =
+ new net::TestURLRequestContextGetter(message_loop_.message_loop_proxy());
+
+ ASSERT_TRUE(server_.InitializeAndWaitUntilReady());
+ server_.RegisterRequestHandler(
+ base::Bind(&RequestHandler::HandleRequest,
+ base::Unretained(request_handler_.get())));
+
+ std::string url_prefix(
+ base::StringPrintf("http://localhost:%d/uploads/", server_.port()));
+
+ uploader().reset(
+ new AttachmentUploaderImpl(url_prefix, url_request_context_getter_));
+ upload_callback_ = base::Bind(&AttachmentUploaderImplTest::UploadDone,
+ base::Unretained(this));
+}
+
+void AttachmentUploaderImplTest::RunAndQuitAfter(int num_invocations) {
+ invocations_remaining_ = num_invocations;
+ message_loop_.Run();
pavely 2014/05/15 23:27:28 In some previous change Tim asked me not to use Me
maniscalco 2014/05/16 16:46:37 I like this pattern better. Done. Thanks for poi
+}
+
+scoped_ptr<AttachmentUploader>& AttachmentUploaderImplTest::uploader() {
+ return uploader_;
+}
+
+const AttachmentUploader::UploadCallback&
+AttachmentUploaderImplTest::upload_callback() const {
+ return upload_callback_;
+}
+
+std::vector<HttpRequest>& AttachmentUploaderImplTest::http_requests_received() {
+ return http_requests_received_;
+}
+
+std::vector<AttachmentUploader::UploadResult>&
+AttachmentUploaderImplTest::upload_results() {
+ return upload_results_;
+}
+
+std::vector<AttachmentId>&
+AttachmentUploaderImplTest::updated_attachment_ids() {
+ return updated_attachment_ids_;
+}
+
+void AttachmentUploaderImplTest::UploadDone(
+ const AttachmentUploader::UploadResult& result,
+ const AttachmentId& updated_attachment_id) {
+ DCHECK(CalledOnValidThread());
+ upload_results_.push_back(result);
+ updated_attachment_ids_.push_back(updated_attachment_id);
+ --invocations_remaining_;
+ if (invocations_remaining_ == 0) {
+ base::MessageLoop::current()->Quit();
+ }
+}
+
+RequestHandler::RequestHandler(
+ const scoped_refptr<base::SingleThreadTaskRunner>& test_task_runner,
+ const base::WeakPtr<AttachmentUploaderImplTest>& test)
+ : test_task_runner_(test_task_runner), test_(test) {
+ DetachFromThread();
+}
+
+RequestHandler::~RequestHandler() {
+ DetachFromThread();
+}
+
+scoped_ptr<HttpResponse> RequestHandler::HandleRequest(
+ const HttpRequest& request) {
+ DCHECK(CalledOnValidThread());
+ test_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &AttachmentUploaderImplTest::OnRequestReceived, test_, request));
+ scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse);
+ http_response->set_code(net::HTTP_OK);
+ http_response->set_content("hello");
+ http_response->set_content_type("text/plain");
+ return http_response.PassAs<HttpResponse>();
+}
+
+// Verify the "happy case" of uploading an attachment.
+TEST_F(AttachmentUploaderImplTest, UploadAttachment_HappyCase) {
+ scoped_refptr<base::RefCountedString> some_data(new base::RefCountedString);
+ some_data->data() = kAttachmentData;
+ Attachment attachment = Attachment::Create(some_data);
+ uploader()->UploadAttachment(attachment, upload_callback());
+ RunAndQuitAfter(1);
+
+ // See that the HTTP server received one request.
+ EXPECT_EQ(1U, http_requests_received().size());
+ const HttpRequest& http_request = http_requests_received().front();
+ EXPECT_EQ(net::test_server::METHOD_POST, http_request.method);
+ std::string expected_relative_url("/uploads/" +
+ attachment.GetId().GetProto().unique_id());
+ EXPECT_EQ(expected_relative_url, http_request.relative_url);
+ EXPECT_TRUE(http_request.has_content);
+ EXPECT_EQ(kAttachmentData, http_request.content);
+
+ // See that the UploadCallback received a result and updated AttachmentId.
+ EXPECT_EQ(1U, upload_results().size());
+ EXPECT_EQ(1U, updated_attachment_ids().size());
+ EXPECT_EQ(AttachmentUploader::UPLOAD_SUCCESS, upload_results().front());
+ EXPECT_EQ(attachment.GetId(), updated_attachment_ids().front());
+ // TODO(maniscalco): Once AttachmentUploaderImpl is capable of updating the
+ // AttachmentId with server address information about the attachment, add some
+ // checks here to verify it works properly (bug 371522).
+}
+
+// Verify two overlapping calls to upload the same attachment result in only one
+// HTTP request.
+TEST_F(AttachmentUploaderImplTest, UploadAttachment_Collapse) {
+ scoped_refptr<base::RefCountedString> some_data(new base::RefCountedString);
+ some_data->data() = kAttachmentData;
+ Attachment attachment1 = Attachment::Create(some_data);
+ Attachment attachment2 = attachment1;
+ uploader()->UploadAttachment(attachment1, upload_callback());
+ uploader()->UploadAttachment(attachment2, upload_callback());
+ // Wait for upload_callback() to be invoked twice.
+ RunAndQuitAfter(2);
+ // See there was only one request.
+ EXPECT_EQ(1U, http_requests_received().size());
+}
+
+// Verify that the internal state associated with an upload is removed when the
+// uplaod finishes. We do this by issuing two non-overlapping uploads for the
+// same attachment and see that it results in two HTTP requests.
+TEST_F(AttachmentUploaderImplTest, UploadAttachment_CleanUpAfterUpload) {
+ scoped_refptr<base::RefCountedString> some_data(new base::RefCountedString);
+ some_data->data() = kAttachmentData;
+ Attachment attachment1 = Attachment::Create(some_data);
+ Attachment attachment2 = attachment1;
+ uploader()->UploadAttachment(attachment1, upload_callback());
+ // Wait for upload_callback() to be invoked before starting the second upload.
+ RunAndQuitAfter(1);
+ uploader()->UploadAttachment(attachment2, upload_callback());
+ // Wait for upload_callback() to be invoked a second time.
+ RunAndQuitAfter(1);
+ // See there were two requests.
+ EXPECT_EQ(2U, http_requests_received().size());
+}
+
+} // namespace syncer

Powered by Google App Engine
This is Rietveld 408576698