1 // Copyright 2014 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 "sync/internal_api/public/attachments/attachment_uploader_impl.h"
8 #include "base/callback.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/ref_counted_memory.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/threading/non_thread_safe.h"
15 #include "base/threading/thread.h"
16 #include "net/test/embedded_test_server/embedded_test_server.h"
17 #include "net/test/embedded_test_server/http_request.h"
18 #include "net/test/embedded_test_server/http_response.h"
19 #include "net/url_request/url_request_test_util.h"
20 #include "sync/api/attachments/attachment.h"
21 #include "sync/protocol/sync.pb.h"
22 #include "testing/gtest/include/gtest/gtest.h"
26 const char kAttachmentData
[] = "some data";
32 using net::test_server::BasicHttpResponse
;
33 using net::test_server::HttpRequest
;
34 using net::test_server::HttpResponse
;
38 // Text fixture for AttachmentUploaderImpl test.
40 // This fixture provides an embedded HTTP server for interacting with
41 // AttachmentUploaderImpl.
42 class AttachmentUploaderImplTest
: public testing::Test
,
43 public base::NonThreadSafe
{
45 void OnRequestReceived(const HttpRequest
& request
);
48 AttachmentUploaderImplTest();
51 // Run the message loop until UploadDone has been invoked |num_uploads| times.
52 void RunAndWaitFor(int num_uploads
);
54 scoped_ptr
<AttachmentUploader
>& uploader();
55 const AttachmentUploader::UploadCallback
& upload_callback() const;
56 std::vector
<HttpRequest
>& http_requests_received();
57 std::vector
<AttachmentUploader::UploadResult
>& upload_results();
58 std::vector
<AttachmentId
>& updated_attachment_ids();
61 // An UploadCallback invoked by AttachmentUploaderImpl.
62 void UploadDone(const AttachmentUploader::UploadResult
& result
,
63 const AttachmentId
& updated_attachment_id
);
65 base::MessageLoopForIO message_loop_
;
66 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter_
;
67 scoped_ptr
<RequestHandler
> request_handler_
;
68 scoped_ptr
<AttachmentUploader
> uploader_
;
69 AttachmentUploader::UploadCallback upload_callback_
;
70 net::test_server::EmbeddedTestServer server_
;
72 // A closure that signals an upload has finished.
73 base::Closure signal_upload_done_
;
74 std::vector
<HttpRequest
> http_requests_received_
;
75 std::vector
<AttachmentUploader::UploadResult
> upload_results_
;
76 std::vector
<AttachmentId
> updated_attachment_ids_
;
78 // Must be last data member.
79 base::WeakPtrFactory
<AttachmentUploaderImplTest
> weak_ptr_factory_
;
82 // Handles HTTP requests received by the EmbeddedTestServer.
83 class RequestHandler
: public base::NonThreadSafe
{
85 // Construct a RequestHandler that will PostTask to |test| using
86 // |test_task_runner|.
88 const scoped_refptr
<base::SingleThreadTaskRunner
>& test_task_runner
,
89 const base::WeakPtr
<AttachmentUploaderImplTest
>& test
);
93 scoped_ptr
<HttpResponse
> HandleRequest(const HttpRequest
& request
);
96 scoped_refptr
<base::SingleThreadTaskRunner
> test_task_runner_
;
97 base::WeakPtr
<AttachmentUploaderImplTest
> test_
;
100 AttachmentUploaderImplTest::AttachmentUploaderImplTest()
101 : weak_ptr_factory_(this) {
104 void AttachmentUploaderImplTest::OnRequestReceived(const HttpRequest
& request
) {
105 DCHECK(CalledOnValidThread());
106 http_requests_received_
.push_back(request
);
109 void AttachmentUploaderImplTest::SetUp() {
110 DCHECK(CalledOnValidThread());
111 request_handler_
.reset(new RequestHandler(message_loop_
.message_loop_proxy(),
112 weak_ptr_factory_
.GetWeakPtr()));
113 url_request_context_getter_
=
114 new net::TestURLRequestContextGetter(message_loop_
.message_loop_proxy());
116 ASSERT_TRUE(server_
.InitializeAndWaitUntilReady());
117 server_
.RegisterRequestHandler(
118 base::Bind(&RequestHandler::HandleRequest
,
119 base::Unretained(request_handler_
.get())));
121 std::string
url_prefix(
122 base::StringPrintf("http://localhost:%d/uploads/", server_
.port()));
125 new AttachmentUploaderImpl(url_prefix
, url_request_context_getter_
));
126 upload_callback_
= base::Bind(&AttachmentUploaderImplTest::UploadDone
,
127 base::Unretained(this));
130 void AttachmentUploaderImplTest::RunAndWaitFor(int num_uploads
) {
131 for (int i
= 0; i
< num_uploads
; ++i
) {
132 // Run the loop until one upload completes.
133 base::RunLoop run_loop
;
134 signal_upload_done_
= run_loop
.QuitClosure();
139 scoped_ptr
<AttachmentUploader
>& AttachmentUploaderImplTest::uploader() {
143 const AttachmentUploader::UploadCallback
&
144 AttachmentUploaderImplTest::upload_callback() const {
145 return upload_callback_
;
148 std::vector
<HttpRequest
>& AttachmentUploaderImplTest::http_requests_received() {
149 return http_requests_received_
;
152 std::vector
<AttachmentUploader::UploadResult
>&
153 AttachmentUploaderImplTest::upload_results() {
154 return upload_results_
;
157 std::vector
<AttachmentId
>&
158 AttachmentUploaderImplTest::updated_attachment_ids() {
159 return updated_attachment_ids_
;
162 void AttachmentUploaderImplTest::UploadDone(
163 const AttachmentUploader::UploadResult
& result
,
164 const AttachmentId
& updated_attachment_id
) {
165 DCHECK(CalledOnValidThread());
166 upload_results_
.push_back(result
);
167 updated_attachment_ids_
.push_back(updated_attachment_id
);
168 signal_upload_done_
.Run();
171 RequestHandler::RequestHandler(
172 const scoped_refptr
<base::SingleThreadTaskRunner
>& test_task_runner
,
173 const base::WeakPtr
<AttachmentUploaderImplTest
>& test
)
174 : test_task_runner_(test_task_runner
), test_(test
) {
178 RequestHandler::~RequestHandler() {
182 scoped_ptr
<HttpResponse
> RequestHandler::HandleRequest(
183 const HttpRequest
& request
) {
184 DCHECK(CalledOnValidThread());
185 test_task_runner_
->PostTask(
188 &AttachmentUploaderImplTest::OnRequestReceived
, test_
, request
));
189 scoped_ptr
<BasicHttpResponse
> http_response(new BasicHttpResponse
);
190 http_response
->set_code(net::HTTP_OK
);
191 http_response
->set_content("hello");
192 http_response
->set_content_type("text/plain");
193 return http_response
.PassAs
<HttpResponse
>();
196 // Verify the "happy case" of uploading an attachment.
197 TEST_F(AttachmentUploaderImplTest
, UploadAttachment_HappyCase
) {
198 scoped_refptr
<base::RefCountedString
> some_data(new base::RefCountedString
);
199 some_data
->data() = kAttachmentData
;
200 Attachment attachment
= Attachment::Create(some_data
);
201 uploader()->UploadAttachment(attachment
, upload_callback());
204 // See that the HTTP server received one request.
205 EXPECT_EQ(1U, http_requests_received().size());
206 const HttpRequest
& http_request
= http_requests_received().front();
207 EXPECT_EQ(net::test_server::METHOD_POST
, http_request
.method
);
208 std::string
expected_relative_url("/uploads/" +
209 attachment
.GetId().GetProto().unique_id());
210 EXPECT_EQ(expected_relative_url
, http_request
.relative_url
);
211 EXPECT_TRUE(http_request
.has_content
);
212 EXPECT_EQ(kAttachmentData
, http_request
.content
);
214 // See that the UploadCallback received a result and updated AttachmentId.
215 EXPECT_EQ(1U, upload_results().size());
216 EXPECT_EQ(1U, updated_attachment_ids().size());
217 EXPECT_EQ(AttachmentUploader::UPLOAD_SUCCESS
, upload_results().front());
218 EXPECT_EQ(attachment
.GetId(), updated_attachment_ids().front());
219 // TODO(maniscalco): Once AttachmentUploaderImpl is capable of updating the
220 // AttachmentId with server address information about the attachment, add some
221 // checks here to verify it works properly (bug 371522).
224 // Verify two overlapping calls to upload the same attachment result in only one
226 TEST_F(AttachmentUploaderImplTest
, UploadAttachment_Collapse
) {
227 scoped_refptr
<base::RefCountedString
> some_data(new base::RefCountedString
);
228 some_data
->data() = kAttachmentData
;
229 Attachment attachment1
= Attachment::Create(some_data
);
230 Attachment attachment2
= attachment1
;
231 uploader()->UploadAttachment(attachment1
, upload_callback());
232 uploader()->UploadAttachment(attachment2
, upload_callback());
233 // Wait for upload_callback() to be invoked twice.
235 // See there was only one request.
236 EXPECT_EQ(1U, http_requests_received().size());
239 // Verify that the internal state associated with an upload is removed when the
240 // uplaod finishes. We do this by issuing two non-overlapping uploads for the
241 // same attachment and see that it results in two HTTP requests.
242 TEST_F(AttachmentUploaderImplTest
, UploadAttachment_CleanUpAfterUpload
) {
243 scoped_refptr
<base::RefCountedString
> some_data(new base::RefCountedString
);
244 some_data
->data() = kAttachmentData
;
245 Attachment attachment1
= Attachment::Create(some_data
);
246 Attachment attachment2
= attachment1
;
247 uploader()->UploadAttachment(attachment1
, upload_callback());
248 // Wait for upload_callback() to be invoked before starting the second upload.
250 uploader()->UploadAttachment(attachment2
, upload_callback());
251 // Wait for upload_callback() to be invoked a second time.
253 // See there were two requests.
254 EXPECT_EQ(2U, http_requests_received().size());
257 } // namespace syncer