// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "google_apis/drive/base_requests.h" #include "base/bind.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/values.h" #include "google_apis/drive/drive_api_parser.h" #include "google_apis/drive/dummy_auth_service.h" #include "google_apis/drive/request_sender.h" #include "google_apis/drive/test_util.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace google_apis { namespace { const char kValidJsonString[] = "{ \"test\": 123 }"; const char kInvalidJsonString[] = "$$$"; class FakeUrlFetchRequest : public UrlFetchRequestBase { public: FakeUrlFetchRequest(RequestSender* sender, const EntryActionCallback& callback, const GURL& url) : UrlFetchRequestBase(sender), callback_(callback), url_(url) { } ~FakeUrlFetchRequest() override {} protected: GURL GetURL() const override { return url_; } void ProcessURLFetchResults(const net::URLFetcher* source) override { callback_.Run(GetErrorCode()); } void RunCallbackOnPrematureFailure(GDataErrorCode code) override { callback_.Run(code); } EntryActionCallback callback_; GURL url_; }; class FakeMultipartUploadRequest : public MultipartUploadRequestBase { public: FakeMultipartUploadRequest( RequestSender* sender, const std::string& title, const std::string& parent_resource_id, const std::string& content_type, int64 content_length, const base::Time& modified_date, const base::Time& last_viewed_by_me_date, const base::FilePath& local_file_path, const FileResourceCallback& callback, const google_apis::ProgressCallback& progress_callback, const GURL& url, std::string* upload_content_type, std::string* upload_content_data) : MultipartUploadRequestBase(sender, title, parent_resource_id, content_type, content_length, modified_date, last_viewed_by_me_date, local_file_path, callback, progress_callback), url_(url), upload_content_type_(upload_content_type), upload_content_data_(upload_content_data) {} ~FakeMultipartUploadRequest() override {} bool GetContentData(std::string* content_type, std::string* content_data) override { const bool result = MultipartUploadRequestBase::GetContentData(content_type, content_data); *upload_content_type_ = *content_type; *upload_content_data_ = *content_data; return result; } base::SequencedTaskRunner* blocking_task_runner() const { return MultipartUploadRequestBase::blocking_task_runner(); } protected: GURL GetURL() const override { return url_; } private: const GURL url_; std::string* const upload_content_type_; std::string* const upload_content_data_; }; } // namespace class BaseRequestsTest : public testing::Test { public: BaseRequestsTest() : response_code_(net::HTTP_OK) {} void SetUp() override { request_context_getter_ = new net::TestURLRequestContextGetter( message_loop_.message_loop_proxy()); sender_.reset(new RequestSender(new DummyAuthService, request_context_getter_.get(), message_loop_.message_loop_proxy(), std::string() /* custom user agent */)); ASSERT_TRUE(test_server_.InitializeAndWaitUntilReady()); test_server_.RegisterRequestHandler( base::Bind(&BaseRequestsTest::HandleRequest, base::Unretained(this))); } scoped_ptr HandleRequest( const net::test_server::HttpRequest& request) { scoped_ptr response( new net::test_server::BasicHttpResponse); response->set_code(response_code_); response->set_content(response_body_); response->set_content_type("application/json"); return response.Pass(); } base::MessageLoopForIO message_loop_; scoped_refptr request_context_getter_; scoped_ptr sender_; net::test_server::EmbeddedTestServer test_server_; net::HttpStatusCode response_code_; std::string response_body_; }; typedef BaseRequestsTest MultipartUploadRequestBaseTest; TEST_F(BaseRequestsTest, ParseValidJson) { scoped_ptr json(ParseJson(kValidJsonString)); base::DictionaryValue* root_dict = NULL; ASSERT_TRUE(json); ASSERT_TRUE(json->GetAsDictionary(&root_dict)); int int_value = 0; ASSERT_TRUE(root_dict->GetInteger("test", &int_value)); EXPECT_EQ(123, int_value); } TEST_F(BaseRequestsTest, ParseInvalidJson) { EXPECT_FALSE(ParseJson(kInvalidJsonString)); } TEST_F(BaseRequestsTest, UrlFetchRequestBaseResponseCodeOverride) { response_code_ = net::HTTP_FORBIDDEN; response_body_ = "{\"error\": {\n" " \"errors\": [\n" " {\n" " \"domain\": \"usageLimits\",\n" " \"reason\": \"rateLimitExceeded\",\n" " \"message\": \"Rate Limit Exceeded\"\n" " }\n" " ],\n" " \"code\": 403,\n" " \"message\": \"Rate Limit Exceeded\"\n" " }\n" "}\n"; GDataErrorCode error = GDATA_OTHER_ERROR; base::RunLoop run_loop; sender_->StartRequestWithRetry( new FakeUrlFetchRequest( sender_.get(), test_util::CreateQuitCallback( &run_loop, test_util::CreateCopyResultCallback(&error)), test_server_.base_url())); run_loop.Run(); // HTTP_FORBIDDEN (403) is overridden by the error reason. EXPECT_EQ(HTTP_SERVICE_UNAVAILABLE, error); } TEST_F(MultipartUploadRequestBaseTest, Basic) { response_code_ = net::HTTP_OK; response_body_ = "{\"kind\": \"drive#file\", \"id\": \"file_id\"}"; scoped_ptr file; GDataErrorCode error = GDATA_OTHER_ERROR; base::RunLoop run_loop; const base::FilePath source_path = google_apis::test_util::GetTestFilePath("chromeos/file_manager/text.txt"); std::string upload_content_type; std::string upload_content_data; scoped_ptr request(new FakeMultipartUploadRequest( sender_.get(), "test.txt", "parent_id", "text/plain", 10, base::Time(), base::Time(), source_path, test_util::CreateQuitCallback( &run_loop, test_util::CreateCopyResultCallback(&error, &file)), ProgressCallback(), test_server_.base_url(), &upload_content_type, &upload_content_data)); request->SetBoundaryForTesting("TESTBOUNDARY"); sender_->StartRequestWithRetry(request.release()); run_loop.Run(); EXPECT_EQ("multipart/related; boundary=TESTBOUNDARY", upload_content_type); EXPECT_EQ( "--TESTBOUNDARY\n" "Content-Type: application/json\n" "\n" "{\"parents\":[{\"id\":\"parent_id\",\"kind\":\"drive#fileLink\"}]," "\"title\":\"test.txt\"}\n" "--TESTBOUNDARY\n" "Content-Type: text/plain\n" "\n" "This is a sample file. I like chocolate and chips.\n" "\n" "--TESTBOUNDARY--", upload_content_data); ASSERT_EQ(HTTP_SUCCESS, error); EXPECT_EQ("file_id", file->file_id()); } } // Namespace google_apis