Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: chrome/browser/google_apis/gdata_wapi_operations_unittest.cc

Issue 11308315: google_apis: Add a test for uploading a large file (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/bind.h" 5 #include "base/bind.h"
6 #include "base/file_path.h" 6 #include "base/file_path.h"
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/json/json_reader.h" 8 #include "base/json/json_reader.h"
9 #include "base/message_loop_proxy.h" 9 #include "base/message_loop_proxy.h"
10 #include "base/string_number_conversions.h" 10 #include "base/string_number_conversions.h"
11 #include "base/string_split.h"
11 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
12 #include "chrome/browser/google_apis/gdata_wapi_operations.h" 13 #include "chrome/browser/google_apis/gdata_wapi_operations.h"
13 #include "chrome/browser/google_apis/gdata_wapi_parser.h" 14 #include "chrome/browser/google_apis/gdata_wapi_parser.h"
14 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h" 15 #include "chrome/browser/google_apis/gdata_wapi_url_generator.h"
15 #include "chrome/browser/google_apis/operation_registry.h" 16 #include "chrome/browser/google_apis/operation_registry.h"
16 #include "chrome/browser/google_apis/test_server/http_server.h" 17 #include "chrome/browser/google_apis/test_server/http_server.h"
17 #include "chrome/browser/google_apis/test_util.h" 18 #include "chrome/browser/google_apis/test_util.h"
18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/test/base/testing_browser_process.h" 20 #include "chrome/test/base/testing_browser_process.h"
20 #include "chrome/test/base/testing_profile.h" 21 #include "chrome/test/base/testing_profile.h"
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 bool RemovePrefix(const std::string& input, 125 bool RemovePrefix(const std::string& input,
125 const std::string& prefix, 126 const std::string& prefix,
126 std::string* output) { 127 std::string* output) {
127 if (!StartsWithASCII(input, prefix, true /* case sensitive */)) 128 if (!StartsWithASCII(input, prefix, true /* case sensitive */))
128 return false; 129 return false;
129 130
130 *output = input.substr(prefix.size()); 131 *output = input.substr(prefix.size());
131 return true; 132 return true;
132 } 133 }
133 134
135 // Parses a value of Content-Range header, which looks like
136 // "bytes <start_position>-<end_position>/<length>".
137 // Returns true on success.
138 bool ParseContentRangeHeader(const std::string& value,
139 int64* start_position,
140 int64* end_position,
141 int64* length) {
142 DCHECK(start_position);
143 DCHECK(end_position);
144 DCHECK(length);
145
146 std::string remaining;
147 if (!RemovePrefix(value, "bytes ", &remaining))
148 return false;
149
150 std::vector<std::string> parts;
151 base::SplitString(remaining, '/', &parts);
152 if (parts.size() != 2U)
153 return false;
154
155 const std::string range = parts[0];
156 if (!base::StringToInt64(parts[1], length))
157 return false;
158
159 parts.clear();
160 base::SplitString(range, '-', &parts);
161 if (parts.size() != 2U)
162 return false;
163
164 return (base::StringToInt64(parts[0], start_position) &&
165 base::StringToInt64(parts[1], end_position));
166 }
167
134 // This class sets a request context getter for testing in 168 // This class sets a request context getter for testing in
135 // |testing_browser_process| and then clears the state when an instance of it 169 // |testing_browser_process| and then clears the state when an instance of it
136 // goes out of scope. 170 // goes out of scope.
137 class ScopedRequestContextGetterForTesting { 171 class ScopedRequestContextGetterForTesting {
138 public: 172 public:
139 ScopedRequestContextGetterForTesting( 173 ScopedRequestContextGetterForTesting(
140 TestingBrowserProcess* testing_browser_process) 174 TestingBrowserProcess* testing_browser_process)
141 : testing_browser_process_(testing_browser_process) { 175 : testing_browser_process_(testing_browser_process) {
142 context_getter_ = new net::TestURLRequestContextGetter( 176 context_getter_ = new net::TestURLRequestContextGetter(
143 content::BrowserThread::GetMessageLoopProxyForThread( 177 content::BrowserThread::GetMessageLoopProxyForThread(
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 scoped_ptr<test_server::HttpResponse> HandleUploadRequest( 356 scoped_ptr<test_server::HttpResponse> HandleUploadRequest(
323 const test_server::HttpRequest& request) { 357 const test_server::HttpRequest& request) {
324 http_request_ = request; 358 http_request_ = request;
325 359
326 const GURL absolute_url = test_server_.GetURL(request.relative_url); 360 const GURL absolute_url = test_server_.GetURL(request.relative_url);
327 if (absolute_url.path() != "/upload_url") 361 if (absolute_url.path() != "/upload_url")
328 return scoped_ptr<test_server::HttpResponse>(); 362 return scoped_ptr<test_server::HttpResponse>();
329 363
330 // TODO(satorux): We should create a correct entry for the uploaded file, 364 // TODO(satorux): We should create a correct entry for the uploaded file,
331 // but for now, just return entry.xml. 365 // but for now, just return entry.xml.
332 return CreateHttpResponseFromFile( 366 scoped_ptr<test_server::HttpResponse> response =
333 test_util::GetTestFilePath("gdata/entry.xml")); 367 CreateHttpResponseFromFile(
368 test_util::GetTestFilePath("gdata/entry.xml"));
369
370 // Check if the Content-Range header is present. This must be present if
371 // the request body is not empty.
372 if (!request.content.empty()) {
373 std::map<std::string, std::string>::const_iterator iter =
374 request.headers.find("Content-Range");
375 if (iter == request.headers.end())
376 return scoped_ptr<test_server::HttpResponse>();
377 int64 start_position = 0;
378 int64 end_position = 0;
379 int64 length = 0;
380 if (!ParseContentRangeHeader(iter->second,
381 &start_position,
382 &end_position,
383 &length)) {
384 return scoped_ptr<test_server::HttpResponse>();
385 }
386
387 // Add Range header to the response, based on the values of
388 // Content-Range header in the request.
389 response->AddCustomHeader(
390 "Range",
391 "bytes=" +
392 base::Int64ToString(start_position) + "-" +
393 base::Int64ToString(end_position));
394
395 // Change the response code if this is not the end of an upload.
396 if (end_position + 1 < length)
397 response->set_code(test_server::RESUME_INCOMPLETE);
398 }
399
400 return response.Pass();
334 } 401 }
335 402
336 MessageLoopForUI message_loop_; 403 MessageLoopForUI message_loop_;
337 content::TestBrowserThread ui_thread_; 404 content::TestBrowserThread ui_thread_;
338 content::TestBrowserThread file_thread_; 405 content::TestBrowserThread file_thread_;
339 content::TestBrowserThread io_thread_; 406 content::TestBrowserThread io_thread_;
340 test_server::HttpServer test_server_; 407 test_server::HttpServer test_server_;
341 scoped_ptr<TestingProfile> profile_; 408 scoped_ptr<TestingProfile> profile_;
342 OperationRegistry operation_registry_; 409 OperationRegistry operation_registry_;
343 scoped_ptr<GDataWapiUrlGenerator> url_generator_; 410 scoped_ptr<GDataWapiUrlGenerator> url_generator_;
(...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after
855 new ResumeUploadOperation( 922 new ResumeUploadOperation(
856 &operation_registry_, 923 &operation_registry_,
857 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, 924 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit,
858 &response, 925 &response,
859 &new_entry), 926 &new_entry),
860 resume_params); 927 resume_params);
861 928
862 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); 929 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
863 MessageLoop::current()->Run(); 930 MessageLoop::current()->Run();
864 931
865 EXPECT_EQ(HTTP_SUCCESS, result_code);
866 // METHOD_PUT should be used to upload data. 932 // METHOD_PUT should be used to upload data.
867 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); 933 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
868 // Request should go to the upload URL. 934 // Request should go to the upload URL.
869 EXPECT_EQ(upload_url.path(), http_request_.relative_url); 935 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
870 // Content-Range header should be added. 936 // Content-Range header should be added.
871 EXPECT_EQ("bytes 0-" + 937 EXPECT_EQ("bytes 0-" +
872 base::Int64ToString(kUploadContent.size() -1) + "/" + 938 base::Int64ToString(kUploadContent.size() -1) + "/" +
873 base::Int64ToString(kUploadContent.size()), 939 base::Int64ToString(kUploadContent.size()),
874 http_request_.headers["Content-Range"]); 940 http_request_.headers["Content-Range"]);
875 // The upload content should be set in the HTTP request. 941 // The upload content should be set in the HTTP request.
876 EXPECT_TRUE(http_request_.has_content); 942 EXPECT_TRUE(http_request_.has_content);
877 EXPECT_EQ(kUploadContent, http_request_.content); 943 EXPECT_EQ(kUploadContent, http_request_.content);
944
945 // Check the response.
946 EXPECT_EQ(HTTP_SUCCESS, response.code);
947 // The start and end positions should be set to -1, if an upload is complete.
948 EXPECT_EQ(-1, response.start_range_received);
949 EXPECT_EQ(-1, response.end_range_received);
878 } 950 }
879 951
880 // This test exercises InitiateUploadOperation and ResumeUploadOperation for 952 // This test exercises InitiateUploadOperation and ResumeUploadOperation for
953 // a scenario of uploading a new *large* file, which requires mutiple requests
954 // of ResumeUploadOperation.
955 TEST_F(GDataWapiOperationsTest, UploadNewLargeFile) {
956 const size_t kMaxNumBytes = 10;
957 // This is big enough to cause multiple requests of ResumeUploadOperation
958 // as we are gonig to send at most kMaxNumBytes at a time.
959 const std::string kUploadContent(kMaxNumBytes + 1, 'a');
960 GDataErrorCode result_code = GDATA_OTHER_ERROR;
961 GURL upload_url;
962
963 // 1) Get the upload URL for uploading a new file.
964 InitiateUploadParams initiate_params(
965 UPLOAD_NEW_FILE,
966 "New file",
967 "text/plain",
968 kUploadContent.size(),
969 test_server_.GetURL("/feeds/upload/create-session/default/private/full"),
970 FilePath::FromUTF8Unsafe("drive/newfile.txt"));
971
972 InitiateUploadOperation* initiate_operation =
973 new InitiateUploadOperation(
974 &operation_registry_,
975 base::Bind(&CopyResultFromInitiateUploadCallbackAndQuit,
976 &result_code,
977 &upload_url),
978 initiate_params);
979
980 initiate_operation->Start(kTestGDataAuthToken, kTestUserAgent);
981 MessageLoop::current()->Run();
982
983 EXPECT_EQ(HTTP_SUCCESS, result_code);
984 EXPECT_EQ(test_server_.GetURL("/upload_url"), upload_url);
985 EXPECT_EQ(test_server::METHOD_POST, http_request_.method);
986 // convert=false should be passed as files should be uploaded as-is.
987 EXPECT_EQ("/feeds/upload/create-session/default/private/full?convert=false",
988 http_request_.relative_url);
989 EXPECT_EQ("text/plain", http_request_.headers["X-Upload-Content-Type"]);
990 EXPECT_EQ("application/atom+xml", http_request_.headers["Content-Type"]);
991 EXPECT_EQ(base::Int64ToString(kUploadContent.size()),
992 http_request_.headers["X-Upload-Content-Length"]);
993
994 EXPECT_TRUE(http_request_.has_content);
995 EXPECT_EQ("<?xml version=\"1.0\"?>\n"
996 "<entry xmlns=\"http://www.w3.org/2005/Atom\" "
997 "xmlns:docs=\"http://schemas.google.com/docs/2007\">\n"
998 " <title>New file</title>\n"
999 "</entry>\n",
1000 http_request_.content);
1001
1002 // 2) Upload the content to the upload URL with multiple requests.
1003 size_t num_bytes_consumed = 0;
1004 for (size_t start_position = 0; start_position < kUploadContent.size();
1005 start_position += kMaxNumBytes) {
1006 SCOPED_TRACE(testing::Message("start_position: ") << start_position);
1007
1008 // The payload is at most kMaxNumBytes.
1009 const size_t remaining_size = kUploadContent.size() - start_position;
1010 const std::string payload = kUploadContent.substr(
1011 start_position, std::min(kMaxNumBytes, remaining_size));
1012 num_bytes_consumed += payload.size();
1013 // The end position is inclusive, hence -1.
1014 const size_t end_position = start_position + payload.size() - 1;
1015
1016 scoped_refptr<net::IOBuffer> buffer = new net::StringIOBuffer(payload);
1017 ResumeUploadParams resume_params(
1018 UPLOAD_NEW_FILE,
1019 start_position, // start_range
1020 end_position, // end_range
1021 kUploadContent.size(), // content_length,
1022 "text/plain", // content_type
1023 buffer,
1024 upload_url,
1025 FilePath::FromUTF8Unsafe("drive/newfile.txt"));
1026
1027 ResumeUploadResponse response;
1028 scoped_ptr<DocumentEntry> new_entry;
1029
1030 ResumeUploadOperation* resume_operation =
1031 new ResumeUploadOperation(
1032 &operation_registry_,
1033 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit,
1034 &response,
1035 &new_entry),
1036 resume_params);
1037
1038 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
1039 MessageLoop::current()->Run();
1040
1041 // METHOD_PUT should be used to upload data.
1042 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
1043 // Request should go to the upload URL.
1044 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1045 // Content-Range header should be added.
1046 EXPECT_EQ("bytes " +
1047 base::Int64ToString(start_position) + "-" +
1048 base::Int64ToString(end_position) + "/" +
1049 base::Int64ToString(kUploadContent.size()),
1050 http_request_.headers["Content-Range"]);
1051 // The upload content should be set in the HTTP request.
1052 EXPECT_TRUE(http_request_.has_content);
1053 EXPECT_EQ(payload, http_request_.content);
1054
1055 // Check the response.
1056 if (payload.size() == remaining_size) {
1057 EXPECT_EQ(HTTP_SUCCESS, response.code);
kinaba 2012/12/03 04:37:57 The expected response code for UPLOAD_NEW_FILE mod
satorux1 2012/12/03 05:02:22 Good catch! Fixed!
1058 // The start and end positions should be set to -1, if an upload is
1059 // complete.
1060 EXPECT_EQ(-1, response.start_range_received);
1061 EXPECT_EQ(-1, response.end_range_received);
1062 } else {
1063 EXPECT_EQ(HTTP_RESUME_INCOMPLETE, response.code);
1064 EXPECT_EQ(static_cast<int64>(start_position),
1065 response.start_range_received);
1066 EXPECT_EQ(static_cast<int64>(end_position),
1067 response.end_range_received);
1068 }
1069 }
1070
1071 EXPECT_EQ(kUploadContent.size(), num_bytes_consumed);
1072 }
1073
1074 // This test exercises InitiateUploadOperation and ResumeUploadOperation for
881 // a scenario of uploading a new *empty* file. 1075 // a scenario of uploading a new *empty* file.
882 // 1076 //
883 // The test is almost identical to UploadNewFile. The only difference is the 1077 // The test is almost identical to UploadNewFile. The only difference is the
884 // expectation for the Content-Range header. 1078 // expectation for the Content-Range header.
885 TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) { 1079 TEST_F(GDataWapiOperationsTest, UploadNewEmptyFile) {
886 const std::string kUploadContent = ""; 1080 const std::string kUploadContent = "";
887 GDataErrorCode result_code = GDATA_OTHER_ERROR; 1081 GDataErrorCode result_code = GDATA_OTHER_ERROR;
888 GURL upload_url; 1082 GURL upload_url;
889 1083
890 // 1) Get the upload URL for uploading a new file. 1084 // 1) Get the upload URL for uploading a new file.
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
945 new ResumeUploadOperation( 1139 new ResumeUploadOperation(
946 &operation_registry_, 1140 &operation_registry_,
947 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, 1141 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit,
948 &response, 1142 &response,
949 &new_entry), 1143 &new_entry),
950 resume_params); 1144 resume_params);
951 1145
952 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); 1146 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
953 MessageLoop::current()->Run(); 1147 MessageLoop::current()->Run();
954 1148
955 EXPECT_EQ(HTTP_SUCCESS, result_code);
956 // METHOD_PUT should be used to upload data. 1149 // METHOD_PUT should be used to upload data.
957 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); 1150 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
958 // Request should go to the upload URL. 1151 // Request should go to the upload URL.
959 EXPECT_EQ(upload_url.path(), http_request_.relative_url); 1152 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
960 // Content-Range header should not exit if the content is empty. 1153 // Content-Range header should not exit if the content is empty.
961 // We should not generate the header with an invalid value "bytes 0--1/0". 1154 // We should not generate the header with an invalid value "bytes 0--1/0".
962 EXPECT_EQ(0U, http_request_.headers.count("Content-Range")); 1155 EXPECT_EQ(0U, http_request_.headers.count("Content-Range"));
963 // The upload content should be set in the HTTP request. 1156 // The upload content should be set in the HTTP request.
964 EXPECT_TRUE(http_request_.has_content); 1157 EXPECT_TRUE(http_request_.has_content);
965 EXPECT_EQ(kUploadContent, http_request_.content); 1158 EXPECT_EQ(kUploadContent, http_request_.content);
1159
1160 // Check the response.
1161 EXPECT_EQ(HTTP_SUCCESS, response.code);
1162 // The start and end positions should be set to -1, if an upload is complete.
1163 EXPECT_EQ(-1, response.start_range_received);
1164 EXPECT_EQ(-1, response.end_range_received);
966 } 1165 }
967 1166
968 // This test exercises InitiateUploadOperation and ResumeUploadOperation for 1167 // This test exercises InitiateUploadOperation and ResumeUploadOperation for
969 // a scenario of updating an existing file. 1168 // a scenario of updating an existing file.
970 TEST_F(GDataWapiOperationsTest, UploadExistingFile) { 1169 TEST_F(GDataWapiOperationsTest, UploadExistingFile) {
971 const std::string kUploadContent = "hello"; 1170 const std::string kUploadContent = "hello";
972 GDataErrorCode result_code = GDATA_OTHER_ERROR; 1171 GDataErrorCode result_code = GDATA_OTHER_ERROR;
973 GURL upload_url; 1172 GURL upload_url;
974 1173
975 // 1) Get the upload URL for uploading an existing file. 1174 // 1) Get the upload URL for uploading an existing file.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 new ResumeUploadOperation( 1230 new ResumeUploadOperation(
1032 &operation_registry_, 1231 &operation_registry_,
1033 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit, 1232 base::Bind(&CopyResultFromResumeUploadCallbackAndQuit,
1034 &response, 1233 &response,
1035 &new_entry), 1234 &new_entry),
1036 resume_params); 1235 resume_params);
1037 1236
1038 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent); 1237 resume_operation->Start(kTestGDataAuthToken, kTestUserAgent);
1039 MessageLoop::current()->Run(); 1238 MessageLoop::current()->Run();
1040 1239
1041 EXPECT_EQ(HTTP_SUCCESS, result_code);
1042 // METHOD_PUT should be used to upload data. 1240 // METHOD_PUT should be used to upload data.
1043 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method); 1241 EXPECT_EQ(test_server::METHOD_PUT, http_request_.method);
1044 // Request should go to the upload URL. 1242 // Request should go to the upload URL.
1045 EXPECT_EQ(upload_url.path(), http_request_.relative_url); 1243 EXPECT_EQ(upload_url.path(), http_request_.relative_url);
1046 // Content-Range header should be added. 1244 // Content-Range header should be added.
1047 EXPECT_EQ("bytes 0-" + 1245 EXPECT_EQ("bytes 0-" +
1048 base::Int64ToString(kUploadContent.size() -1) + "/" + 1246 base::Int64ToString(kUploadContent.size() -1) + "/" +
1049 base::Int64ToString(kUploadContent.size()), 1247 base::Int64ToString(kUploadContent.size()),
1050 http_request_.headers["Content-Range"]); 1248 http_request_.headers["Content-Range"]);
1051 // The upload content should be set in the HTTP request. 1249 // The upload content should be set in the HTTP request.
1052 EXPECT_TRUE(http_request_.has_content); 1250 EXPECT_TRUE(http_request_.has_content);
1053 EXPECT_EQ(kUploadContent, http_request_.content); 1251 EXPECT_EQ(kUploadContent, http_request_.content);
1252
1253 // Check the response.
1254 EXPECT_EQ(HTTP_SUCCESS, response.code);
1255 // The start and end positions should be set to -1, if an upload is complete.
1256 EXPECT_EQ(-1, response.start_range_received);
1257 EXPECT_EQ(-1, response.end_range_received);
1054 } 1258 }
1055 1259
1056 } // namespace google_apis 1260 } // namespace google_apis
OLDNEW
« no previous file with comments | « chrome/browser/google_apis/gdata_wapi_operations.h ('k') | chrome/browser/google_apis/test_server/http_response.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698