Fix build break
[chromium-blink-merge.git] / chrome / browser / google_apis / gdata_wapi_operations_unittest.cc
blob88f2027eb71af5ef8ccc6fb8905c8330ed153727
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.
5 #include <algorithm>
6 #include <map>
8 #include "base/bind.h"
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 {
35 namespace {
37 const char kTestGDataAuthToken[] = "testtoken";
38 const char kTestUserAgent[] = "test-user-agent";
39 const char kTestETag[] = "test_etag";
41 class GDataWapiOperationsTest : public testing::Test {
42 public:
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 {
50 file_thread_.Start();
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())));
79 received_bytes_ = 0;
80 content_length_ = 0;
83 virtual void TearDown() OVERRIDE {
84 test_server_.ShutdownAndWaitUntilComplete();
85 request_context_getter_ = NULL;
88 protected:
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",
107 &remaining_path)) {
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"));
115 } else {
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
135 // matter.
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") ==
166 string::npos) {
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.
178 std::string content;
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);
199 // Check an ETag.
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>();
216 received_bytes_ = 0;
218 http_response->set_code(test_server::SUCCESS);
219 GURL upload_url;
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");
225 } else {
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
252 // file.
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>();
263 int64 length = 0;
264 int64 start_position = 0;
265 int64 end_position = 0;
266 if (!test_util::ParseContentRangeHeader(iter->second,
267 &start_position,
268 &end_position,
269 &length)) {
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(
283 "Range",
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
308 // the WAPI server.
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
314 // instead of GET).
315 test_server::HttpRequest http_request_;
318 } // namespace
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(),
327 *url_generator_,
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(),
361 *url_generator_,
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(),
396 *url_generator_,
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(),
424 *url_generator_,
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"),
440 result_data.get()));
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(),
450 *url_generator_,
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"
462 "&showroot=true",
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(),
474 *url_generator_,
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(),
514 *url_generator_,
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(),
550 *url_generator_,
551 CreateComposedCallback(base::Bind(&test_util::RunAndQuit),
552 test_util::CreateCopyResultCallback(&result_code)),
553 "file:2_file_resource_id",
554 std::string());
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);
562 EXPECT_EQ(
563 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
564 "&showroot=true",
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(),
575 *url_generator_,
576 CreateComposedCallback(
577 base::Bind(&test_util::RunAndQuit),
578 test_util::CreateCopyResultCallback(&result_code)),
579 "file:2_file_resource_id",
580 "etag");
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);
588 EXPECT_EQ(
589 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
590 "&showroot=true",
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(),
603 *url_generator_,
604 CreateComposedCallback(
605 base::Bind(&test_util::RunAndQuit),
606 test_util::CreateCopyResultCallback(&result_code, &result_data)),
607 "folder:root",
608 "new directory");
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"
617 "&showroot=true",
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"
627 "</entry>\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(),
639 *url_generator_,
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
644 "New Document");
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"
661 "</entry>\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(),
672 *url_generator_,
673 CreateComposedCallback(
674 base::Bind(&test_util::RunAndQuit),
675 test_util::CreateCopyResultCallback(&result_code)),
676 "file:2_file_resource_id",
677 "New File");
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);
685 EXPECT_EQ(
686 "/feeds/default/private/full/file%3A2_file_resource_id?v=3&alt=json"
687 "&showroot=true",
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"
696 "</entry>\n",
697 http_request_.content);
700 TEST_F(GDataWapiOperationsTest, AuthorizeAppOperation_ValidFeed) {
701 GDataErrorCode result_code = GDATA_OTHER_ERROR;
702 GURL result_data;
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(),
708 *url_generator_,
709 CreateComposedCallback(
710 base::Bind(&test_util::RunAndQuit),
711 test_util::CreateCopyResultCallback(&result_code, &result_data)),
712 "file:2_file_resource_id",
713 "APP_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"
732 "</entry>\n",
733 http_request_.content);
736 TEST_F(GDataWapiOperationsTest, AuthorizeAppOperation_InvalidFeed) {
737 GDataErrorCode result_code = GDATA_OTHER_ERROR;
738 GURL result_data;
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(),
744 *url_generator_,
745 CreateComposedCallback(
746 base::Bind(&test_util::RunAndQuit),
747 test_util::CreateCopyResultCallback(&result_code, &result_data)),
748 "invalid_resource_id",
749 "APP_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"
768 "</entry>\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(),
780 *url_generator_,
781 CreateComposedCallback(
782 base::Bind(&test_util::RunAndQuit),
783 test_util::CreateCopyResultCallback(&result_code)),
784 "folder:root",
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"
794 "&showroot=true",
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"
803 "</entry>\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(),
815 *url_generator_,
816 CreateComposedCallback(
817 base::Bind(&test_util::RunAndQuit),
818 test_util::CreateCopyResultCallback(&result_code)),
819 "folder:root",
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;
841 GURL upload_url;
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(),
848 *url_generator_,
849 CreateComposedCallback(
850 base::Bind(&test_util::RunAndQuit),
851 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
852 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
853 "text/plain",
854 kUploadContent.size(),
855 "folder:id",
856 "New file");
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.
867 EXPECT_EQ(
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"
881 "</entry>\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)),
896 ProgressCallback(),
897 UPLOAD_NEW_FILE,
898 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
899 upload_url,
900 0, // start_position
901 kUploadContent.size(), // end_position (exclusive)
902 kUploadContent.size(), // content_length,
903 "text/plain", // content_type
904 buffer);
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
934 // test case.
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;
943 GURL upload_url;
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(),
950 *url_generator_,
951 CreateComposedCallback(
952 base::Bind(&test_util::RunAndQuit),
953 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
954 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
955 "text/plain",
956 kUploadContent.size(),
957 "folder:id",
958 "New file");
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.
969 EXPECT_EQ(
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"
983 "</entry>\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)),
1001 UPLOAD_NEW_FILE,
1002 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1003 upload_url,
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)),
1051 ProgressCallback(),
1052 UPLOAD_NEW_FILE,
1053 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1054 upload_url,
1055 start_position,
1056 end_position,
1057 kUploadContent.size(), // content_length,
1058 "text/plain", // content_type
1059 buffer);
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
1084 // complete.
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.
1088 break;
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)),
1104 UPLOAD_NEW_FILE,
1105 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1106 upload_url,
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;
1141 GURL upload_url;
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(),
1148 *url_generator_,
1149 CreateComposedCallback(
1150 base::Bind(&test_util::RunAndQuit),
1151 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1152 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1153 "text/plain",
1154 kUploadContent.size(),
1155 "folder:id",
1156 "New file");
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.
1167 EXPECT_EQ(
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"
1181 "</entry>\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)),
1196 ProgressCallback(),
1197 UPLOAD_NEW_FILE,
1198 base::FilePath::FromUTF8Unsafe("drive/newfile.txt"),
1199 upload_url,
1200 0, // start_position
1201 kUploadContent.size(), // end_position (exclusive)
1202 kUploadContent.size(), // content_length,
1203 "text/plain", // content_type
1204 buffer);
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;
1234 GURL upload_url;
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(),
1241 *url_generator_,
1242 CreateComposedCallback(
1243 base::Bind(&test_util::RunAndQuit),
1244 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1245 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1246 "text/plain",
1247 kUploadContent.size(),
1248 "file:foo",
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
1265 // "text/plain".
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
1271 // requires a body)
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)),
1288 ProgressCallback(),
1289 UPLOAD_EXISTING_FILE,
1290 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1291 upload_url,
1292 0, // start_position
1293 kUploadContent.size(), // end_position (exclusive)
1294 kUploadContent.size(), // content_length,
1295 "text/plain", // content_type
1296 buffer);
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;
1328 GURL upload_url;
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(),
1335 *url_generator_,
1336 CreateComposedCallback(
1337 base::Bind(&test_util::RunAndQuit),
1338 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1339 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1340 "text/plain",
1341 kUploadContent.size(),
1342 "file:foo",
1343 kTestETag);
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
1359 // "text/plain".
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
1365 // requires a body)
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)),
1382 ProgressCallback(),
1383 UPLOAD_EXISTING_FILE,
1384 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1385 upload_url,
1386 0, // start_position
1387 kUploadContent.size(), // end_position (exclusive)
1388 kUploadContent.size(), // content_length,
1389 "text/plain", // content_type
1390 buffer);
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;
1423 GURL upload_url;
1425 InitiateUploadExistingFileOperation* initiate_operation =
1426 new InitiateUploadExistingFileOperation(
1427 &operation_registry_,
1428 request_context_getter_.get(),
1429 *url_generator_,
1430 CreateComposedCallback(
1431 base::Bind(&test_util::RunAndQuit),
1432 test_util::CreateCopyResultCallback(&result_code, &upload_url)),
1433 base::FilePath::FromUTF8Unsafe("drive/existingfile.txt"),
1434 "text/plain",
1435 kUploadContent.size(),
1436 "file:foo",
1437 kWrongETag);
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
1452 // "text/plain".
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
1458 // requires a body)
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