1 // Copyright (c) 2012 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.
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/json/json_reader.h"
13 #include "base/json/json_writer.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/run_loop.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "google_apis/drive/dummy_auth_service.h"
20 #include "google_apis/drive/gdata_wapi_parser.h"
21 #include "google_apis/drive/gdata_wapi_requests.h"
22 #include "google_apis/drive/gdata_wapi_url_generator.h"
23 #include "google_apis/drive/request_sender.h"
24 #include "google_apis/drive/test_util.h"
25 #include "net/base/escape.h"
26 #include "net/test/embedded_test_server/embedded_test_server.h"
27 #include "net/test/embedded_test_server/http_request.h"
28 #include "net/test/embedded_test_server/http_response.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
32 namespace google_apis
{
36 const char kTestUserAgent
[] = "test-user-agent";
37 const char kTestETag
[] = "test_etag";
38 const char kTestDownloadPathPrefix
[] = "/download/";
40 class GDataWapiRequestsTest
: public testing::Test
{
42 GDataWapiRequestsTest() {
45 virtual void SetUp() OVERRIDE
{
46 request_context_getter_
= new net::TestURLRequestContextGetter(
47 message_loop_
.message_loop_proxy());
49 request_sender_
.reset(new RequestSender(new DummyAuthService
,
50 request_context_getter_
.get(),
51 message_loop_
.message_loop_proxy(),
54 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
56 ASSERT_TRUE(test_server_
.InitializeAndWaitUntilReady());
57 test_server_
.RegisterRequestHandler(
58 base::Bind(&test_util::HandleDownloadFileRequest
,
59 test_server_
.base_url(),
60 base::Unretained(&http_request_
)));
61 test_server_
.RegisterRequestHandler(
62 base::Bind(&GDataWapiRequestsTest::HandleResourceFeedRequest
,
63 base::Unretained(this)));
64 test_server_
.RegisterRequestHandler(
65 base::Bind(&GDataWapiRequestsTest::HandleMetadataRequest
,
66 base::Unretained(this)));
67 test_server_
.RegisterRequestHandler(
68 base::Bind(&GDataWapiRequestsTest::HandleCreateSessionRequest
,
69 base::Unretained(this)));
70 test_server_
.RegisterRequestHandler(
71 base::Bind(&GDataWapiRequestsTest::HandleUploadRequest
,
72 base::Unretained(this)));
73 test_server_
.RegisterRequestHandler(
74 base::Bind(&GDataWapiRequestsTest::HandleDownloadRequest
,
75 base::Unretained(this)));
77 GURL test_base_url
= test_util::GetBaseUrlForTesting(test_server_
.port());
78 url_generator_
.reset(new GDataWapiUrlGenerator(
79 test_base_url
, test_base_url
.Resolve(kTestDownloadPathPrefix
)));
86 // Handles a request for fetching a resource feed.
87 scoped_ptr
<net::test_server::HttpResponse
> HandleResourceFeedRequest(
88 const net::test_server::HttpRequest
& request
) {
89 http_request_
= request
;
91 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
92 std::string remaining_path
;
93 if (absolute_url
.path() == "/feeds/default/private/full" &&
94 request
.method
== net::test_server::METHOD_POST
) {
95 // This is a request for copying a document.
96 // TODO(satorux): we should generate valid JSON data for the newly
97 // copied document but for now, just return "file_entry.json"
98 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
99 test_util::CreateHttpResponseFromFile(
100 test_util::GetTestFilePath("gdata/file_entry.json")));
101 return result
.PassAs
<net::test_server::HttpResponse
>();
104 if (!test_util::RemovePrefix(absolute_url
.path(),
105 "/feeds/default/private/full",
107 return scoped_ptr
<net::test_server::HttpResponse
>();
110 if (remaining_path
.empty()) {
111 // Process the default feed.
112 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
113 test_util::CreateHttpResponseFromFile(
114 test_util::GetTestFilePath("gdata/root_feed.json")));
115 return result
.PassAs
<net::test_server::HttpResponse
>();
117 // Process a feed for a single resource ID.
118 const std::string resource_id
= net::UnescapeURLComponent(
119 remaining_path
.substr(1), net::UnescapeRule::URL_SPECIAL_CHARS
);
120 if (resource_id
== "file:2_file_resource_id") {
121 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
122 test_util::CreateHttpResponseFromFile(
123 test_util::GetTestFilePath("gdata/file_entry.json")));
124 return result
.PassAs
<net::test_server::HttpResponse
>();
125 } else if (resource_id
== "folder:root/contents" &&
126 request
.method
== net::test_server::METHOD_POST
) {
127 // This is a request for creating a directory in the root directory.
128 // TODO(satorux): we should generate valid JSON data for the newly
129 // created directory but for now, just return "directory_entry.json"
130 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
131 test_util::CreateHttpResponseFromFile(
132 test_util::GetTestFilePath(
133 "gdata/directory_entry.json")));
134 return result
.PassAs
<net::test_server::HttpResponse
>();
135 } else if (resource_id
==
136 "folder:root/contents/file:2_file_resource_id" &&
137 request
.method
== net::test_server::METHOD_DELETE
) {
138 // This is a request for deleting a file from the root directory.
139 // TODO(satorux): Investigate what's returned from the server, and
140 // copy it. For now, just return a random file, as the contents don't
142 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
143 test_util::CreateHttpResponseFromFile(
144 test_util::GetTestFilePath("gdata/testfile.txt")));
145 return result
.PassAs
<net::test_server::HttpResponse
>();
146 } else if (resource_id
== "invalid_resource_id") {
147 // Check if this is an authorization request for an app.
148 // This emulates to return invalid formatted result from the server.
149 if (request
.method
== net::test_server::METHOD_PUT
&&
150 request
.content
.find("<docs:authorizedApp>") != std::string::npos
) {
151 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
152 test_util::CreateHttpResponseFromFile(
153 test_util::GetTestFilePath("gdata/testfile.txt")));
154 return result
.PassAs
<net::test_server::HttpResponse
>();
159 return scoped_ptr
<net::test_server::HttpResponse
>();
162 // Handles a request for fetching a metadata feed.
163 scoped_ptr
<net::test_server::HttpResponse
> HandleMetadataRequest(
164 const net::test_server::HttpRequest
& request
) {
165 http_request_
= request
;
167 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
168 if (absolute_url
.path() != "/feeds/metadata/default")
169 return scoped_ptr
<net::test_server::HttpResponse
>();
171 scoped_ptr
<net::test_server::BasicHttpResponse
> result(
172 test_util::CreateHttpResponseFromFile(
173 test_util::GetTestFilePath(
174 "gdata/account_metadata.json")));
175 if (absolute_url
.query().find("include-installed-apps=true") ==
177 // Exclude the list of installed apps.
178 scoped_ptr
<base::Value
> parsed_content(
179 base::JSONReader::Read(result
->content(), base::JSON_PARSE_RFC
));
180 CHECK(parsed_content
);
182 // Remove the install apps node.
183 base::DictionaryValue
* dictionary_value
;
184 CHECK(parsed_content
->GetAsDictionary(&dictionary_value
));
185 dictionary_value
->Remove("entry.docs$installedApp", NULL
);
187 // Write back it as the content of the result.
189 base::JSONWriter::Write(parsed_content
.get(), &content
);
190 result
->set_content(content
);
193 return result
.PassAs
<net::test_server::HttpResponse
>();
196 // Handles a request for creating a session for uploading.
197 scoped_ptr
<net::test_server::HttpResponse
> HandleCreateSessionRequest(
198 const net::test_server::HttpRequest
& request
) {
199 http_request_
= request
;
201 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
202 if (StartsWithASCII(absolute_url
.path(),
203 "/feeds/upload/create-session/default/private/full",
204 true)) { // case sensitive
205 // This is an initiating upload URL.
206 scoped_ptr
<net::test_server::BasicHttpResponse
> http_response(
207 new net::test_server::BasicHttpResponse
);
210 std::map
<std::string
, std::string
>::const_iterator found
=
211 request
.headers
.find("If-Match");
212 if (found
!= request
.headers
.end() &&
213 found
->second
!= "*" &&
214 found
->second
!= kTestETag
) {
215 http_response
->set_code(net::HTTP_PRECONDITION_FAILED
);
216 return http_response
.PassAs
<net::test_server::HttpResponse
>();
219 // Check if the X-Upload-Content-Length is present. If yes, store the
220 // length of the file.
221 found
= request
.headers
.find("X-Upload-Content-Length");
222 if (found
== request
.headers
.end() ||
223 !base::StringToInt64(found
->second
, &content_length_
)) {
224 return scoped_ptr
<net::test_server::HttpResponse
>();
228 http_response
->set_code(net::HTTP_OK
);
230 // POST is used for a new file, and PUT is used for an existing file.
231 if (request
.method
== net::test_server::METHOD_POST
) {
232 upload_url
= test_server_
.GetURL("/upload_new_file");
233 } else if (request
.method
== net::test_server::METHOD_PUT
) {
234 upload_url
= test_server_
.GetURL("/upload_existing_file");
236 return scoped_ptr
<net::test_server::HttpResponse
>();
238 http_response
->AddCustomHeader("Location", upload_url
.spec());
239 return http_response
.PassAs
<net::test_server::HttpResponse
>();
242 return scoped_ptr
<net::test_server::HttpResponse
>();
245 // Handles a request for uploading content.
246 scoped_ptr
<net::test_server::HttpResponse
> HandleUploadRequest(
247 const net::test_server::HttpRequest
& request
) {
248 http_request_
= request
;
250 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
251 if (absolute_url
.path() != "/upload_new_file" &&
252 absolute_url
.path() != "/upload_existing_file") {
253 return scoped_ptr
<net::test_server::HttpResponse
>();
256 // TODO(satorux): We should create a correct JSON data for the uploaded
257 // file, but for now, just return file_entry.json.
258 scoped_ptr
<net::test_server::BasicHttpResponse
> response
=
259 test_util::CreateHttpResponseFromFile(
260 test_util::GetTestFilePath("gdata/file_entry.json"));
261 // response.code() is set to SUCCESS. Change it to CREATED if it's a new
263 if (absolute_url
.path() == "/upload_new_file")
264 response
->set_code(net::HTTP_CREATED
);
266 // Check if the Content-Range header is present. This must be present if
267 // the request body is not empty.
268 if (!request
.content
.empty()) {
269 std::map
<std::string
, std::string
>::const_iterator iter
=
270 request
.headers
.find("Content-Range");
271 if (iter
== request
.headers
.end())
272 return scoped_ptr
<net::test_server::HttpResponse
>();
274 int64 start_position
= 0;
275 int64 end_position
= 0;
276 if (!test_util::ParseContentRangeHeader(iter
->second
,
280 return scoped_ptr
<net::test_server::HttpResponse
>();
282 EXPECT_EQ(start_position
, received_bytes_
);
283 EXPECT_EQ(length
, content_length_
);
284 // end_position is inclusive, but so +1 to change the range to byte size.
285 received_bytes_
= end_position
+ 1;
288 // Add Range header to the response, based on the values of
289 // Content-Range header in the request.
290 // The header is annotated only when at least one byte is received.
291 if (received_bytes_
> 0) {
292 response
->AddCustomHeader(
294 "bytes=0-" + base::Int64ToString(received_bytes_
- 1));
297 // Change the code to RESUME_INCOMPLETE if upload is not complete.
298 if (received_bytes_
< content_length_
)
299 response
->set_code(static_cast<net::HttpStatusCode
>(308));
301 return response
.PassAs
<net::test_server::HttpResponse
>();
304 // Handles a request for downloading a file.
305 scoped_ptr
<net::test_server::HttpResponse
> HandleDownloadRequest(
306 const net::test_server::HttpRequest
& request
) {
307 http_request_
= request
;
309 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
311 if (!test_util::RemovePrefix(absolute_url
.path(),
312 kTestDownloadPathPrefix
,
314 return scoped_ptr
<net::test_server::HttpResponse
>();
317 // For testing, returns a text with |id| repeated 3 times.
318 scoped_ptr
<net::test_server::BasicHttpResponse
> response(
319 new net::test_server::BasicHttpResponse
);
320 response
->set_code(net::HTTP_OK
);
321 response
->set_content(id
+ id
+ id
);
322 response
->set_content_type("text/plain");
323 return response
.PassAs
<net::test_server::HttpResponse
>();
326 base::MessageLoopForIO message_loop_
; // Test server needs IO thread.
327 net::test_server::EmbeddedTestServer test_server_
;
328 scoped_ptr
<RequestSender
> request_sender_
;
329 scoped_ptr
<GDataWapiUrlGenerator
> url_generator_
;
330 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_getter_
;
331 base::ScopedTempDir temp_dir_
;
333 // These fields are used to keep the current upload state during a
334 // test case. These values are updated by the request from
335 // ResumeUploadRequest, and used to construct the response for
336 // both ResumeUploadRequest and GetUploadStatusRequest, to emulate
338 int64 received_bytes_
;
339 int64 content_length_
;
341 // The incoming HTTP request is saved so tests can verify the request
342 // parameters like HTTP method (ex. some requests should use DELETE
344 net::test_server::HttpRequest http_request_
;
349 TEST_F(GDataWapiRequestsTest
, GetResourceListRequest_DefaultFeed
) {
350 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
351 scoped_ptr
<ResourceList
> result_data
;
354 base::RunLoop run_loop
;
355 GetResourceListRequest
* request
= new GetResourceListRequest(
356 request_sender_
.get(),
358 GURL(), // Pass an empty URL to use the default feed
359 0, // start changestamp
360 std::string(), // search string
361 std::string(), // directory resource ID
362 test_util::CreateQuitCallback(
364 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
365 request_sender_
->StartRequestWithRetry(request
);
369 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
370 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
371 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&"
372 "showfolders=true&include-shared=true&max-results=500",
373 http_request_
.relative_url
);
375 // Sanity check of the result.
376 scoped_ptr
<ResourceList
> expected(
377 ResourceList::ExtractAndParse(
378 *test_util::LoadJSONFile("gdata/root_feed.json")));
379 ASSERT_TRUE(result_data
);
380 EXPECT_EQ(expected
->title(), result_data
->title());
383 TEST_F(GDataWapiRequestsTest
, GetResourceListRequest_ValidFeed
) {
384 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
385 scoped_ptr
<ResourceList
> result_data
;
388 base::RunLoop run_loop
;
389 GetResourceListRequest
* request
= new GetResourceListRequest(
390 request_sender_
.get(),
392 test_server_
.GetURL("/files/gdata/root_feed.json"),
393 0, // start changestamp
394 std::string(), // search string
395 std::string(), // directory resource ID
396 test_util::CreateQuitCallback(
398 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
399 request_sender_
->StartRequestWithRetry(request
);
403 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
404 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
405 EXPECT_EQ("/files/gdata/root_feed.json?v=3&alt=json&showroot=true&"
406 "showfolders=true&include-shared=true&max-results=500",
407 http_request_
.relative_url
);
409 scoped_ptr
<ResourceList
> expected(
410 ResourceList::ExtractAndParse(
411 *test_util::LoadJSONFile("gdata/root_feed.json")));
412 ASSERT_TRUE(result_data
);
413 EXPECT_EQ(expected
->title(), result_data
->title());
416 TEST_F(GDataWapiRequestsTest
, GetResourceListRequest_InvalidFeed
) {
417 // testfile.txt exists but the response is not JSON, so it should
418 // emit a parse error instead.
419 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
420 scoped_ptr
<ResourceList
> result_data
;
423 base::RunLoop run_loop
;
424 GetResourceListRequest
* request
= new GetResourceListRequest(
425 request_sender_
.get(),
427 test_server_
.GetURL("/files/gdata/testfile.txt"),
428 0, // start changestamp
429 std::string(), // search string
430 std::string(), // directory resource ID
431 test_util::CreateQuitCallback(
433 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
434 request_sender_
->StartRequestWithRetry(request
);
438 EXPECT_EQ(GDATA_PARSE_ERROR
, result_code
);
439 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
440 EXPECT_EQ("/files/gdata/testfile.txt?v=3&alt=json&showroot=true&"
441 "showfolders=true&include-shared=true&max-results=500",
442 http_request_
.relative_url
);
443 EXPECT_FALSE(result_data
);
446 TEST_F(GDataWapiRequestsTest
, SearchByTitleRequest
) {
447 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
448 scoped_ptr
<ResourceList
> result_data
;
451 base::RunLoop run_loop
;
452 SearchByTitleRequest
* request
= new SearchByTitleRequest(
453 request_sender_
.get(),
456 std::string(), // directory resource id
457 test_util::CreateQuitCallback(
459 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
460 request_sender_
->StartRequestWithRetry(request
);
464 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
465 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
466 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&"
467 "showfolders=true&include-shared=true&max-results=500"
468 "&title=search-title&title-exact=true",
469 http_request_
.relative_url
);
470 EXPECT_TRUE(result_data
);
473 TEST_F(GDataWapiRequestsTest
, GetResourceEntryRequest_ValidResourceId
) {
474 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
475 scoped_ptr
<base::Value
> result_data
;
478 base::RunLoop run_loop
;
479 GetResourceEntryRequest
* request
= new GetResourceEntryRequest(
480 request_sender_
.get(),
482 "file:2_file_resource_id", // resource ID
483 GURL(), // embed origin
484 test_util::CreateQuitCallback(
486 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
487 request_sender_
->StartRequestWithRetry(request
);
491 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
492 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
493 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
494 "?v=3&alt=json&showroot=true",
495 http_request_
.relative_url
);
496 scoped_ptr
<base::Value
> expected_json
=
497 test_util::LoadJSONFile("gdata/file_entry.json");
498 ASSERT_TRUE(expected_json
);
499 EXPECT_TRUE(result_data
);
500 EXPECT_TRUE(base::Value::Equals(expected_json
.get(), result_data
.get()));
503 TEST_F(GDataWapiRequestsTest
, GetResourceEntryRequest_InvalidResourceId
) {
504 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
505 scoped_ptr
<base::Value
> result_data
;
508 base::RunLoop run_loop
;
509 GetResourceEntryRequest
* request
= new GetResourceEntryRequest(
510 request_sender_
.get(),
512 "<invalid>", // resource ID
513 GURL(), // embed origin
514 test_util::CreateQuitCallback(
516 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
517 request_sender_
->StartRequestWithRetry(request
);
521 EXPECT_EQ(HTTP_NOT_FOUND
, result_code
);
522 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
523 EXPECT_EQ("/feeds/default/private/full/%3Cinvalid%3E?v=3&alt=json"
525 http_request_
.relative_url
);
526 ASSERT_FALSE(result_data
);
529 TEST_F(GDataWapiRequestsTest
, GetAccountMetadataRequest
) {
530 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
531 scoped_ptr
<AccountMetadata
> result_data
;
534 base::RunLoop run_loop
;
535 GetAccountMetadataRequest
* request
= new GetAccountMetadataRequest(
536 request_sender_
.get(),
538 test_util::CreateQuitCallback(
540 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
541 true); // Include installed apps.
542 request_sender_
->StartRequestWithRetry(request
);
546 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
547 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
548 EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true"
549 "&include-installed-apps=true",
550 http_request_
.relative_url
);
552 scoped_ptr
<AccountMetadata
> expected(
553 AccountMetadata::CreateFrom(
554 *test_util::LoadJSONFile("gdata/account_metadata.json")));
556 ASSERT_TRUE(result_data
.get());
557 EXPECT_EQ(expected
->largest_changestamp(),
558 result_data
->largest_changestamp());
559 EXPECT_EQ(expected
->quota_bytes_total(),
560 result_data
->quota_bytes_total());
561 EXPECT_EQ(expected
->quota_bytes_used(),
562 result_data
->quota_bytes_used());
564 // Sanity check for installed apps.
565 EXPECT_EQ(expected
->installed_apps().size(),
566 result_data
->installed_apps().size());
569 TEST_F(GDataWapiRequestsTest
,
570 GetAccountMetadataRequestWithoutInstalledApps
) {
571 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
572 scoped_ptr
<AccountMetadata
> result_data
;
575 base::RunLoop run_loop
;
576 GetAccountMetadataRequest
* request
= new GetAccountMetadataRequest(
577 request_sender_
.get(),
579 test_util::CreateQuitCallback(
581 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
582 false); // Exclude installed apps.
583 request_sender_
->StartRequestWithRetry(request
);
587 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
588 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
589 EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true",
590 http_request_
.relative_url
);
592 scoped_ptr
<AccountMetadata
> expected(
593 AccountMetadata::CreateFrom(
594 *test_util::LoadJSONFile("gdata/account_metadata.json")));
596 ASSERT_TRUE(result_data
.get());
597 EXPECT_EQ(expected
->largest_changestamp(),
598 result_data
->largest_changestamp());
599 EXPECT_EQ(expected
->quota_bytes_total(),
600 result_data
->quota_bytes_total());
601 EXPECT_EQ(expected
->quota_bytes_used(),
602 result_data
->quota_bytes_used());
604 // Installed apps shouldn't be included.
605 EXPECT_EQ(0U, result_data
->installed_apps().size());
608 TEST_F(GDataWapiRequestsTest
, DeleteResourceRequest
) {
609 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
612 base::RunLoop run_loop
;
613 DeleteResourceRequest
* request
= new DeleteResourceRequest(
614 request_sender_
.get(),
616 test_util::CreateQuitCallback(
618 test_util::CreateCopyResultCallback(&result_code
)),
619 "file:2_file_resource_id",
622 request_sender_
->StartRequestWithRetry(request
);
626 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
627 EXPECT_EQ(net::test_server::METHOD_DELETE
, http_request_
.method
);
629 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
631 http_request_
.relative_url
);
632 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
635 TEST_F(GDataWapiRequestsTest
, DeleteResourceRequestWithETag
) {
636 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
639 base::RunLoop run_loop
;
640 DeleteResourceRequest
* request
= new DeleteResourceRequest(
641 request_sender_
.get(),
643 test_util::CreateQuitCallback(
645 test_util::CreateCopyResultCallback(&result_code
)),
646 "file:2_file_resource_id",
649 request_sender_
->StartRequestWithRetry(request
);
653 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
654 EXPECT_EQ(net::test_server::METHOD_DELETE
, http_request_
.method
);
656 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
658 http_request_
.relative_url
);
659 EXPECT_EQ("etag", http_request_
.headers
["If-Match"]);
662 TEST_F(GDataWapiRequestsTest
, CreateDirectoryRequest
) {
663 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
664 scoped_ptr
<base::Value
> result_data
;
666 // Create "new directory" in the root directory.
668 base::RunLoop run_loop
;
669 CreateDirectoryRequest
* request
= new CreateDirectoryRequest(
670 request_sender_
.get(),
672 test_util::CreateQuitCallback(
674 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
678 request_sender_
->StartRequestWithRetry(request
);
682 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
683 EXPECT_EQ(net::test_server::METHOD_POST
, http_request_
.method
);
684 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json"
686 http_request_
.relative_url
);
687 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
689 EXPECT_TRUE(http_request_
.has_content
);
690 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
691 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
692 " <category scheme=\"http://schemas.google.com/g/2005#kind\" "
693 "term=\"http://schemas.google.com/docs/2007#folder\"/>\n"
694 " <title>new directory</title>\n"
696 http_request_
.content
);
699 TEST_F(GDataWapiRequestsTest
, RenameResourceRequest
) {
700 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
702 // Rename a file with a new name "New File".
704 base::RunLoop run_loop
;
705 RenameResourceRequest
* request
= new RenameResourceRequest(
706 request_sender_
.get(),
708 test_util::CreateQuitCallback(
710 test_util::CreateCopyResultCallback(&result_code
)),
711 "file:2_file_resource_id",
714 request_sender_
->StartRequestWithRetry(request
);
718 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
719 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
721 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
723 http_request_
.relative_url
);
724 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
725 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
727 EXPECT_TRUE(http_request_
.has_content
);
728 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
729 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
730 " <title>New File</title>\n"
732 http_request_
.content
);
735 TEST_F(GDataWapiRequestsTest
, AuthorizeAppRequest_ValidFeed
) {
736 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
739 // Authorize an app with APP_ID to access to a document.
741 base::RunLoop run_loop
;
742 AuthorizeAppRequest
* request
= new AuthorizeAppRequest(
743 request_sender_
.get(),
745 test_util::CreateQuitCallback(
747 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
748 "file:2_file_resource_id",
751 request_sender_
->StartRequestWithRetry(request
);
755 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
756 EXPECT_EQ(GURL("https://entry1_open_with_link/"), result_data
);
758 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
759 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
760 "?v=3&alt=json&showroot=true",
761 http_request_
.relative_url
);
762 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
763 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
765 EXPECT_TRUE(http_request_
.has_content
);
766 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
767 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
768 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
769 " <docs:authorizedApp>the_app_id</docs:authorizedApp>\n"
771 http_request_
.content
);
774 TEST_F(GDataWapiRequestsTest
, AuthorizeAppRequest_NotFound
) {
775 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
778 // Authorize an app with APP_ID to access to a document.
780 base::RunLoop run_loop
;
781 AuthorizeAppRequest
* request
= new AuthorizeAppRequest(
782 request_sender_
.get(),
784 test_util::CreateQuitCallback(
786 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
787 "file:2_file_resource_id",
788 "unauthorized_app_id");
790 request_sender_
->StartRequestWithRetry(request
);
794 EXPECT_EQ(GDATA_OTHER_ERROR
, result_code
);
795 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
796 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
797 "?v=3&alt=json&showroot=true",
798 http_request_
.relative_url
);
799 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
800 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
802 EXPECT_TRUE(http_request_
.has_content
);
803 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
804 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
805 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
806 " <docs:authorizedApp>unauthorized_app_id</docs:authorizedApp>\n"
808 http_request_
.content
);
811 TEST_F(GDataWapiRequestsTest
, AuthorizeAppRequest_InvalidFeed
) {
812 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
815 // Authorize an app with APP_ID to access to a document but an invalid feed.
817 base::RunLoop run_loop
;
818 AuthorizeAppRequest
* request
= new AuthorizeAppRequest(
819 request_sender_
.get(),
821 test_util::CreateQuitCallback(
823 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
824 "invalid_resource_id",
827 request_sender_
->StartRequestWithRetry(request
);
831 EXPECT_EQ(GDATA_PARSE_ERROR
, result_code
);
832 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
833 EXPECT_EQ("/feeds/default/private/full/invalid_resource_id"
834 "?v=3&alt=json&showroot=true",
835 http_request_
.relative_url
);
836 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
837 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
839 EXPECT_TRUE(http_request_
.has_content
);
840 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
841 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
842 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
843 " <docs:authorizedApp>APP_ID</docs:authorizedApp>\n"
845 http_request_
.content
);
848 TEST_F(GDataWapiRequestsTest
, AddResourceToDirectoryRequest
) {
849 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
851 // Add a file to the root directory.
853 base::RunLoop run_loop
;
854 AddResourceToDirectoryRequest
* request
=
855 new AddResourceToDirectoryRequest(
856 request_sender_
.get(),
858 test_util::CreateQuitCallback(
860 test_util::CreateCopyResultCallback(&result_code
)),
862 "file:2_file_resource_id");
864 request_sender_
->StartRequestWithRetry(request
);
868 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
869 EXPECT_EQ(net::test_server::METHOD_POST
, http_request_
.method
);
870 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json"
872 http_request_
.relative_url
);
873 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
875 EXPECT_TRUE(http_request_
.has_content
);
876 EXPECT_EQ(base::StringPrintf("<?xml version=\"1.0\"?>\n"
877 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
878 " <id>%sfeeds/default/private/full/"
879 "file%%3A2_file_resource_id</id>\n"
881 test_server_
.base_url().spec().c_str()),
882 http_request_
.content
);
885 TEST_F(GDataWapiRequestsTest
, RemoveResourceFromDirectoryRequest
) {
886 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
888 // Remove a file from the root directory.
890 base::RunLoop run_loop
;
891 RemoveResourceFromDirectoryRequest
* request
=
892 new RemoveResourceFromDirectoryRequest(
893 request_sender_
.get(),
895 test_util::CreateQuitCallback(
897 test_util::CreateCopyResultCallback(&result_code
)),
899 "file:2_file_resource_id");
901 request_sender_
->StartRequestWithRetry(request
);
905 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
906 // DELETE method should be used, without the body content.
907 EXPECT_EQ(net::test_server::METHOD_DELETE
, http_request_
.method
);
908 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents/"
909 "file%3A2_file_resource_id?v=3&alt=json&showroot=true",
910 http_request_
.relative_url
);
911 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
912 EXPECT_FALSE(http_request_
.has_content
);
915 // This test exercises InitiateUploadNewFileRequest and
916 // ResumeUploadRequest for a scenario of uploading a new file.
917 TEST_F(GDataWapiRequestsTest
, UploadNewFile
) {
918 const std::string kUploadContent
= "hello";
919 const base::FilePath kTestFilePath
=
920 temp_dir_
.path().AppendASCII("upload_file.txt");
921 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath
, kUploadContent
));
923 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
926 // 1) Get the upload URL for uploading a new file.
928 base::RunLoop run_loop
;
929 InitiateUploadNewFileRequest
* initiate_request
=
930 new InitiateUploadNewFileRequest(
931 request_sender_
.get(),
933 test_util::CreateQuitCallback(
935 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
937 kUploadContent
.size(),
940 request_sender_
->StartRequestWithRetry(initiate_request
);
944 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
945 EXPECT_EQ(test_server_
.GetURL("/upload_new_file"), upload_url
);
946 EXPECT_EQ(net::test_server::METHOD_POST
, http_request_
.method
);
947 // convert=false should be passed as files should be uploaded as-is.
949 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
950 "?convert=false&v=3&alt=json&showroot=true",
951 http_request_
.relative_url
);
952 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
953 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
954 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
955 http_request_
.headers
["X-Upload-Content-Length"]);
957 EXPECT_TRUE(http_request_
.has_content
);
958 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
959 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
960 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
961 " <title>New file</title>\n"
963 http_request_
.content
);
965 // 2) Upload the content to the upload URL.
966 UploadRangeResponse response
;
967 scoped_ptr
<ResourceEntry
> new_entry
;
970 base::RunLoop run_loop
;
971 ResumeUploadRequest
* resume_request
= new ResumeUploadRequest(
972 request_sender_
.get(),
973 test_util::CreateQuitCallback(
975 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
979 kUploadContent
.size(), // end_position (exclusive)
980 kUploadContent
.size(), // content_length,
981 "text/plain", // content_type
984 request_sender_
->StartRequestWithRetry(resume_request
);
988 // METHOD_PUT should be used to upload data.
989 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
990 // Request should go to the upload URL.
991 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
992 // Content-Range header should be added.
993 EXPECT_EQ("bytes 0-" +
994 base::Int64ToString(kUploadContent
.size() -1) + "/" +
995 base::Int64ToString(kUploadContent
.size()),
996 http_request_
.headers
["Content-Range"]);
997 // The upload content should be set in the HTTP request.
998 EXPECT_TRUE(http_request_
.has_content
);
999 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1001 // Check the response.
1002 EXPECT_EQ(HTTP_CREATED
, response
.code
); // Because it's a new file
1003 // The start and end positions should be set to -1, if an upload is complete.
1004 EXPECT_EQ(-1, response
.start_position_received
);
1005 EXPECT_EQ(-1, response
.end_position_received
);
1008 // This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest
1009 // for a scenario of uploading a new *large* file, which requires multiple
1010 // requests of ResumeUploadRequest. GetUploadRequest is also tested in this
1012 TEST_F(GDataWapiRequestsTest
, UploadNewLargeFile
) {
1013 const size_t kMaxNumBytes
= 10;
1014 // This is big enough to cause multiple requests of ResumeUploadRequest
1015 // as we are going to send at most kMaxNumBytes at a time.
1016 // So, sending "kMaxNumBytes * 2 + 1" bytes ensures three
1017 // ResumeUploadRequests, which are start, middle and last requests.
1018 const std::string
kUploadContent(kMaxNumBytes
* 2 + 1, 'a');
1019 const base::FilePath kTestFilePath
=
1020 temp_dir_
.path().AppendASCII("upload_file.txt");
1021 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath
, kUploadContent
));
1023 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1026 // 1) Get the upload URL for uploading a new file.
1028 base::RunLoop run_loop
;
1029 InitiateUploadNewFileRequest
* initiate_request
=
1030 new InitiateUploadNewFileRequest(
1031 request_sender_
.get(),
1033 test_util::CreateQuitCallback(
1035 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1037 kUploadContent
.size(),
1040 request_sender_
->StartRequestWithRetry(initiate_request
);
1044 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1045 EXPECT_EQ(test_server_
.GetURL("/upload_new_file"), upload_url
);
1046 EXPECT_EQ(net::test_server::METHOD_POST
, http_request_
.method
);
1047 // convert=false should be passed as files should be uploaded as-is.
1049 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
1050 "?convert=false&v=3&alt=json&showroot=true",
1051 http_request_
.relative_url
);
1052 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1053 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
1054 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1055 http_request_
.headers
["X-Upload-Content-Length"]);
1057 EXPECT_TRUE(http_request_
.has_content
);
1058 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
1059 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
1060 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
1061 " <title>New file</title>\n"
1063 http_request_
.content
);
1065 // 2) Before sending any data, check the current status.
1066 // This is an edge case test for GetUploadStatusRequest
1067 // (UploadRangeRequestBase).
1069 UploadRangeResponse response
;
1070 scoped_ptr
<ResourceEntry
> new_entry
;
1072 // Check the response by GetUploadStatusRequest.
1074 base::RunLoop run_loop
;
1075 GetUploadStatusRequest
* get_upload_status_request
=
1076 new GetUploadStatusRequest(
1077 request_sender_
.get(),
1078 test_util::CreateQuitCallback(
1080 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1082 kUploadContent
.size());
1083 request_sender_
->StartRequestWithRetry(get_upload_status_request
);
1087 // METHOD_PUT should be used to upload data.
1088 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1089 // Request should go to the upload URL.
1090 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1091 // Content-Range header should be added.
1092 EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent
.size()),
1093 http_request_
.headers
["Content-Range"]);
1094 EXPECT_TRUE(http_request_
.has_content
);
1095 EXPECT_TRUE(http_request_
.content
.empty());
1097 // Check the response.
1098 EXPECT_EQ(HTTP_RESUME_INCOMPLETE
, response
.code
);
1099 EXPECT_EQ(0, response
.start_position_received
);
1100 EXPECT_EQ(0, response
.end_position_received
);
1103 // 3) Upload the content to the upload URL with multiple requests.
1104 size_t num_bytes_consumed
= 0;
1105 for (size_t start_position
= 0; start_position
< kUploadContent
.size();
1106 start_position
+= kMaxNumBytes
) {
1107 SCOPED_TRACE(testing::Message("start_position: ") << start_position
);
1109 // The payload is at most kMaxNumBytes.
1110 const size_t remaining_size
= kUploadContent
.size() - start_position
;
1111 const std::string payload
= kUploadContent
.substr(
1112 start_position
, std::min(kMaxNumBytes
, remaining_size
));
1113 num_bytes_consumed
+= payload
.size();
1114 // The end position is exclusive.
1115 const size_t end_position
= start_position
+ payload
.size();
1117 UploadRangeResponse response
;
1118 scoped_ptr
<ResourceEntry
> new_entry
;
1121 base::RunLoop run_loop
;
1122 ResumeUploadRequest
* resume_request
= new ResumeUploadRequest(
1123 request_sender_
.get(),
1124 test_util::CreateQuitCallback(
1126 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1131 kUploadContent
.size(), // content_length,
1132 "text/plain", // content_type
1134 request_sender_
->StartRequestWithRetry(resume_request
);
1138 // METHOD_PUT should be used to upload data.
1139 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1140 // Request should go to the upload URL.
1141 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1142 // Content-Range header should be added.
1143 EXPECT_EQ("bytes " +
1144 base::Int64ToString(start_position
) + "-" +
1145 base::Int64ToString(end_position
- 1) + "/" +
1146 base::Int64ToString(kUploadContent
.size()),
1147 http_request_
.headers
["Content-Range"]);
1148 // The upload content should be set in the HTTP request.
1149 EXPECT_TRUE(http_request_
.has_content
);
1150 EXPECT_EQ(payload
, http_request_
.content
);
1152 // Check the response.
1153 if (payload
.size() == remaining_size
) {
1154 EXPECT_EQ(HTTP_CREATED
, response
.code
); // Because it's a new file.
1155 // The start and end positions should be set to -1, if an upload is
1157 EXPECT_EQ(-1, response
.start_position_received
);
1158 EXPECT_EQ(-1, response
.end_position_received
);
1159 // The upload process is completed, so exit from the loop.
1163 EXPECT_EQ(HTTP_RESUME_INCOMPLETE
, response
.code
);
1164 EXPECT_EQ(0, response
.start_position_received
);
1165 EXPECT_EQ(static_cast<int64
>(end_position
),
1166 response
.end_position_received
);
1168 // Check the response by GetUploadStatusRequest.
1170 base::RunLoop run_loop
;
1171 GetUploadStatusRequest
* get_upload_status_request
=
1172 new GetUploadStatusRequest(
1173 request_sender_
.get(),
1174 test_util::CreateQuitCallback(
1176 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1178 kUploadContent
.size());
1179 request_sender_
->StartRequestWithRetry(get_upload_status_request
);
1183 // METHOD_PUT should be used to upload data.
1184 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1185 // Request should go to the upload URL.
1186 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1187 // Content-Range header should be added.
1188 EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent
.size()),
1189 http_request_
.headers
["Content-Range"]);
1190 EXPECT_TRUE(http_request_
.has_content
);
1191 EXPECT_TRUE(http_request_
.content
.empty());
1193 // Check the response.
1194 EXPECT_EQ(HTTP_RESUME_INCOMPLETE
, response
.code
);
1195 EXPECT_EQ(0, response
.start_position_received
);
1196 EXPECT_EQ(static_cast<int64
>(end_position
),
1197 response
.end_position_received
);
1200 EXPECT_EQ(kUploadContent
.size(), num_bytes_consumed
);
1203 // This test exercises InitiateUploadNewFileRequest and ResumeUploadRequest
1204 // for a scenario of uploading a new *empty* file.
1206 // The test is almost identical to UploadNewFile. The only difference is the
1207 // expectation for the Content-Range header.
1208 TEST_F(GDataWapiRequestsTest
, UploadNewEmptyFile
) {
1209 const std::string kUploadContent
;
1210 const base::FilePath kTestFilePath
=
1211 temp_dir_
.path().AppendASCII("empty_file.txt");
1212 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath
, kUploadContent
));
1214 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1217 // 1) Get the upload URL for uploading a new file.
1219 base::RunLoop run_loop
;
1220 InitiateUploadNewFileRequest
* initiate_request
=
1221 new InitiateUploadNewFileRequest(
1222 request_sender_
.get(),
1224 test_util::CreateQuitCallback(
1226 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1228 kUploadContent
.size(),
1231 request_sender_
->StartRequestWithRetry(initiate_request
);
1235 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1236 EXPECT_EQ(test_server_
.GetURL("/upload_new_file"), upload_url
);
1237 EXPECT_EQ(net::test_server::METHOD_POST
, http_request_
.method
);
1238 // convert=false should be passed as files should be uploaded as-is.
1240 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
1241 "?convert=false&v=3&alt=json&showroot=true",
1242 http_request_
.relative_url
);
1243 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1244 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
1245 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1246 http_request_
.headers
["X-Upload-Content-Length"]);
1248 EXPECT_TRUE(http_request_
.has_content
);
1249 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
1250 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
1251 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
1252 " <title>New file</title>\n"
1254 http_request_
.content
);
1256 // 2) Upload the content to the upload URL.
1257 UploadRangeResponse response
;
1258 scoped_ptr
<ResourceEntry
> new_entry
;
1261 base::RunLoop run_loop
;
1262 ResumeUploadRequest
* resume_request
= new ResumeUploadRequest(
1263 request_sender_
.get(),
1264 test_util::CreateQuitCallback(
1266 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1269 0, // start_position
1270 kUploadContent
.size(), // end_position (exclusive)
1271 kUploadContent
.size(), // content_length,
1272 "text/plain", // content_type
1274 request_sender_
->StartRequestWithRetry(resume_request
);
1278 // METHOD_PUT should be used to upload data.
1279 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1280 // Request should go to the upload URL.
1281 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1282 // Content-Range header should not exit if the content is empty.
1283 // We should not generate the header with an invalid value "bytes 0--1/0".
1284 EXPECT_EQ(0U, http_request_
.headers
.count("Content-Range"));
1285 // The upload content should be set in the HTTP request.
1286 EXPECT_TRUE(http_request_
.has_content
);
1287 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1289 // Check the response.
1290 EXPECT_EQ(HTTP_CREATED
, response
.code
); // Because it's a new file.
1291 // The start and end positions should be set to -1, if an upload is complete.
1292 EXPECT_EQ(-1, response
.start_position_received
);
1293 EXPECT_EQ(-1, response
.end_position_received
);
1296 // This test exercises InitiateUploadExistingFileRequest and
1297 // ResumeUploadRequest for a scenario of updating an existing file.
1298 TEST_F(GDataWapiRequestsTest
, UploadExistingFile
) {
1299 const std::string kUploadContent
= "hello";
1300 const base::FilePath kTestFilePath
=
1301 temp_dir_
.path().AppendASCII("upload_file.txt");
1302 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath
, kUploadContent
));
1304 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1307 // 1) Get the upload URL for uploading an existing file.
1309 base::RunLoop run_loop
;
1310 InitiateUploadExistingFileRequest
* initiate_request
=
1311 new InitiateUploadExistingFileRequest(
1312 request_sender_
.get(),
1314 test_util::CreateQuitCallback(
1316 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1318 kUploadContent
.size(),
1320 std::string() /* etag */);
1321 request_sender_
->StartRequestWithRetry(initiate_request
);
1325 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1326 EXPECT_EQ(test_server_
.GetURL("/upload_existing_file"), upload_url
);
1327 // For updating an existing file, METHOD_PUT should be used.
1328 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1329 // convert=false should be passed as files should be uploaded as-is.
1330 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1331 "?convert=false&v=3&alt=json&showroot=true",
1332 http_request_
.relative_url
);
1333 // Even though the body is empty, the content type should be set to
1335 EXPECT_EQ("text/plain", http_request_
.headers
["Content-Type"]);
1336 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1337 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1338 http_request_
.headers
["X-Upload-Content-Length"]);
1339 // For updating an existing file, an empty body should be attached (PUT
1341 EXPECT_TRUE(http_request_
.has_content
);
1342 EXPECT_EQ("", http_request_
.content
);
1343 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
1345 // 2) Upload the content to the upload URL.
1346 UploadRangeResponse response
;
1347 scoped_ptr
<ResourceEntry
> new_entry
;
1350 base::RunLoop run_loop
;
1351 ResumeUploadRequest
* resume_request
= new ResumeUploadRequest(
1352 request_sender_
.get(),
1353 test_util::CreateQuitCallback(
1355 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1358 0, // start_position
1359 kUploadContent
.size(), // end_position (exclusive)
1360 kUploadContent
.size(), // content_length,
1361 "text/plain", // content_type
1364 request_sender_
->StartRequestWithRetry(resume_request
);
1368 // METHOD_PUT should be used to upload data.
1369 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1370 // Request should go to the upload URL.
1371 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1372 // Content-Range header should be added.
1373 EXPECT_EQ("bytes 0-" +
1374 base::Int64ToString(kUploadContent
.size() -1) + "/" +
1375 base::Int64ToString(kUploadContent
.size()),
1376 http_request_
.headers
["Content-Range"]);
1377 // The upload content should be set in the HTTP request.
1378 EXPECT_TRUE(http_request_
.has_content
);
1379 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1381 // Check the response.
1382 EXPECT_EQ(HTTP_SUCCESS
, response
.code
); // Because it's an existing file.
1383 // The start and end positions should be set to -1, if an upload is complete.
1384 EXPECT_EQ(-1, response
.start_position_received
);
1385 EXPECT_EQ(-1, response
.end_position_received
);
1388 // This test exercises InitiateUploadExistingFileRequest and
1389 // ResumeUploadRequest for a scenario of updating an existing file.
1390 TEST_F(GDataWapiRequestsTest
, UploadExistingFileWithETag
) {
1391 const std::string kUploadContent
= "hello";
1392 const base::FilePath kTestFilePath
=
1393 temp_dir_
.path().AppendASCII("upload_file.txt");
1394 ASSERT_TRUE(test_util::WriteStringToFile(kTestFilePath
, kUploadContent
));
1396 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1399 // 1) Get the upload URL for uploading an existing file.
1401 base::RunLoop run_loop
;
1402 InitiateUploadExistingFileRequest
* initiate_request
=
1403 new InitiateUploadExistingFileRequest(
1404 request_sender_
.get(),
1406 test_util::CreateQuitCallback(
1408 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1410 kUploadContent
.size(),
1413 request_sender_
->StartRequestWithRetry(initiate_request
);
1417 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1418 EXPECT_EQ(test_server_
.GetURL("/upload_existing_file"), upload_url
);
1419 // For updating an existing file, METHOD_PUT should be used.
1420 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1421 // convert=false should be passed as files should be uploaded as-is.
1422 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1423 "?convert=false&v=3&alt=json&showroot=true",
1424 http_request_
.relative_url
);
1425 // Even though the body is empty, the content type should be set to
1427 EXPECT_EQ("text/plain", http_request_
.headers
["Content-Type"]);
1428 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1429 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1430 http_request_
.headers
["X-Upload-Content-Length"]);
1431 // For updating an existing file, an empty body should be attached (PUT
1433 EXPECT_TRUE(http_request_
.has_content
);
1434 EXPECT_EQ("", http_request_
.content
);
1435 EXPECT_EQ(kTestETag
, http_request_
.headers
["If-Match"]);
1437 // 2) Upload the content to the upload URL.
1438 UploadRangeResponse response
;
1439 scoped_ptr
<ResourceEntry
> new_entry
;
1442 base::RunLoop run_loop
;
1443 ResumeUploadRequest
* resume_request
= new ResumeUploadRequest(
1444 request_sender_
.get(),
1445 test_util::CreateQuitCallback(
1447 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1450 0, // start_position
1451 kUploadContent
.size(), // end_position (exclusive)
1452 kUploadContent
.size(), // content_length,
1453 "text/plain", // content_type
1455 request_sender_
->StartRequestWithRetry(resume_request
);
1459 // METHOD_PUT should be used to upload data.
1460 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1461 // Request should go to the upload URL.
1462 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1463 // Content-Range header should be added.
1464 EXPECT_EQ("bytes 0-" +
1465 base::Int64ToString(kUploadContent
.size() -1) + "/" +
1466 base::Int64ToString(kUploadContent
.size()),
1467 http_request_
.headers
["Content-Range"]);
1468 // The upload content should be set in the HTTP request.
1469 EXPECT_TRUE(http_request_
.has_content
);
1470 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1472 // Check the response.
1473 EXPECT_EQ(HTTP_SUCCESS
, response
.code
); // Because it's an existing file.
1474 // The start and end positions should be set to -1, if an upload is complete.
1475 EXPECT_EQ(-1, response
.start_position_received
);
1476 EXPECT_EQ(-1, response
.end_position_received
);
1479 // This test exercises InitiateUploadExistingFileRequest for a scenario of
1480 // confliction on updating an existing file.
1481 TEST_F(GDataWapiRequestsTest
, UploadExistingFileWithETagConflict
) {
1482 const std::string kUploadContent
= "hello";
1483 const std::string kWrongETag
= "wrong_etag";
1484 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1488 base::RunLoop run_loop
;
1489 InitiateUploadExistingFileRequest
* initiate_request
=
1490 new InitiateUploadExistingFileRequest(
1491 request_sender_
.get(),
1493 test_util::CreateQuitCallback(
1495 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1497 kUploadContent
.size(),
1500 request_sender_
->StartRequestWithRetry(initiate_request
);
1504 EXPECT_EQ(HTTP_PRECONDITION
, result_code
);
1505 // For updating an existing file, METHOD_PUT should be used.
1506 EXPECT_EQ(net::test_server::METHOD_PUT
, http_request_
.method
);
1507 // convert=false should be passed as files should be uploaded as-is.
1508 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1509 "?convert=false&v=3&alt=json&showroot=true",
1510 http_request_
.relative_url
);
1511 // Even though the body is empty, the content type should be set to
1513 EXPECT_EQ("text/plain", http_request_
.headers
["Content-Type"]);
1514 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1515 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1516 http_request_
.headers
["X-Upload-Content-Length"]);
1517 // For updating an existing file, an empty body should be attached (PUT
1519 EXPECT_TRUE(http_request_
.has_content
);
1520 EXPECT_EQ("", http_request_
.content
);
1521 EXPECT_EQ(kWrongETag
, http_request_
.headers
["If-Match"]);
1524 TEST_F(GDataWapiRequestsTest
, DownloadFileRequest
) {
1525 const base::FilePath kDownloadedFilePath
=
1526 temp_dir_
.path().AppendASCII("cache_file");
1527 const std::string
kTestIdWithTypeLabel("file:dummyId");
1528 const std::string
kTestId("dummyId");
1530 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1531 base::FilePath temp_file
;
1533 base::RunLoop run_loop
;
1534 DownloadFileRequest
* request
= new DownloadFileRequest(
1535 request_sender_
.get(),
1537 test_util::CreateQuitCallback(
1539 test_util::CreateCopyResultCallback(&result_code
, &temp_file
)),
1540 GetContentCallback(),
1542 kTestIdWithTypeLabel
,
1543 kDownloadedFilePath
);
1544 request_sender_
->StartRequestWithRetry(request
);
1548 std::string contents
;
1549 base::ReadFileToString(temp_file
, &contents
);
1550 base::DeleteFile(temp_file
, false);
1552 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1553 EXPECT_EQ(net::test_server::METHOD_GET
, http_request_
.method
);
1554 EXPECT_EQ(kTestDownloadPathPrefix
+ kTestId
, http_request_
.relative_url
);
1555 EXPECT_EQ(kDownloadedFilePath
, temp_file
);
1557 const std::string expected_contents
= kTestId
+ kTestId
+ kTestId
;
1558 EXPECT_EQ(expected_contents
, contents
);
1561 } // namespace google_apis