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/json/json_reader.h"
12 #include "base/json/json_writer.h"
13 #include "base/message_loop_proxy.h"
14 #include "base/stringprintf.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/values.h"
17 #include "chrome/browser/google_apis/gdata_wapi_operations.h"
18 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
19 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
20 #include "chrome/browser/google_apis/operation_registry.h"
21 #include "chrome/browser/google_apis/task_util.h"
22 #include "chrome/browser/google_apis/test_server/http_request.h"
23 #include "chrome/browser/google_apis/test_server/http_response.h"
24 #include "chrome/browser/google_apis/test_server/http_server.h"
25 #include "chrome/browser/google_apis/test_util.h"
26 #include "chrome/browser/profiles/profile.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "content/public/test/test_browser_thread.h"
29 #include "net/base/escape.h"
30 #include "net/url_request/url_request_test_util.h"
31 #include "testing/gtest/include/gtest/gtest.h"
33 namespace google_apis
{
37 const char kTestGDataAuthToken
[] = "testtoken";
38 const char kTestUserAgent
[] = "test-user-agent";
39 const char kTestETag
[] = "test_etag";
41 class GDataWapiOperationsTest
: public testing::Test
{
43 GDataWapiOperationsTest()
44 : ui_thread_(content::BrowserThread::UI
, &message_loop_
),
45 file_thread_(content::BrowserThread::FILE),
46 io_thread_(content::BrowserThread::IO
) {
49 virtual void SetUp() OVERRIDE
{
51 io_thread_
.StartIOThread();
52 profile_
.reset(new TestingProfile
);
54 request_context_getter_
= new net::TestURLRequestContextGetter(
55 content::BrowserThread::GetMessageLoopProxyForThread(
56 content::BrowserThread::IO
));
58 ASSERT_TRUE(test_server_
.InitializeAndWaitUntilReady());
59 test_server_
.RegisterRequestHandler(
60 base::Bind(&test_util::HandleDownloadRequest
,
61 test_server_
.base_url(),
62 base::Unretained(&http_request_
)));
63 test_server_
.RegisterRequestHandler(
64 base::Bind(&GDataWapiOperationsTest::HandleResourceFeedRequest
,
65 base::Unretained(this)));
66 test_server_
.RegisterRequestHandler(
67 base::Bind(&GDataWapiOperationsTest::HandleMetadataRequest
,
68 base::Unretained(this)));
69 test_server_
.RegisterRequestHandler(
70 base::Bind(&GDataWapiOperationsTest::HandleCreateSessionRequest
,
71 base::Unretained(this)));
72 test_server_
.RegisterRequestHandler(
73 base::Bind(&GDataWapiOperationsTest::HandleUploadRequest
,
74 base::Unretained(this)));
76 url_generator_
.reset(new GDataWapiUrlGenerator(
77 test_util::GetBaseUrlForTesting(test_server_
.port())));
83 virtual void TearDown() OVERRIDE
{
84 test_server_
.ShutdownAndWaitUntilComplete();
85 request_context_getter_
= NULL
;
89 // Handles a request for fetching a resource feed.
90 scoped_ptr
<test_server::HttpResponse
> HandleResourceFeedRequest(
91 const test_server::HttpRequest
& request
) {
92 http_request_
= request
;
94 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
95 std::string remaining_path
;
96 if (absolute_url
.path() == "/feeds/default/private/full" &&
97 request
.method
== test_server::METHOD_POST
) {
98 // This is a request for copying a document.
99 // TODO(satorux): we should generate valid JSON data for the newly
100 // copied document but for now, just return "file_entry.json"
101 return test_util::CreateHttpResponseFromFile(
102 test_util::GetTestFilePath("chromeos/gdata/file_entry.json"));
105 if (!test_util::RemovePrefix(absolute_url
.path(),
106 "/feeds/default/private/full",
108 return scoped_ptr
<test_server::HttpResponse
>();
111 if (remaining_path
.empty()) {
112 // Process the default feed.
113 return test_util::CreateHttpResponseFromFile(
114 test_util::GetTestFilePath("chromeos/gdata/root_feed.json"));
116 // Process a feed for a single resource ID.
117 const std::string resource_id
= net::UnescapeURLComponent(
118 remaining_path
.substr(1), net::UnescapeRule::URL_SPECIAL_CHARS
);
119 if (resource_id
== "file:2_file_resource_id") {
120 return test_util::CreateHttpResponseFromFile(
121 test_util::GetTestFilePath("chromeos/gdata/file_entry.json"));
122 } else if (resource_id
== "folder:root/contents" &&
123 request
.method
== test_server::METHOD_POST
) {
124 // This is a request for creating a directory in the root directory.
125 // TODO(satorux): we should generate valid JSON data for the newly
126 // created directory but for now, just return "directory_entry.json"
127 return test_util::CreateHttpResponseFromFile(
128 test_util::GetTestFilePath("chromeos/gdata/directory_entry.json"));
129 } else if (resource_id
==
130 "folder:root/contents/file:2_file_resource_id" &&
131 request
.method
== test_server::METHOD_DELETE
) {
132 // This is a request for deleting a file from the root directory.
133 // TODO(satorux): Investigate what's returned from the server, and
134 // copy it. For now, just return a random file, as the contents don't
136 return test_util::CreateHttpResponseFromFile(
137 test_util::GetTestFilePath("chromeos/gdata/testfile.txt"));
138 } else if (resource_id
== "invalid_resource_id") {
139 // Check if this is an authorization request for an app.
140 // This emulates to return invalid formatted result from the server.
141 if (request
.method
== test_server::METHOD_PUT
&&
142 request
.content
.find("<docs:authorizedApp>") != std::string::npos
) {
143 return test_util::CreateHttpResponseFromFile(
144 test_util::GetTestFilePath("chromeos/gdata/testfile.txt"));
149 return scoped_ptr
<test_server::HttpResponse
>();
152 // Handles a request for fetching a metadata feed.
153 scoped_ptr
<test_server::HttpResponse
> HandleMetadataRequest(
154 const test_server::HttpRequest
& request
) {
155 http_request_
= request
;
157 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
158 if (absolute_url
.path() != "/feeds/metadata/default")
159 return scoped_ptr
<test_server::HttpResponse
>();
161 scoped_ptr
<test_server::HttpResponse
> result(
162 test_util::CreateHttpResponseFromFile(
163 test_util::GetTestFilePath(
164 "chromeos/gdata/account_metadata.json")));
165 if (absolute_url
.query().find("include-installed-apps=true") ==
167 // Exclude the list of installed apps.
168 scoped_ptr
<base::Value
> parsed_content(
169 base::JSONReader::Read(result
->content(), base::JSON_PARSE_RFC
));
170 CHECK(parsed_content
);
172 // Remove the install apps node.
173 base::DictionaryValue
* dictionary_value
;
174 CHECK(parsed_content
->GetAsDictionary(&dictionary_value
));
175 dictionary_value
->Remove("entry.docs$installedApp", NULL
);
177 // Write back it as the content of the result.
179 base::JSONWriter::Write(parsed_content
.get(), &content
);
180 result
->set_content(content
);
183 return result
.Pass();
186 // Handles a request for creating a session for uploading.
187 scoped_ptr
<test_server::HttpResponse
> HandleCreateSessionRequest(
188 const test_server::HttpRequest
& request
) {
189 http_request_
= request
;
191 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
192 if (StartsWithASCII(absolute_url
.path(),
193 "/feeds/upload/create-session/default/private/full",
194 true)) { // case sensitive
195 // This is an initiating upload URL.
196 scoped_ptr
<test_server::HttpResponse
> http_response(
197 new test_server::HttpResponse
);
200 std::map
<std::string
, std::string
>::const_iterator found
=
201 request
.headers
.find("If-Match");
202 if (found
!= request
.headers
.end() &&
203 found
->second
!= "*" &&
204 found
->second
!= kTestETag
) {
205 http_response
->set_code(test_server::PRECONDITION
);
206 return http_response
.Pass();
209 // Check if the X-Upload-Content-Length is present. If yes, store the
210 // length of the file.
211 found
= request
.headers
.find("X-Upload-Content-Length");
212 if (found
== request
.headers
.end() ||
213 !base::StringToInt64(found
->second
, &content_length_
)) {
214 return scoped_ptr
<test_server::HttpResponse
>();
218 http_response
->set_code(test_server::SUCCESS
);
220 // POST is used for a new file, and PUT is used for an existing file.
221 if (request
.method
== test_server::METHOD_POST
) {
222 upload_url
= test_server_
.GetURL("/upload_new_file");
223 } else if (request
.method
== test_server::METHOD_PUT
) {
224 upload_url
= test_server_
.GetURL("/upload_existing_file");
226 return scoped_ptr
<test_server::HttpResponse
>();
228 http_response
->AddCustomHeader("Location", upload_url
.spec());
229 return http_response
.Pass();
232 return scoped_ptr
<test_server::HttpResponse
>();
235 // Handles a request for uploading content.
236 scoped_ptr
<test_server::HttpResponse
> HandleUploadRequest(
237 const test_server::HttpRequest
& request
) {
238 http_request_
= request
;
240 const GURL absolute_url
= test_server_
.GetURL(request
.relative_url
);
241 if (absolute_url
.path() != "/upload_new_file" &&
242 absolute_url
.path() != "/upload_existing_file") {
243 return scoped_ptr
<test_server::HttpResponse
>();
246 // TODO(satorux): We should create a correct JSON data for the uploaded
247 // file, but for now, just return file_entry.json.
248 scoped_ptr
<test_server::HttpResponse
> response
=
249 test_util::CreateHttpResponseFromFile(
250 test_util::GetTestFilePath("chromeos/gdata/file_entry.json"));
251 // response.code() is set to SUCCESS. Change it to CREATED if it's a new
253 if (absolute_url
.path() == "/upload_new_file")
254 response
->set_code(test_server::CREATED
);
256 // Check if the Content-Range header is present. This must be present if
257 // the request body is not empty.
258 if (!request
.content
.empty()) {
259 std::map
<std::string
, std::string
>::const_iterator iter
=
260 request
.headers
.find("Content-Range");
261 if (iter
== request
.headers
.end())
262 return scoped_ptr
<test_server::HttpResponse
>();
264 int64 start_position
= 0;
265 int64 end_position
= 0;
266 if (!test_util::ParseContentRangeHeader(iter
->second
,
270 return scoped_ptr
<test_server::HttpResponse
>();
272 EXPECT_EQ(start_position
, received_bytes_
);
273 EXPECT_EQ(length
, content_length_
);
274 // end_position is inclusive, but so +1 to change the range to byte size.
275 received_bytes_
= end_position
+ 1;
278 // Add Range header to the response, based on the values of
279 // Content-Range header in the request.
280 // The header is annotated only when at least one byte is received.
281 if (received_bytes_
> 0) {
282 response
->AddCustomHeader(
284 "bytes=0-" + base::Int64ToString(received_bytes_
- 1));
287 // Change the code to RESUME_INCOMPLETE if upload is not complete.
288 if (received_bytes_
< content_length_
)
289 response
->set_code(test_server::RESUME_INCOMPLETE
);
291 return response
.Pass();
294 MessageLoopForUI message_loop_
;
295 content::TestBrowserThread ui_thread_
;
296 content::TestBrowserThread file_thread_
;
297 content::TestBrowserThread io_thread_
;
298 test_server::HttpServer test_server_
;
299 scoped_ptr
<TestingProfile
> profile_
;
300 OperationRegistry operation_registry_
;
301 scoped_ptr
<GDataWapiUrlGenerator
> url_generator_
;
302 scoped_refptr
<net::TestURLRequestContextGetter
> request_context_getter_
;
304 // These fields are used to keep the current upload state during a
305 // test case. These values are updated by the request from
306 // ResumeUploadOperation, and used to construct the response for
307 // both ResumeUploadOperation and GetUploadStatusOperation, to emulate
309 int64 received_bytes_
;
310 int64 content_length_
;
312 // The incoming HTTP request is saved so tests can verify the request
313 // parameters like HTTP method (ex. some operations should use DELETE
315 test_server::HttpRequest http_request_
;
320 TEST_F(GDataWapiOperationsTest
, GetResourceListOperation_DefaultFeed
) {
321 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
322 scoped_ptr
<ResourceList
> result_data
;
324 GetResourceListOperation
* operation
= new GetResourceListOperation(
325 &operation_registry_
,
326 request_context_getter_
.get(),
328 GURL(), // Pass an empty URL to use the default feed
329 0, // start changestamp
330 std::string(), // search string
331 std::string(), // directory resource ID
332 CreateComposedCallback(
333 base::Bind(&test_util::RunAndQuit
),
334 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
335 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
336 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
337 MessageLoop::current()->Run();
339 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
340 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
341 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true&"
342 "showfolders=true&include-shared=true&max-results=500&"
343 "include-installed-apps=true",
344 http_request_
.relative_url
);
346 // Sanity check of the result.
347 scoped_ptr
<ResourceList
> expected(
348 ResourceList::ExtractAndParse(
349 *test_util::LoadJSONFile("chromeos/gdata/root_feed.json")));
350 ASSERT_TRUE(result_data
);
351 EXPECT_EQ(expected
->title(), result_data
->title());
354 TEST_F(GDataWapiOperationsTest
, GetResourceListOperation_ValidFeed
) {
355 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
356 scoped_ptr
<ResourceList
> result_data
;
358 GetResourceListOperation
* operation
= new GetResourceListOperation(
359 &operation_registry_
,
360 request_context_getter_
.get(),
362 test_server_
.GetURL("/files/chromeos/gdata/root_feed.json"),
363 0, // start changestamp
364 std::string(), // search string
365 std::string(), // directory resource ID
366 CreateComposedCallback(
367 base::Bind(&test_util::RunAndQuit
),
368 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
369 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
370 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
371 MessageLoop::current()->Run();
373 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
374 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
375 EXPECT_EQ("/files/chromeos/gdata/root_feed.json?v=3&alt=json&showroot=true&"
376 "showfolders=true&include-shared=true&max-results=500"
377 "&include-installed-apps=true",
378 http_request_
.relative_url
);
380 scoped_ptr
<ResourceList
> expected(
381 ResourceList::ExtractAndParse(
382 *test_util::LoadJSONFile("chromeos/gdata/root_feed.json")));
383 ASSERT_TRUE(result_data
);
384 EXPECT_EQ(expected
->title(), result_data
->title());
387 TEST_F(GDataWapiOperationsTest
, GetResourceListOperation_InvalidFeed
) {
388 // testfile.txt exists but the response is not JSON, so it should
389 // emit a parse error instead.
390 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
391 scoped_ptr
<ResourceList
> result_data
;
393 GetResourceListOperation
* operation
= new GetResourceListOperation(
394 &operation_registry_
,
395 request_context_getter_
.get(),
397 test_server_
.GetURL("/files/chromeos/gdata/testfile.txt"),
398 0, // start changestamp
399 std::string(), // search string
400 std::string(), // directory resource ID
401 CreateComposedCallback(
402 base::Bind(&test_util::RunAndQuit
),
403 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
404 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
405 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
406 MessageLoop::current()->Run();
408 EXPECT_EQ(GDATA_PARSE_ERROR
, result_code
);
409 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
410 EXPECT_EQ("/files/chromeos/gdata/testfile.txt?v=3&alt=json&showroot=true&"
411 "showfolders=true&include-shared=true&max-results=500&"
412 "include-installed-apps=true",
413 http_request_
.relative_url
);
414 EXPECT_FALSE(result_data
);
417 TEST_F(GDataWapiOperationsTest
, GetResourceEntryOperation_ValidResourceId
) {
418 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
419 scoped_ptr
<base::Value
> result_data
;
421 GetResourceEntryOperation
* operation
= new GetResourceEntryOperation(
422 &operation_registry_
,
423 request_context_getter_
.get(),
425 "file:2_file_resource_id", // resource ID
426 CreateComposedCallback(
427 base::Bind(&test_util::RunAndQuit
),
428 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
429 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
430 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
431 MessageLoop::current()->Run();
433 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
434 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
435 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
436 "?v=3&alt=json&showroot=true",
437 http_request_
.relative_url
);
438 EXPECT_TRUE(test_util::VerifyJsonData(
439 test_util::GetTestFilePath("chromeos/gdata/file_entry.json"),
443 TEST_F(GDataWapiOperationsTest
, GetResourceEntryOperation_InvalidResourceId
) {
444 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
445 scoped_ptr
<base::Value
> result_data
;
447 GetResourceEntryOperation
* operation
= new GetResourceEntryOperation(
448 &operation_registry_
,
449 request_context_getter_
.get(),
451 "<invalid>", // resource ID
452 CreateComposedCallback(
453 base::Bind(&test_util::RunAndQuit
),
454 test_util::CreateCopyResultCallback(&result_code
, &result_data
)));
455 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
456 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
457 MessageLoop::current()->Run();
459 EXPECT_EQ(HTTP_NOT_FOUND
, result_code
);
460 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
461 EXPECT_EQ("/feeds/default/private/full/%3Cinvalid%3E?v=3&alt=json"
463 http_request_
.relative_url
);
464 ASSERT_FALSE(result_data
);
467 TEST_F(GDataWapiOperationsTest
, GetAccountMetadataOperation
) {
468 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
469 scoped_ptr
<AccountMetadata
> result_data
;
471 GetAccountMetadataOperation
* operation
= new GetAccountMetadataOperation(
472 &operation_registry_
,
473 request_context_getter_
.get(),
475 CreateComposedCallback(
476 base::Bind(&test_util::RunAndQuit
),
477 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
478 true); // Include installed apps.
479 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
480 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
481 MessageLoop::current()->Run();
483 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
484 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
485 EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true"
486 "&include-installed-apps=true",
487 http_request_
.relative_url
);
489 scoped_ptr
<AccountMetadata
> expected(
490 AccountMetadata::CreateFrom(
491 *test_util::LoadJSONFile("chromeos/gdata/account_metadata.json")));
493 ASSERT_TRUE(result_data
.get());
494 EXPECT_EQ(expected
->largest_changestamp(),
495 result_data
->largest_changestamp());
496 EXPECT_EQ(expected
->quota_bytes_total(),
497 result_data
->quota_bytes_total());
498 EXPECT_EQ(expected
->quota_bytes_used(),
499 result_data
->quota_bytes_used());
501 // Sanity check for installed apps.
502 EXPECT_EQ(expected
->installed_apps().size(),
503 result_data
->installed_apps().size());
506 TEST_F(GDataWapiOperationsTest
,
507 GetAccountMetadataOperationWithoutInstalledApps
) {
508 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
509 scoped_ptr
<AccountMetadata
> result_data
;
511 GetAccountMetadataOperation
* operation
= new GetAccountMetadataOperation(
512 &operation_registry_
,
513 request_context_getter_
.get(),
515 CreateComposedCallback(
516 base::Bind(&test_util::RunAndQuit
),
517 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
518 false); // Exclude installed apps.
519 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
520 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
521 MessageLoop::current()->Run();
523 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
524 EXPECT_EQ(test_server::METHOD_GET
, http_request_
.method
);
525 EXPECT_EQ("/feeds/metadata/default?v=3&alt=json&showroot=true",
526 http_request_
.relative_url
);
528 scoped_ptr
<AccountMetadata
> expected(
529 AccountMetadata::CreateFrom(
530 *test_util::LoadJSONFile("chromeos/gdata/account_metadata.json")));
532 ASSERT_TRUE(result_data
.get());
533 EXPECT_EQ(expected
->largest_changestamp(),
534 result_data
->largest_changestamp());
535 EXPECT_EQ(expected
->quota_bytes_total(),
536 result_data
->quota_bytes_total());
537 EXPECT_EQ(expected
->quota_bytes_used(),
538 result_data
->quota_bytes_used());
540 // Installed apps shouldn't be included.
541 EXPECT_EQ(0U, result_data
->installed_apps().size());
544 TEST_F(GDataWapiOperationsTest
, DeleteResourceOperation
) {
545 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
547 DeleteResourceOperation
* operation
= new DeleteResourceOperation(
548 &operation_registry_
,
549 request_context_getter_
.get(),
551 CreateComposedCallback(base::Bind(&test_util::RunAndQuit
),
552 test_util::CreateCopyResultCallback(&result_code
)),
553 "file:2_file_resource_id",
556 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
557 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
558 MessageLoop::current()->Run();
560 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
561 EXPECT_EQ(test_server::METHOD_DELETE
, http_request_
.method
);
563 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
565 http_request_
.relative_url
);
566 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
569 TEST_F(GDataWapiOperationsTest
, DeleteResourceOperationWithETag
) {
570 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
572 DeleteResourceOperation
* operation
= new DeleteResourceOperation(
573 &operation_registry_
,
574 request_context_getter_
.get(),
576 CreateComposedCallback(
577 base::Bind(&test_util::RunAndQuit
),
578 test_util::CreateCopyResultCallback(&result_code
)),
579 "file:2_file_resource_id",
582 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
583 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
584 MessageLoop::current()->Run();
586 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
587 EXPECT_EQ(test_server::METHOD_DELETE
, http_request_
.method
);
589 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
591 http_request_
.relative_url
);
592 EXPECT_EQ("etag", http_request_
.headers
["If-Match"]);
595 TEST_F(GDataWapiOperationsTest
, CreateDirectoryOperation
) {
596 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
597 scoped_ptr
<base::Value
> result_data
;
599 // Create "new directory" in the root directory.
600 CreateDirectoryOperation
* operation
= new CreateDirectoryOperation(
601 &operation_registry_
,
602 request_context_getter_
.get(),
604 CreateComposedCallback(
605 base::Bind(&test_util::RunAndQuit
),
606 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
610 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
611 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
612 MessageLoop::current()->Run();
614 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
615 EXPECT_EQ(test_server::METHOD_POST
, http_request_
.method
);
616 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json"
618 http_request_
.relative_url
);
619 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
621 EXPECT_TRUE(http_request_
.has_content
);
622 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
623 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
624 " <category scheme=\"http://schemas.google.com/g/2005#kind\" "
625 "term=\"http://schemas.google.com/docs/2007#folder\"/>\n"
626 " <title>new directory</title>\n"
628 http_request_
.content
);
631 TEST_F(GDataWapiOperationsTest
, CopyHostedDocumentOperation
) {
632 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
633 scoped_ptr
<base::Value
> result_data
;
635 // Copy a document with a new name "New Document".
636 CopyHostedDocumentOperation
* operation
= new CopyHostedDocumentOperation(
637 &operation_registry_
,
638 request_context_getter_
.get(),
640 CreateComposedCallback(
641 base::Bind(&test_util::RunAndQuit
),
642 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
643 "document:5_document_resource_id", // source resource ID
646 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
647 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
648 MessageLoop::current()->Run();
650 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
651 EXPECT_EQ(test_server::METHOD_POST
, http_request_
.method
);
652 EXPECT_EQ("/feeds/default/private/full?v=3&alt=json&showroot=true",
653 http_request_
.relative_url
);
654 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
656 EXPECT_TRUE(http_request_
.has_content
);
657 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
658 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
659 " <id>document:5_document_resource_id</id>\n"
660 " <title>New Document</title>\n"
662 http_request_
.content
);
665 TEST_F(GDataWapiOperationsTest
, RenameResourceOperation
) {
666 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
668 // Rename a file with a new name "New File".
669 RenameResourceOperation
* operation
= new RenameResourceOperation(
670 &operation_registry_
,
671 request_context_getter_
.get(),
673 CreateComposedCallback(
674 base::Bind(&test_util::RunAndQuit
),
675 test_util::CreateCopyResultCallback(&result_code
)),
676 "file:2_file_resource_id",
679 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
680 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
681 MessageLoop::current()->Run();
683 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
684 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
686 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
688 http_request_
.relative_url
);
689 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
690 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
692 EXPECT_TRUE(http_request_
.has_content
);
693 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
694 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
695 " <title>New File</title>\n"
697 http_request_
.content
);
700 TEST_F(GDataWapiOperationsTest
, AuthorizeAppOperation_ValidFeed
) {
701 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
704 // Authorize an app with APP_ID to access to a document.
705 AuthorizeAppOperation
* operation
= new AuthorizeAppOperation(
706 &operation_registry_
,
707 request_context_getter_
.get(),
709 CreateComposedCallback(
710 base::Bind(&test_util::RunAndQuit
),
711 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
712 "file:2_file_resource_id",
715 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
716 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
717 MessageLoop::current()->Run();
719 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
720 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
721 EXPECT_EQ("/feeds/default/private/full/file%3A2_file_resource_id"
722 "?v=3&alt=json&showroot=true",
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\" "
730 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
731 " <docs:authorizedApp>APP_ID</docs:authorizedApp>\n"
733 http_request_
.content
);
736 TEST_F(GDataWapiOperationsTest
, AuthorizeAppOperation_InvalidFeed
) {
737 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
740 // Authorize an app with APP_ID to access to a document but an invalid feed.
741 AuthorizeAppOperation
* operation
= new AuthorizeAppOperation(
742 &operation_registry_
,
743 request_context_getter_
.get(),
745 CreateComposedCallback(
746 base::Bind(&test_util::RunAndQuit
),
747 test_util::CreateCopyResultCallback(&result_code
, &result_data
)),
748 "invalid_resource_id",
751 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
752 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
753 MessageLoop::current()->Run();
755 EXPECT_EQ(GDATA_PARSE_ERROR
, result_code
);
756 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
757 EXPECT_EQ("/feeds/default/private/full/invalid_resource_id"
758 "?v=3&alt=json&showroot=true",
759 http_request_
.relative_url
);
760 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
761 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
763 EXPECT_TRUE(http_request_
.has_content
);
764 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
765 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
766 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
767 " <docs:authorizedApp>APP_ID</docs:authorizedApp>\n"
769 http_request_
.content
);
772 TEST_F(GDataWapiOperationsTest
, AddResourceToDirectoryOperation
) {
773 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
775 // Add a file to the root directory.
776 AddResourceToDirectoryOperation
* operation
=
777 new AddResourceToDirectoryOperation(
778 &operation_registry_
,
779 request_context_getter_
.get(),
781 CreateComposedCallback(
782 base::Bind(&test_util::RunAndQuit
),
783 test_util::CreateCopyResultCallback(&result_code
)),
785 "file:2_file_resource_id");
787 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
788 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
789 MessageLoop::current()->Run();
791 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
792 EXPECT_EQ(test_server::METHOD_POST
, http_request_
.method
);
793 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents?v=3&alt=json"
795 http_request_
.relative_url
);
796 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
798 EXPECT_TRUE(http_request_
.has_content
);
799 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
800 "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
801 " <id>http://127.0.0.1:8040/feeds/default/private/full/"
802 "file%3A2_file_resource_id</id>\n"
804 http_request_
.content
);
807 TEST_F(GDataWapiOperationsTest
, RemoveResourceFromDirectoryOperation
) {
808 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
810 // Remove a file from the root directory.
811 RemoveResourceFromDirectoryOperation
* operation
=
812 new RemoveResourceFromDirectoryOperation(
813 &operation_registry_
,
814 request_context_getter_
.get(),
816 CreateComposedCallback(
817 base::Bind(&test_util::RunAndQuit
),
818 test_util::CreateCopyResultCallback(&result_code
)),
820 "file:2_file_resource_id");
822 operation
->Start(kTestGDataAuthToken
, kTestUserAgent
,
823 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
824 MessageLoop::current()->Run();
826 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
827 // DELETE method should be used, without the body content.
828 EXPECT_EQ(test_server::METHOD_DELETE
, http_request_
.method
);
829 EXPECT_EQ("/feeds/default/private/full/folder%3Aroot/contents/"
830 "file%3A2_file_resource_id?v=3&alt=json&showroot=true",
831 http_request_
.relative_url
);
832 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
833 EXPECT_FALSE(http_request_
.has_content
);
836 // This test exercises InitiateUploadNewFileOperation and
837 // ResumeUploadOperation for a scenario of uploading a new file.
838 TEST_F(GDataWapiOperationsTest
, UploadNewFile
) {
839 const std::string kUploadContent
= "hello";
840 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
843 // 1) Get the upload URL for uploading a new file.
844 InitiateUploadNewFileOperation
* initiate_operation
=
845 new InitiateUploadNewFileOperation(
846 &operation_registry_
,
847 request_context_getter_
.get(),
849 CreateComposedCallback(
850 base::Bind(&test_util::RunAndQuit
),
851 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
852 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
854 kUploadContent
.size(),
858 initiate_operation
->Start(
859 kTestGDataAuthToken
, kTestUserAgent
,
860 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
861 MessageLoop::current()->Run();
863 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
864 EXPECT_EQ(test_server_
.GetURL("/upload_new_file"), upload_url
);
865 EXPECT_EQ(test_server::METHOD_POST
, http_request_
.method
);
866 // convert=false should be passed as files should be uploaded as-is.
868 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
869 "?convert=false&v=3&alt=json&showroot=true",
870 http_request_
.relative_url
);
871 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
872 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
873 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
874 http_request_
.headers
["X-Upload-Content-Length"]);
876 EXPECT_TRUE(http_request_
.has_content
);
877 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
878 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
879 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
880 " <title>New file</title>\n"
882 http_request_
.content
);
884 // 2) Upload the content to the upload URL.
885 scoped_refptr
<net::IOBuffer
> buffer
= new net::StringIOBuffer(kUploadContent
);
887 UploadRangeResponse response
;
888 scoped_ptr
<ResourceEntry
> new_entry
;
890 ResumeUploadOperation
* resume_operation
= new ResumeUploadOperation(
891 &operation_registry_
,
892 request_context_getter_
.get(),
893 CreateComposedCallback(
894 base::Bind(&test_util::RunAndQuit
),
895 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
898 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
901 kUploadContent
.size(), // end_position (exclusive)
902 kUploadContent
.size(), // content_length,
903 "text/plain", // content_type
906 resume_operation
->Start(
907 kTestGDataAuthToken
, kTestUserAgent
,
908 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
909 MessageLoop::current()->Run();
911 // METHOD_PUT should be used to upload data.
912 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
913 // Request should go to the upload URL.
914 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
915 // Content-Range header should be added.
916 EXPECT_EQ("bytes 0-" +
917 base::Int64ToString(kUploadContent
.size() -1) + "/" +
918 base::Int64ToString(kUploadContent
.size()),
919 http_request_
.headers
["Content-Range"]);
920 // The upload content should be set in the HTTP request.
921 EXPECT_TRUE(http_request_
.has_content
);
922 EXPECT_EQ(kUploadContent
, http_request_
.content
);
924 // Check the response.
925 EXPECT_EQ(HTTP_CREATED
, response
.code
); // Because it's a new file
926 // The start and end positions should be set to -1, if an upload is complete.
927 EXPECT_EQ(-1, response
.start_position_received
);
928 EXPECT_EQ(-1, response
.end_position_received
);
931 // This test exercises InitiateUploadNewFileOperation and ResumeUploadOperation
932 // for a scenario of uploading a new *large* file, which requires multiple
933 // requests of ResumeUploadOperation. GetUploadOperation is also tested in this
935 TEST_F(GDataWapiOperationsTest
, UploadNewLargeFile
) {
936 const size_t kMaxNumBytes
= 10;
937 // This is big enough to cause multiple requests of ResumeUploadOperation
938 // as we are going to send at most kMaxNumBytes at a time.
939 // So, sending "kMaxNumBytes * 2 + 1" bytes ensures three
940 // ResumeUploadOperations, which are start, middle and last operations.
941 const std::string
kUploadContent(kMaxNumBytes
* 2 + 1, 'a');
942 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
945 // 1) Get the upload URL for uploading a new file.
946 InitiateUploadNewFileOperation
* initiate_operation
=
947 new InitiateUploadNewFileOperation(
948 &operation_registry_
,
949 request_context_getter_
.get(),
951 CreateComposedCallback(
952 base::Bind(&test_util::RunAndQuit
),
953 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
954 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
956 kUploadContent
.size(),
960 initiate_operation
->Start(
961 kTestGDataAuthToken
, kTestUserAgent
,
962 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
963 MessageLoop::current()->Run();
965 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
966 EXPECT_EQ(test_server_
.GetURL("/upload_new_file"), upload_url
);
967 EXPECT_EQ(test_server::METHOD_POST
, http_request_
.method
);
968 // convert=false should be passed as files should be uploaded as-is.
970 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
971 "?convert=false&v=3&alt=json&showroot=true",
972 http_request_
.relative_url
);
973 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
974 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
975 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
976 http_request_
.headers
["X-Upload-Content-Length"]);
978 EXPECT_TRUE(http_request_
.has_content
);
979 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
980 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
981 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
982 " <title>New file</title>\n"
984 http_request_
.content
);
986 // 2) Before sending any data, check the current status.
987 // This is an edge case test for GetUploadStatusOperation
988 // (UploadRangeOperationBase).
990 UploadRangeResponse response
;
991 scoped_ptr
<ResourceEntry
> new_entry
;
993 // Check the response by GetUploadStatusOperation.
994 GetUploadStatusOperation
* get_upload_status_operation
=
995 new GetUploadStatusOperation(
996 &operation_registry_
,
997 request_context_getter_
.get(),
998 CreateComposedCallback(
999 base::Bind(&test_util::RunAndQuit
),
1000 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1002 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1004 kUploadContent
.size());
1005 get_upload_status_operation
->Start(
1006 kTestGDataAuthToken
, kTestUserAgent
,
1007 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1008 MessageLoop::current()->Run();
1010 // METHOD_PUT should be used to upload data.
1011 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1012 // Request should go to the upload URL.
1013 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1014 // Content-Range header should be added.
1015 EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent
.size()),
1016 http_request_
.headers
["Content-Range"]);
1017 EXPECT_TRUE(http_request_
.has_content
);
1018 EXPECT_TRUE(http_request_
.content
.empty());
1020 // Check the response.
1021 EXPECT_EQ(HTTP_RESUME_INCOMPLETE
, response
.code
);
1022 EXPECT_EQ(0, response
.start_position_received
);
1023 EXPECT_EQ(0, response
.end_position_received
);
1026 // 3) Upload the content to the upload URL with multiple requests.
1027 size_t num_bytes_consumed
= 0;
1028 for (size_t start_position
= 0; start_position
< kUploadContent
.size();
1029 start_position
+= kMaxNumBytes
) {
1030 SCOPED_TRACE(testing::Message("start_position: ") << start_position
);
1032 // The payload is at most kMaxNumBytes.
1033 const size_t remaining_size
= kUploadContent
.size() - start_position
;
1034 const std::string payload
= kUploadContent
.substr(
1035 start_position
, std::min(kMaxNumBytes
, remaining_size
));
1036 num_bytes_consumed
+= payload
.size();
1037 // The end position is exclusive.
1038 const size_t end_position
= start_position
+ payload
.size();
1040 scoped_refptr
<net::IOBuffer
> buffer
= new net::StringIOBuffer(payload
);
1042 UploadRangeResponse response
;
1043 scoped_ptr
<ResourceEntry
> new_entry
;
1045 ResumeUploadOperation
* resume_operation
= new ResumeUploadOperation(
1046 &operation_registry_
,
1047 request_context_getter_
.get(),
1048 CreateComposedCallback(
1049 base::Bind(&test_util::RunAndQuit
),
1050 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1053 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1057 kUploadContent
.size(), // content_length,
1058 "text/plain", // content_type
1061 resume_operation
->Start(
1062 kTestGDataAuthToken
, kTestUserAgent
,
1063 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1064 MessageLoop::current()->Run();
1066 // METHOD_PUT should be used to upload data.
1067 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1068 // Request should go to the upload URL.
1069 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1070 // Content-Range header should be added.
1071 EXPECT_EQ("bytes " +
1072 base::Int64ToString(start_position
) + "-" +
1073 base::Int64ToString(end_position
- 1) + "/" +
1074 base::Int64ToString(kUploadContent
.size()),
1075 http_request_
.headers
["Content-Range"]);
1076 // The upload content should be set in the HTTP request.
1077 EXPECT_TRUE(http_request_
.has_content
);
1078 EXPECT_EQ(payload
, http_request_
.content
);
1080 // Check the response.
1081 if (payload
.size() == remaining_size
) {
1082 EXPECT_EQ(HTTP_CREATED
, response
.code
); // Because it's a new file.
1083 // The start and end positions should be set to -1, if an upload is
1085 EXPECT_EQ(-1, response
.start_position_received
);
1086 EXPECT_EQ(-1, response
.end_position_received
);
1087 // The upload process is completed, so exit from the loop.
1091 EXPECT_EQ(HTTP_RESUME_INCOMPLETE
, response
.code
);
1092 EXPECT_EQ(0, response
.start_position_received
);
1093 EXPECT_EQ(static_cast<int64
>(end_position
),
1094 response
.end_position_received
);
1096 // Check the response by GetUploadStatusOperation.
1097 GetUploadStatusOperation
* get_upload_status_operation
=
1098 new GetUploadStatusOperation(
1099 &operation_registry_
,
1100 request_context_getter_
.get(),
1101 CreateComposedCallback(
1102 base::Bind(&test_util::RunAndQuit
),
1103 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1105 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1107 kUploadContent
.size());
1108 get_upload_status_operation
->Start(
1109 kTestGDataAuthToken
, kTestUserAgent
,
1110 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1111 MessageLoop::current()->Run();
1113 // METHOD_PUT should be used to upload data.
1114 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1115 // Request should go to the upload URL.
1116 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1117 // Content-Range header should be added.
1118 EXPECT_EQ("bytes */" + base::Int64ToString(kUploadContent
.size()),
1119 http_request_
.headers
["Content-Range"]);
1120 EXPECT_TRUE(http_request_
.has_content
);
1121 EXPECT_TRUE(http_request_
.content
.empty());
1123 // Check the response.
1124 EXPECT_EQ(HTTP_RESUME_INCOMPLETE
, response
.code
);
1125 EXPECT_EQ(0, response
.start_position_received
);
1126 EXPECT_EQ(static_cast<int64
>(end_position
),
1127 response
.end_position_received
);
1130 EXPECT_EQ(kUploadContent
.size(), num_bytes_consumed
);
1133 // This test exercises InitiateUploadNewFileOperation and ResumeUploadOperation
1134 // for a scenario of uploading a new *empty* file.
1136 // The test is almost identical to UploadNewFile. The only difference is the
1137 // expectation for the Content-Range header.
1138 TEST_F(GDataWapiOperationsTest
, UploadNewEmptyFile
) {
1139 const std::string kUploadContent
;
1140 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1143 // 1) Get the upload URL for uploading a new file.
1144 InitiateUploadNewFileOperation
* initiate_operation
=
1145 new InitiateUploadNewFileOperation(
1146 &operation_registry_
,
1147 request_context_getter_
.get(),
1149 CreateComposedCallback(
1150 base::Bind(&test_util::RunAndQuit
),
1151 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1152 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1154 kUploadContent
.size(),
1158 initiate_operation
->Start(
1159 kTestGDataAuthToken
, kTestUserAgent
,
1160 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1161 MessageLoop::current()->Run();
1163 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1164 EXPECT_EQ(test_server_
.GetURL("/upload_new_file"), upload_url
);
1165 EXPECT_EQ(test_server::METHOD_POST
, http_request_
.method
);
1166 // convert=false should be passed as files should be uploaded as-is.
1168 "/feeds/upload/create-session/default/private/full/folder%3Aid/contents"
1169 "?convert=false&v=3&alt=json&showroot=true",
1170 http_request_
.relative_url
);
1171 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1172 EXPECT_EQ("application/atom+xml", http_request_
.headers
["Content-Type"]);
1173 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1174 http_request_
.headers
["X-Upload-Content-Length"]);
1176 EXPECT_TRUE(http_request_
.has_content
);
1177 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
1178 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
1179 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
1180 " <title>New file</title>\n"
1182 http_request_
.content
);
1184 // 2) Upload the content to the upload URL.
1185 scoped_refptr
<net::IOBuffer
> buffer
= new net::StringIOBuffer(kUploadContent
);
1187 UploadRangeResponse response
;
1188 scoped_ptr
<ResourceEntry
> new_entry
;
1190 ResumeUploadOperation
* resume_operation
= new ResumeUploadOperation(
1191 &operation_registry_
,
1192 request_context_getter_
.get(),
1193 CreateComposedCallback(
1194 base::Bind(&test_util::RunAndQuit
),
1195 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1198 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1200 0, // start_position
1201 kUploadContent
.size(), // end_position (exclusive)
1202 kUploadContent
.size(), // content_length,
1203 "text/plain", // content_type
1206 resume_operation
->Start(
1207 kTestGDataAuthToken
, kTestUserAgent
,
1208 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1209 MessageLoop::current()->Run();
1211 // METHOD_PUT should be used to upload data.
1212 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1213 // Request should go to the upload URL.
1214 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1215 // Content-Range header should not exit if the content is empty.
1216 // We should not generate the header with an invalid value "bytes 0--1/0".
1217 EXPECT_EQ(0U, http_request_
.headers
.count("Content-Range"));
1218 // The upload content should be set in the HTTP request.
1219 EXPECT_TRUE(http_request_
.has_content
);
1220 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1222 // Check the response.
1223 EXPECT_EQ(HTTP_CREATED
, response
.code
); // Because it's a new file.
1224 // The start and end positions should be set to -1, if an upload is complete.
1225 EXPECT_EQ(-1, response
.start_position_received
);
1226 EXPECT_EQ(-1, response
.end_position_received
);
1229 // This test exercises InitiateUploadExistingFileOperation and
1230 // ResumeUploadOperation for a scenario of updating an existing file.
1231 TEST_F(GDataWapiOperationsTest
, UploadExistingFile
) {
1232 const std::string kUploadContent
= "hello";
1233 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1236 // 1) Get the upload URL for uploading an existing file.
1237 InitiateUploadExistingFileOperation
* initiate_operation
=
1238 new InitiateUploadExistingFileOperation(
1239 &operation_registry_
,
1240 request_context_getter_
.get(),
1242 CreateComposedCallback(
1243 base::Bind(&test_util::RunAndQuit
),
1244 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1245 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1247 kUploadContent
.size(),
1249 std::string() /* etag */);
1251 initiate_operation
->Start(
1252 kTestGDataAuthToken
, kTestUserAgent
,
1253 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1254 MessageLoop::current()->Run();
1256 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1257 EXPECT_EQ(test_server_
.GetURL("/upload_existing_file"), upload_url
);
1258 // For updating an existing file, METHOD_PUT should be used.
1259 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1260 // convert=false should be passed as files should be uploaded as-is.
1261 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1262 "?convert=false&v=3&alt=json&showroot=true",
1263 http_request_
.relative_url
);
1264 // Even though the body is empty, the content type should be set to
1266 EXPECT_EQ("text/plain", http_request_
.headers
["Content-Type"]);
1267 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1268 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1269 http_request_
.headers
["X-Upload-Content-Length"]);
1270 // For updating an existing file, an empty body should be attached (PUT
1272 EXPECT_TRUE(http_request_
.has_content
);
1273 EXPECT_EQ("", http_request_
.content
);
1274 EXPECT_EQ("*", http_request_
.headers
["If-Match"]);
1276 // 2) Upload the content to the upload URL.
1277 scoped_refptr
<net::IOBuffer
> buffer
= new net::StringIOBuffer(kUploadContent
);
1279 UploadRangeResponse response
;
1280 scoped_ptr
<ResourceEntry
> new_entry
;
1282 ResumeUploadOperation
* resume_operation
= new ResumeUploadOperation(
1283 &operation_registry_
,
1284 request_context_getter_
.get(),
1285 CreateComposedCallback(
1286 base::Bind(&test_util::RunAndQuit
),
1287 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1289 UPLOAD_EXISTING_FILE
,
1290 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1292 0, // start_position
1293 kUploadContent
.size(), // end_position (exclusive)
1294 kUploadContent
.size(), // content_length,
1295 "text/plain", // content_type
1298 resume_operation
->Start(
1299 kTestGDataAuthToken
, kTestUserAgent
,
1300 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1301 MessageLoop::current()->Run();
1303 // METHOD_PUT should be used to upload data.
1304 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1305 // Request should go to the upload URL.
1306 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1307 // Content-Range header should be added.
1308 EXPECT_EQ("bytes 0-" +
1309 base::Int64ToString(kUploadContent
.size() -1) + "/" +
1310 base::Int64ToString(kUploadContent
.size()),
1311 http_request_
.headers
["Content-Range"]);
1312 // The upload content should be set in the HTTP request.
1313 EXPECT_TRUE(http_request_
.has_content
);
1314 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1316 // Check the response.
1317 EXPECT_EQ(HTTP_SUCCESS
, response
.code
); // Because it's an existing file.
1318 // The start and end positions should be set to -1, if an upload is complete.
1319 EXPECT_EQ(-1, response
.start_position_received
);
1320 EXPECT_EQ(-1, response
.end_position_received
);
1323 // This test exercises InitiateUploadExistingFileOperation and
1324 // ResumeUploadOperation for a scenario of updating an existing file.
1325 TEST_F(GDataWapiOperationsTest
, UploadExistingFileWithETag
) {
1326 const std::string kUploadContent
= "hello";
1327 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1330 // 1) Get the upload URL for uploading an existing file.
1331 InitiateUploadExistingFileOperation
* initiate_operation
=
1332 new InitiateUploadExistingFileOperation(
1333 &operation_registry_
,
1334 request_context_getter_
.get(),
1336 CreateComposedCallback(
1337 base::Bind(&test_util::RunAndQuit
),
1338 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1339 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1341 kUploadContent
.size(),
1345 initiate_operation
->Start(
1346 kTestGDataAuthToken
, kTestUserAgent
,
1347 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1348 MessageLoop::current()->Run();
1350 EXPECT_EQ(HTTP_SUCCESS
, result_code
);
1351 EXPECT_EQ(test_server_
.GetURL("/upload_existing_file"), upload_url
);
1352 // For updating an existing file, METHOD_PUT should be used.
1353 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1354 // convert=false should be passed as files should be uploaded as-is.
1355 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1356 "?convert=false&v=3&alt=json&showroot=true",
1357 http_request_
.relative_url
);
1358 // Even though the body is empty, the content type should be set to
1360 EXPECT_EQ("text/plain", http_request_
.headers
["Content-Type"]);
1361 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1362 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1363 http_request_
.headers
["X-Upload-Content-Length"]);
1364 // For updating an existing file, an empty body should be attached (PUT
1366 EXPECT_TRUE(http_request_
.has_content
);
1367 EXPECT_EQ("", http_request_
.content
);
1368 EXPECT_EQ(kTestETag
, http_request_
.headers
["If-Match"]);
1370 // 2) Upload the content to the upload URL.
1371 scoped_refptr
<net::IOBuffer
> buffer
= new net::StringIOBuffer(kUploadContent
);
1373 UploadRangeResponse response
;
1374 scoped_ptr
<ResourceEntry
> new_entry
;
1376 ResumeUploadOperation
* resume_operation
= new ResumeUploadOperation(
1377 &operation_registry_
,
1378 request_context_getter_
.get(),
1379 CreateComposedCallback(
1380 base::Bind(&test_util::RunAndQuit
),
1381 test_util::CreateCopyResultCallback(&response
, &new_entry
)),
1383 UPLOAD_EXISTING_FILE
,
1384 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1386 0, // start_position
1387 kUploadContent
.size(), // end_position (exclusive)
1388 kUploadContent
.size(), // content_length,
1389 "text/plain", // content_type
1392 resume_operation
->Start(
1393 kTestGDataAuthToken
, kTestUserAgent
,
1394 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1395 MessageLoop::current()->Run();
1397 // METHOD_PUT should be used to upload data.
1398 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1399 // Request should go to the upload URL.
1400 EXPECT_EQ(upload_url
.path(), http_request_
.relative_url
);
1401 // Content-Range header should be added.
1402 EXPECT_EQ("bytes 0-" +
1403 base::Int64ToString(kUploadContent
.size() -1) + "/" +
1404 base::Int64ToString(kUploadContent
.size()),
1405 http_request_
.headers
["Content-Range"]);
1406 // The upload content should be set in the HTTP request.
1407 EXPECT_TRUE(http_request_
.has_content
);
1408 EXPECT_EQ(kUploadContent
, http_request_
.content
);
1410 // Check the response.
1411 EXPECT_EQ(HTTP_SUCCESS
, response
.code
); // Because it's an existing file.
1412 // The start and end positions should be set to -1, if an upload is complete.
1413 EXPECT_EQ(-1, response
.start_position_received
);
1414 EXPECT_EQ(-1, response
.end_position_received
);
1417 // This test exercises InitiateUploadExistingFileOperation for a scenario of
1418 // confliction on updating an existing file.
1419 TEST_F(GDataWapiOperationsTest
, UploadExistingFileWithETagConflict
) {
1420 const std::string kUploadContent
= "hello";
1421 const std::string kWrongETag
= "wrong_etag";
1422 GDataErrorCode result_code
= GDATA_OTHER_ERROR
;
1425 InitiateUploadExistingFileOperation
* initiate_operation
=
1426 new InitiateUploadExistingFileOperation(
1427 &operation_registry_
,
1428 request_context_getter_
.get(),
1430 CreateComposedCallback(
1431 base::Bind(&test_util::RunAndQuit
),
1432 test_util::CreateCopyResultCallback(&result_code
, &upload_url
)),
1433 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1435 kUploadContent
.size(),
1439 initiate_operation
->Start(
1440 kTestGDataAuthToken
, kTestUserAgent
,
1441 base::Bind(&test_util::DoNothingForReAuthenticateCallback
));
1442 MessageLoop::current()->Run();
1444 EXPECT_EQ(HTTP_PRECONDITION
, result_code
);
1445 // For updating an existing file, METHOD_PUT should be used.
1446 EXPECT_EQ(test_server::METHOD_PUT
, http_request_
.method
);
1447 // convert=false should be passed as files should be uploaded as-is.
1448 EXPECT_EQ("/feeds/upload/create-session/default/private/full/file%3Afoo"
1449 "?convert=false&v=3&alt=json&showroot=true",
1450 http_request_
.relative_url
);
1451 // Even though the body is empty, the content type should be set to
1453 EXPECT_EQ("text/plain", http_request_
.headers
["Content-Type"]);
1454 EXPECT_EQ("text/plain", http_request_
.headers
["X-Upload-Content-Type"]);
1455 EXPECT_EQ(base::Int64ToString(kUploadContent
.size()),
1456 http_request_
.headers
["X-Upload-Content-Length"]);
1457 // For updating an existing file, an empty body should be attached (PUT
1459 EXPECT_TRUE(http_request_
.has_content
);
1460 EXPECT_EQ("", http_request_
.content
);
1461 EXPECT_EQ(kWrongETag
, http_request_
.headers
["If-Match"]);
1464 } // namespace google_apis