| Index: chrome/browser/google_apis/gdata_wapi_operations_unittest.cc
|
| diff --git a/chrome/browser/google_apis/gdata_wapi_operations_unittest.cc b/chrome/browser/google_apis/gdata_wapi_operations_unittest.cc
|
| index cb98d4efaa6d7b1aef957e21dce106fbc58214f3..f25a79daa629eaadae0c5389c95d9549f8cbda6e 100644
|
| --- a/chrome/browser/google_apis/gdata_wapi_operations_unittest.cc
|
| +++ b/chrome/browser/google_apis/gdata_wapi_operations_unittest.cc
|
| @@ -8,6 +8,7 @@
|
| #include "base/json/json_reader.h"
|
| #include "base/message_loop_proxy.h"
|
| #include "base/string_number_conversions.h"
|
| +#include "base/string_split.h"
|
| #include "base/stringprintf.h"
|
| #include "chrome/browser/google_apis/gdata_wapi_operations.h"
|
| #include "chrome/browser/google_apis/gdata_wapi_parser.h"
|
| @@ -131,6 +132,39 @@ bool RemovePrefix(const std::string& input,
|
| return true;
|
| }
|
|
|
| +// Parses a value of Content-Range header, which looks like
|
| +// "bytes <start_position>-<end_position>/<length>".
|
| +// Returns true on success.
|
| +bool ParseContentRangeHeader(const std::string& value,
|
| + int64* start_position,
|
| + int64* end_position,
|
| + int64* length) {
|
| + DCHECK(start_position);
|
| + DCHECK(end_position);
|
| + DCHECK(length);
|
| +
|
| + std::string remaining;
|
| + if (!RemovePrefix(value, "bytes ", &remaining))
|
| + return false;
|
| +
|
| + std::vector<std::string> parts;
|
| + base::SplitString(remaining, '/', &parts);
|
| + if (parts.size() != 2U)
|
| + return false;
|
| +
|
| + const std::string range = parts[0];
|
| + if (!base::StringToInt64(parts[1], length))
|
| + return false;
|
| +
|
| + parts.clear();
|
| + base::SplitString(range, '-', &parts);
|
| + if (parts.size() != 2U)
|
| + return false;
|
| +
|
| + return (base::StringToInt64(parts[0], start_position) &&
|
| + base::StringToInt64(parts[1], end_position));
|
| +}
|
| +
|
| // This class sets a request context getter for testing in
|
| // |testing_browser_process| and then clears the state when an instance of it
|
| // goes out of scope.
|
| @@ -310,8 +344,16 @@ class GDataWapiOperationsTest : public testing::Test {
|
| scoped_ptr<test_server::HttpResponse> http_response(
|
| new test_server::HttpResponse);
|
| http_response->set_code(test_server::SUCCESS);
|
| - http_response->AddCustomHeader("Location",
|
| - test_server_.GetURL("/upload_url").spec());
|
| + GURL upload_url;
|
| + // POST is used for a new file, and PUT is used for an existing file.
|
| + if (request.method == test_server::METHOD_POST) {
|
| + upload_url = test_server_.GetURL("/upload_new_file");
|
| + } else if (request.method == test_server::METHOD_PUT) {
|
| + upload_url = test_server_.GetURL("/upload_existing_file");
|
| + } else {
|
| + return scoped_ptr<test_server::HttpResponse>();
|
| + }
|
| + http_response->AddCustomHeader("Location", upload_url.spec());
|
| return http_response.Pass();
|
| }
|
|
|
| @@ -324,13 +366,52 @@ class GDataWapiOperationsTest : public testing::Test {
|
| http_request_ = request;
|
|
|
| const GURL absolute_url = test_server_.GetURL(request.relative_url);
|
| - if (absolute_url.path() != "/upload_url")
|
| + if (absolute_url.path() != "/upload_new_file" &&
|
| + absolute_url.path() != "/upload_existing_file") {
|
| return scoped_ptr<test_server::HttpResponse>();
|
| + }
|
|
|
| // TODO(satorux): We should create a correct entry for the uploaded file,
|
| // but for now, just return entry.xml.
|
| - return CreateHttpResponseFromFile(
|
| - test_util::GetTestFilePath("gdata/entry.xml"));
|
| + scoped_ptr<test_server::HttpResponse> response =
|
| + CreateHttpResponseFromFile(
|
| + test_util::GetTestFilePath("gdata/entry.xml"));
|
| + // response.code() is set to SUCCESS. Change it to CREATED if it's a new
|
| + // file.
|
| + if (absolute_url.path() == "/upload_new_file")
|
| + response->set_code(test_server::CREATED);
|
| +
|
| + // Check if the Content-Range header is present. This must be present if
|
| + // the request body is not empty.
|
| + if (!request.content.empty()) {
|
| + std::map<std::string, std::string>::const_iterator iter =
|
| + request.headers.find("Content-Range");
|
| + if (iter == request.headers.end())
|
| + return scoped_ptr<test_server::HttpResponse>();
|
| + int64 start_position = 0;
|
| + int64 end_position = 0;
|
| + int64 length = 0;
|
| + if (!ParseContentRangeHeader(iter->second,
|
| + &start_position,
|
| + &end_position,
|
| + &length)) {
|
| + return scoped_ptr<test_server::HttpResponse>();
|
| + }
|
| +
|
| + // Add Range header to the response, based on the values of
|
| + // Content-Range header in the request.
|
| + response->AddCustomHeader(
|
| + "Range",
|
| + "bytes=" +
|
| + base::Int64ToString(start_position) + "-" +
|
| + base::Int64ToString(end_position));
|
| +
|
| + // Change the code to RESUME_INCOMPLETE if upload is not complete.
|
| + if (end_position + 1 < length)
|
| + response->set_code(test_server::RESUME_INCOMPLETE);
|
| + }
|
| +
|
| + return response.Pass();
|
| }
|
|
|
| MessageLoopForUI message_loop_;
|
| @@ -818,7 +899,7 @@ TEST_F(GDataWapiOperationsTest, UploadNewFile) {
|
| MessageLoop::current()->Run();
|
|
|
| EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| - EXPECT_EQ(test_server_.GetURL("/upload_url"), upload_url);
|
| + EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
|
| EXPECT_EQ(test_server::METHOD_POST, http_request_.method);
|
| // convert=false should be passed as files should be uploaded as-is.
|
| EXPECT_EQ("/feeds/upload/create-session/default/private/full?convert=false",
|
| @@ -862,7 +943,6 @@ TEST_F(GDataWapiOperationsTest, UploadNewFile) {
|
| resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
|
| MessageLoop::current()->Run();
|
|
|
| - EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| // METHOD_PUT should be used to upload data.
|
| EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
|
| // Request should go to the upload URL.
|
| @@ -875,6 +955,134 @@ TEST_F(GDataWapiOperationsTest, UploadNewFile) {
|
| // The upload content should be set in the HTTP request.
|
| EXPECT_TRUE(http_request_.has_content);
|
| EXPECT_EQ(kUploadContent, http_request_.content);
|
| +
|
| + // Check the response.
|
| + EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file
|
| + // The start and end positions should be set to -1, if an upload is complete.
|
| + EXPECT_EQ(-1, response.start_range_received);
|
| + EXPECT_EQ(-1, response.end_range_received);
|
| +}
|
| +
|
| +// This test exercises InitiateUploadOperation and ResumeUploadOperation for
|
| +// a scenario of uploading a new *large* file, which requires mutiple requests
|
| +// of ResumeUploadOperation.
|
| +TEST_F(GDataWapiOperationsTest, UploadNewLargeFile) {
|
| + const size_t kMaxNumBytes = 10;
|
| + // This is big enough to cause multiple requests of ResumeUploadOperation
|
| + // as we are gonig to send at most kMaxNumBytes at a time.
|
| + const std::string kUploadContent(kMaxNumBytes + 1, 'a');
|
| + GDataErrorCode result_code = GDATA_OTHER_ERROR;
|
| + GURL upload_url;
|
| +
|
| + // 1) Get the upload URL for uploading a new file.
|
| + InitiateUploadParams initiate_params(
|
| + UPLOAD_NEW_FILE,
|
| + "New file",
|
| + "text/plain",
|
| + kUploadContent.size(),
|
| + test_server_.GetURL("/feeds/upload/create-session/default/private/full"),
|
| + FilePath::FromUTF8Unsafe("drive/newfile.txt"));
|
| +
|
| + InitiateUploadOperation* initiate_operation =
|
| + new InitiateUploadOperation(
|
| + &operation_registry_,
|
| + base::Bind(&CopyResultFromInitiateUploadCallbackAndQuit,
|
| + &result_code,
|
| + &upload_url),
|
| + initiate_params);
|
| +
|
| + initiate_operation->Start(kTestGDataAuthToken, kTestUserAgent);
|
| + MessageLoop::current()->Run();
|
| +
|
| + EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| + EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
|
| + EXPECT_EQ(test_server::METHOD_POST, http_request_.method);
|
| + // convert=false should be passed as files should be uploaded as-is.
|
| + EXPECT_EQ("/feeds/upload/create-session/default/private/full?convert=false",
|
| + http_request_.relative_url);
|
| + EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
|
| + EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
|
| + EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
|
| + http_request_.headers["X-Upload-Content-Length"]);
|
| +
|
| + EXPECT_TRUE(http_request_.has_content);
|
| + EXPECT_EQ("<?xml version=\"1.0\"?>\n"
|
| + "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
|
| + "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
|
| + " <title>New file</title>\n"
|
| + "</entry>\n",
|
| + http_request_.content);
|
| +
|
| + // 2) Upload the content to the upload URL with multiple requests.
|
| + size_t num_bytes_consumed = 0;
|
| + for (size_t start_position = 0; start_position < kUploadContent.size();
|
| + start_position += kMaxNumBytes) {
|
| + SCOPED_TRACE(testing::Message("start_position: ") << start_position);
|
| +
|
| + // The payload is at most kMaxNumBytes.
|
| + const size_t remaining_size = kUploadContent.size() - start_position;
|
| + const std::string payload = kUploadContent.substr(
|
| + start_position, std::min(kMaxNumBytes, remaining_size));
|
| + num_bytes_consumed += payload.size();
|
| + // The end position is inclusive, hence -1.
|
| + const size_t end_position = start_position + payload.size() - 1;
|
| +
|
| + scoped_refptr<net::IOBuffer> buffer = new net::StringIOBuffer(payload);
|
| + ResumeUploadParams resume_params(
|
| + UPLOAD_NEW_FILE,
|
| + start_position, // start_range
|
| + end_position, // end_range
|
| + kUploadContent.size(), // content_length,
|
| + "text/plain", // content_type
|
| + buffer,
|
| + upload_url,
|
| + FilePath::FromUTF8Unsafe("drive/newfile.txt"));
|
| +
|
| + ResumeUploadResponse response;
|
| + scoped_ptr<DocumentEntry> new_entry;
|
| +
|
| + ResumeUploadOperation* resume_operation =
|
| + new ResumeUploadOperation(
|
| + &operation_registry_,
|
| + base::Bind(&CopyResultFromResumeUploadCallbackAndQuit,
|
| + &response,
|
| + &new_entry),
|
| + resume_params);
|
| +
|
| + resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
|
| + MessageLoop::current()->Run();
|
| +
|
| + // METHOD_PUT should be used to upload data.
|
| + EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
|
| + // Request should go to the upload URL.
|
| + EXPECT_EQ(upload_url.path(), http_request_.relative_url);
|
| + // Content-Range header should be added.
|
| + EXPECT_EQ("bytes " +
|
| + base::Int64ToString(start_position) + "-" +
|
| + base::Int64ToString(end_position) + "/" +
|
| + base::Int64ToString(kUploadContent.size()),
|
| + http_request_.headers["Content-Range"]);
|
| + // The upload content should be set in the HTTP request.
|
| + EXPECT_TRUE(http_request_.has_content);
|
| + EXPECT_EQ(payload, http_request_.content);
|
| +
|
| + // Check the response.
|
| + if (payload.size() == remaining_size) {
|
| + EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file.
|
| + // The start and end positions should be set to -1, if an upload is
|
| + // complete.
|
| + EXPECT_EQ(-1, response.start_range_received);
|
| + EXPECT_EQ(-1, response.end_range_received);
|
| + } else {
|
| + EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
|
| + EXPECT_EQ(static_cast<int64>(start_position),
|
| + response.start_range_received);
|
| + EXPECT_EQ(static_cast<int64>(end_position),
|
| + response.end_range_received);
|
| + }
|
| + }
|
| +
|
| + EXPECT_EQ(kUploadContent.size(), num_bytes_consumed);
|
| }
|
|
|
| // This test exercises InitiateUploadOperation and ResumeUploadOperation for
|
| @@ -908,7 +1116,7 @@ TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) {
|
| MessageLoop::current()->Run();
|
|
|
| EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| - EXPECT_EQ(test_server_.GetURL("/upload_url"), upload_url);
|
| + EXPECT_EQ(test_server_.GetURL("/upload_new_file"), upload_url);
|
| EXPECT_EQ(test_server::METHOD_POST, http_request_.method);
|
| // convert=false should be passed as files should be uploaded as-is.
|
| EXPECT_EQ("/feeds/upload/create-session/default/private/full?convert=false",
|
| @@ -952,7 +1160,6 @@ TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) {
|
| resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
|
| MessageLoop::current()->Run();
|
|
|
| - EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| // METHOD_PUT should be used to upload data.
|
| EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
|
| // Request should go to the upload URL.
|
| @@ -963,6 +1170,12 @@ TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) {
|
| // The upload content should be set in the HTTP request.
|
| EXPECT_TRUE(http_request_.has_content);
|
| EXPECT_EQ(kUploadContent, http_request_.content);
|
| +
|
| + // Check the response.
|
| + EXPECT_EQ(HTTP_CREATED, response.code); // Because it's a new file.
|
| + // The start and end positions should be set to -1, if an upload is complete.
|
| + EXPECT_EQ(-1, response.start_range_received);
|
| + EXPECT_EQ(-1, response.end_range_received);
|
| }
|
|
|
| // This test exercises InitiateUploadOperation and ResumeUploadOperation for
|
| @@ -994,7 +1207,7 @@ TEST_F(GDataWapiOperationsTest, UploadExistingFile) {
|
| MessageLoop::current()->Run();
|
|
|
| EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| - EXPECT_EQ(test_server_.GetURL("/upload_url"), upload_url);
|
| + EXPECT_EQ(test_server_.GetURL("/upload_existing_file"), upload_url);
|
| // For updating an existing file, METHOD_PUT should be used.
|
| EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
|
| // convert=false should be passed as files should be uploaded as-is.
|
| @@ -1038,7 +1251,6 @@ TEST_F(GDataWapiOperationsTest, UploadExistingFile) {
|
| resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
|
| MessageLoop::current()->Run();
|
|
|
| - EXPECT_EQ(HTTP_SUCCESS, result_code);
|
| // METHOD_PUT should be used to upload data.
|
| EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
|
| // Request should go to the upload URL.
|
| @@ -1051,6 +1263,12 @@ TEST_F(GDataWapiOperationsTest, UploadExistingFile) {
|
| // The upload content should be set in the HTTP request.
|
| EXPECT_TRUE(http_request_.has_content);
|
| EXPECT_EQ(kUploadContent, http_request_.content);
|
| +
|
| + // Check the response.
|
| + EXPECT_EQ(HTTP_SUCCESS, response.code); // Because it's an existing file.
|
| + // The start and end positions should be set to -1, if an upload is complete.
|
| + EXPECT_EQ(-1, response.start_range_received);
|
| + EXPECT_EQ(-1, response.end_range_received);
|
| }
|
|
|
| } // namespace google_apis
|
|
|