Chromium Code Reviews| Index: content/browser/loader/resource_loader_unittest.cc |
| diff --git a/content/browser/loader/resource_loader_unittest.cc b/content/browser/loader/resource_loader_unittest.cc |
| index 8f962118a79976833f6a2ce31c8aadfc8d28b232..555cfdc4cba19baf0c603006978ab051f0fcf6b3 100644 |
| --- a/content/browser/loader/resource_loader_unittest.cc |
| +++ b/content/browser/loader/resource_loader_unittest.cc |
| @@ -4,20 +4,31 @@ |
| #include "content/browser/loader/resource_loader.h" |
| +#include "base/file_util.h" |
| +#include "base/message_loop/message_loop_proxy.h" |
| +#include "base/platform_file.h" |
| #include "base/run_loop.h" |
| #include "content/browser/browser_thread_impl.h" |
| +#include "content/browser/loader/redirect_to_file_resource_handler.h" |
| #include "content/browser/loader/resource_loader_delegate.h" |
| #include "content/public/browser/resource_request_info.h" |
| +#include "content/public/common/resource_response.h" |
| #include "content/public/test/mock_resource_context.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "content/test/test_content_browser_client.h" |
| +#include "net/base/mock_file_stream.h" |
| #include "net/base/request_priority.h" |
| #include "net/cert/x509_certificate.h" |
| #include "net/ssl/client_cert_store.h" |
| #include "net/ssl/ssl_cert_request_info.h" |
| #include "net/url_request/url_request.h" |
| +#include "net/url_request/url_request_job_factory_impl.h" |
| +#include "net/url_request/url_request_test_job.h" |
| #include "net/url_request/url_request_test_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| +#include "webkit/common/blob/shareable_file_reference.h" |
| + |
| +using webkit_blob::ShareableFileReference; |
| namespace content { |
| namespace { |
| @@ -68,11 +79,32 @@ class ClientCertStoreStub : public net::ClientCertStore { |
| // initialize ResourceLoader. |
| class ResourceHandlerStub : public ResourceHandler { |
| public: |
| - ResourceHandlerStub() : ResourceHandler(NULL) {} |
| + explicit ResourceHandlerStub(net::URLRequest* request) |
| + : ResourceHandler(request), |
| + defer_start_(false), |
| + received_response_completed_(false), |
| + total_bytes_downloaded_(0) { |
| + } |
| + |
| + void set_defer_start(bool defer_start) { defer_start_ = defer_start; } |
| + |
| + const GURL& start_url() const { return start_url_; } |
| + ResourceResponse* response() const { return response_.get(); } |
| + bool received_response_completed() const { |
| + return received_response_completed_; |
| + } |
| + const net::URLRequestStatus& status() const { return status_; } |
| + int total_bytes_downloaded() const { return total_bytes_downloaded_; } |
| + void Resume() { |
| + controller()->Resume(); |
| + } |
| + |
| + // ResourceHandler implementation: |
| virtual bool OnUploadProgress(int request_id, |
| uint64 position, |
| uint64 size) OVERRIDE { |
| + NOTREACHED(); |
| return true; |
| } |
| @@ -80,16 +112,24 @@ class ResourceHandlerStub : public ResourceHandler { |
| const GURL& url, |
| ResourceResponse* response, |
| bool* defer) OVERRIDE { |
| + NOTREACHED(); |
| return true; |
| } |
| virtual bool OnResponseStarted(int request_id, |
| ResourceResponse* response, |
| - bool* defer) OVERRIDE { return true; } |
| + bool* defer) OVERRIDE { |
| + EXPECT_FALSE(response_); |
| + response_ = response; |
| + return true; |
| + } |
| virtual bool OnWillStart(int request_id, |
| const GURL& url, |
| bool* defer) OVERRIDE { |
| + EXPECT_TRUE(start_url_.is_empty()); |
| + start_url_ = url; |
| + *defer = defer_start_; |
| return true; |
| } |
| @@ -97,23 +137,40 @@ class ResourceHandlerStub : public ResourceHandler { |
| scoped_refptr<net::IOBuffer>* buf, |
| int* buf_size, |
| int min_size) OVERRIDE { |
| - return true; |
| + NOTREACHED(); |
| + return false; |
| } |
| virtual bool OnReadCompleted(int request_id, |
| int bytes_read, |
| bool* defer) OVERRIDE { |
| - return true; |
| + NOTREACHED(); |
| + return false; |
| } |
| virtual void OnResponseCompleted(int request_id, |
| const net::URLRequestStatus& status, |
| const std::string& security_info, |
| bool* defer) OVERRIDE { |
| + // TODO(davidben): This DCHECK currently fires everywhere. Fix the places in |
| + // ResourceLoader where OnResponseCompleted is signaled twice. |
| + // DCHECK(!received_response_completed_); |
| + received_response_completed_ = true; |
| + status_ = status; |
| } |
| virtual void OnDataDownloaded(int request_id, |
| - int bytes_downloaded) OVERRIDE {} |
| + int bytes_downloaded) OVERRIDE { |
| + total_bytes_downloaded_ += bytes_downloaded; |
| + } |
| + |
| + private: |
| + bool defer_start_; |
| + GURL start_url_; |
| + scoped_refptr<ResourceResponse> response_; |
| + bool received_response_completed_; |
| + net::URLRequestStatus status_; |
| + int total_bytes_downloaded_; |
| }; |
| // Test browser client that captures calls to SelectClientCertificates and |
| @@ -162,6 +219,86 @@ class ResourceContextStub : public MockResourceContext { |
| scoped_ptr<net::ClientCertStore> dummy_cert_store_; |
| }; |
| +class MockTemporaryFileManager |
| + : public RedirectToFileResourceHandler::Delegate { |
| + public: |
| + MockTemporaryFileManager() : error_(base::PLATFORM_FILE_OK) { |
| + CreateNextTemporary(); |
| + } |
| + |
| + net::testing::MockFileStream* next_file_stream() const { |
| + return next_file_stream_.get(); |
| + } |
| + ShareableFileReference* next_deletable_file() const { |
| + return next_deletable_file_.get(); |
| + } |
| + |
| + void set_next_error(base::PlatformFileError error) { |
| + DCHECK_EQ(base::PLATFORM_FILE_OK, error_); |
| + error_ = error; |
| + } |
| + |
| + // RedirectToFileResourceHandler::Delegate implementation: |
| + virtual void CreateTemporary( |
| + int child_id, |
| + int request_id, |
| + base::WeakPtr<RedirectToFileResourceHandler> handler) OVERRIDE { |
| + base::MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&MockTemporaryFileManager::DoCallback, |
| + base::Unretained(this), handler)); |
| + } |
| + |
| + private: |
| + void CreateNextTemporary() { |
| + DCHECK(!next_file_stream_); |
| + |
| + base::FilePath file_path; |
| + ASSERT_TRUE(base::CreateTemporaryFile(&file_path)); |
| + base::PlatformFile platform_file = |
| + base::CreatePlatformFile(file_path, |
| + base::PLATFORM_FILE_WRITE | |
| + base::PLATFORM_FILE_TEMPORARY | |
| + base::PLATFORM_FILE_CREATE_ALWAYS | |
| + base::PLATFORM_FILE_ASYNC, |
| + NULL, NULL); |
| + ASSERT_NE(base::kInvalidPlatformFileValue, platform_file); |
| + next_file_stream_.reset( |
| + new net::testing::MockFileStream( |
| + platform_file, |
| + base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC, |
| + NULL, base::MessageLoopProxy::current())); |
| + next_deletable_file_ = |
| + ShareableFileReference::GetOrCreate( |
| + file_path, |
| + ShareableFileReference::DELETE_ON_FINAL_RELEASE, |
| + BrowserThread::GetMessageLoopProxyForThread( |
| + BrowserThread::FILE).get()); |
| + } |
| + |
| + void DoCallback(base::WeakPtr<RedirectToFileResourceHandler> handler) { |
| + if (!handler) |
| + return; |
| + |
| + if (error_ != base::PLATFORM_FILE_OK) { |
| + handler->DidCreateTemporaryFile( |
| + error_, scoped_ptr<net::FileStream>(), NULL); |
| + error_ = base::PLATFORM_FILE_OK; |
| + } else { |
| + DCHECK(next_file_stream_); |
| + handler->DidCreateTemporaryFile( |
| + base::PLATFORM_FILE_OK, |
| + next_file_stream_.PassAs<net::FileStream>(), |
| + next_deletable_file_.get()); |
| + next_deletable_file_ = NULL; |
| + } |
| + } |
| + |
| + base::PlatformFileError error_; |
| + scoped_ptr<net::testing::MockFileStream> next_file_stream_; |
| + scoped_refptr<ShareableFileReference> next_deletable_file_; |
| +}; |
| + |
| } // namespace |
| class ResourceLoaderTest : public testing::Test, |
| @@ -172,6 +309,31 @@ class ResourceLoaderTest : public testing::Test, |
| resource_context_(&test_url_request_context_) { |
| } |
| + virtual void SetUp() OVERRIDE { |
| + job_factory_.SetProtocolHandler( |
| + "test", net::URLRequestTestJob::CreateProtocolHandler()); |
| + test_url_request_context_.set_job_factory(&job_factory_); |
|
mmenke
2013/12/05 21:34:03
Optional: Can't we just do this in the constructo
davidben
2013/12/05 22:43:20
Done.
|
| + } |
| + |
| + virtual void TearDown() OVERRIDE { |
| + } |
|
mmenke
2013/12/05 21:34:03
Don't think we need this.
davidben
2013/12/05 22:43:20
Done.
|
| + |
| + scoped_ptr<net::URLRequest> CreateTestRequest(const GURL& url) { |
| + const int kRenderProcessId = 1; |
| + const int kRenderViewId = 2; |
| + |
| + scoped_ptr<net::URLRequest> request( |
| + new net::URLRequest(url, net::DEFAULT_PRIORITY, NULL, |
| + resource_context_.GetRequestContext())); |
| + ResourceRequestInfo::AllocateForTesting(request.get(), |
| + ResourceType::MAIN_FRAME, |
| + &resource_context_, |
| + kRenderProcessId, |
| + kRenderViewId, |
| + false); |
| + return request.Pass(); |
| + } |
| + |
| // ResourceLoaderDelegate: |
| virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( |
| ResourceLoader* loader, |
| @@ -200,6 +362,7 @@ class ResourceLoaderTest : public testing::Test, |
| content::TestBrowserThreadBundle thread_bundle_; |
| + net::URLRequestJobFactoryImpl job_factory_; |
| net::TestURLRequestContext test_url_request_context_; |
| ResourceContextStub resource_context_; |
| }; |
| @@ -209,20 +372,7 @@ class ResourceLoaderTest : public testing::Test, |
| // certificates are correctly passed to the content browser client for |
| // selection. |
| TEST_F(ResourceLoaderTest, ClientCertStoreLookup) { |
| - const int kRenderProcessId = 1; |
| - const int kRenderViewId = 2; |
| - |
| - scoped_ptr<net::URLRequest> request( |
| - new net::URLRequest(GURL("dummy"), |
| - net::DEFAULT_PRIORITY, |
| - NULL, |
| - resource_context_.GetRequestContext())); |
| - ResourceRequestInfo::AllocateForTesting(request.get(), |
| - ResourceType::MAIN_FRAME, |
| - &resource_context_, |
| - kRenderProcessId, |
| - kRenderViewId, |
| - false); |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest(GURL("dummy")); |
| // Set up the test client cert store. |
| net::CertificateList dummy_certs(1, scoped_refptr<net::X509Certificate>( |
| @@ -239,7 +389,8 @@ TEST_F(ResourceLoaderTest, ClientCertStoreLookup) { |
| resource_context_.SetClientCertStore( |
| test_store.PassAs<net::ClientCertStore>()); |
| - scoped_ptr<ResourceHandler> resource_handler(new ResourceHandlerStub()); |
| + scoped_ptr<ResourceHandler> resource_handler( |
| + new ResourceHandlerStub(request.get())); |
| ResourceLoader loader(request.Pass(), resource_handler.Pass(), this); |
| // Prepare a dummy certificate request. |
| @@ -274,26 +425,14 @@ TEST_F(ResourceLoaderTest, ClientCertStoreLookup) { |
| // on a platform with a NULL client cert store still calls the content browser |
| // client for selection. |
| TEST_F(ResourceLoaderTest, ClientCertStoreNull) { |
| - const int kRenderProcessId = 1; |
| - const int kRenderViewId = 2; |
| - |
| - scoped_ptr<net::URLRequest> request( |
| - new net::URLRequest(GURL("dummy"), |
| - net::DEFAULT_PRIORITY, |
| - NULL, |
| - resource_context_.GetRequestContext())); |
| - ResourceRequestInfo::AllocateForTesting(request.get(), |
| - ResourceType::MAIN_FRAME, |
| - &resource_context_, |
| - kRenderProcessId, |
| - kRenderViewId, |
| - false); |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest(GURL("dummy")); |
| // Ownership of the |request| is about to be turned over to ResourceLoader. We |
| // need to keep a raw pointer copy to access this object later. |
| net::URLRequest* raw_ptr_to_request = request.get(); |
| - scoped_ptr<ResourceHandler> resource_handler(new ResourceHandlerStub()); |
| + scoped_ptr<ResourceHandler> resource_handler( |
| + new ResourceHandlerStub(request.get())); |
| ResourceLoader loader(request.Pass(), resource_handler.Pass(), this); |
| // Prepare a dummy certificate request. |
| @@ -320,4 +459,242 @@ TEST_F(ResourceLoaderTest, ClientCertStoreNull) { |
| EXPECT_EQ(net::CertificateList(), test_client.passed_certs()); |
| } |
| +// Tests that a RedirectToFileResourceHandler works and forwards everything |
| +// downstream. |
| +TEST_F(ResourceLoaderTest, RedirectToFile) { |
| + MockTemporaryFileManager temporary_file_manager; |
| + base::FilePath temp_path = |
| + temporary_file_manager.next_deletable_file()->path(); |
| + |
| + // Setup the request. |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest( |
| + net::URLRequestTestJob::test_url_1()); |
| + ResourceHandlerStub* leaf_handler = new ResourceHandlerStub(request.get()); |
| + scoped_ptr<ResourceHandler> resource_handler(leaf_handler); |
| + resource_handler.reset( |
| + new RedirectToFileResourceHandler(resource_handler.Pass(), request.get(), |
| + &temporary_file_manager)); |
| + scoped_ptr<ResourceLoader> loader(new ResourceLoader( |
| + request.Pass(), resource_handler.Pass(), this)); |
| + |
| + // Run it to completion. |
| + loader->StartRequest(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Check that the handler forwarded all information to the downstream handler. |
| + EXPECT_EQ(temp_path, leaf_handler->response()->head.download_file_path); |
| + EXPECT_EQ(net::URLRequestTestJob::test_url_1(), leaf_handler->start_url()); |
| + EXPECT_TRUE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(net::URLRequestStatus::SUCCESS, leaf_handler->status().status()); |
| + EXPECT_EQ(net::URLRequestTestJob::test_data_1().size(), |
| + static_cast<size_t>(leaf_handler->total_bytes_downloaded())); |
| + |
| + // Check that the data was written to the file. |
| + std::string contents; |
| + ASSERT_TRUE(base::ReadFileToString(temp_path, &contents)); |
| + EXPECT_EQ(net::URLRequestTestJob::test_data_1(), contents); |
| + |
| + // Release the loader. The file should be gone now. |
| + loader.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(base::PathExists(temp_path)); |
|
mmenke
2013/12/05 21:34:03
Still a bit concerned about testing cleanup, and w
davidben
2013/12/05 22:43:20
Hrm? Do you mean you'd rather not assert on base::
mmenke
2013/12/05 23:00:13
No, I'm fine with that. I mean I'm not sure asser
davidben
2013/12/05 23:21:00
Ah. Yeah, it's not a terribly good test there. It
|
| +} |
| + |
| +// Tests that RedirectToFileResourceHandler handles errors in creating the |
| +// temporary file. |
| +TEST_F(ResourceLoaderTest, RedirectToFileCreateTemporaryError) { |
| + MockTemporaryFileManager temporary_file_manager; |
| + temporary_file_manager.set_next_error(base::PLATFORM_FILE_ERROR_FAILED); |
| + |
| + // Setup the request. |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest( |
| + net::URLRequestTestJob::test_url_1()); |
| + ResourceHandlerStub* leaf_handler = new ResourceHandlerStub(request.get()); |
| + scoped_ptr<ResourceHandler> resource_handler(leaf_handler); |
| + resource_handler.reset( |
| + new RedirectToFileResourceHandler(resource_handler.Pass(), request.get(), |
| + &temporary_file_manager)); |
| + scoped_ptr<ResourceLoader> loader(new ResourceLoader( |
| + request.Pass(), resource_handler.Pass(), this)); |
| + |
| + // Run it to completion. |
| + loader->StartRequest(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // To downstream, the request was canceled. |
| + EXPECT_TRUE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(net::URLRequestStatus::CANCELED, leaf_handler->status().status()); |
| + EXPECT_EQ(0, leaf_handler->total_bytes_downloaded()); |
| +} |
| + |
| +// Tests that RedirectToFileResourceHandler handles synchronous write errors. |
| +TEST_F(ResourceLoaderTest, RedirectToFileWriteError) { |
| + MockTemporaryFileManager temporary_file_manager; |
| + base::FilePath temp_path = |
| + temporary_file_manager.next_deletable_file()->path(); |
| + net::testing::MockFileStream* mock_file_stream = |
| + temporary_file_manager.next_file_stream(); |
| + mock_file_stream->set_forced_error(net::ERR_FAILED); |
| + |
| + // Setup the request. |
|
mmenke
2013/12/05 21:34:03
nit: "setup" is a noun, "set up" is a verb.
davidben
2013/12/05 22:43:20
Done.
|
| + scoped_ptr<net::URLRequest> request = CreateTestRequest( |
| + net::URLRequestTestJob::test_url_1()); |
| + ResourceHandlerStub* leaf_handler = new ResourceHandlerStub(request.get()); |
| + scoped_ptr<ResourceHandler> resource_handler(leaf_handler); |
| + resource_handler.reset( |
| + new RedirectToFileResourceHandler(resource_handler.Pass(), request.get(), |
| + &temporary_file_manager)); |
| + scoped_ptr<ResourceLoader> loader(new ResourceLoader( |
| + request.Pass(), resource_handler.Pass(), this)); |
| + |
| + // Run it to completion. |
| + loader->StartRequest(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // To downstream, the request was canceled sometime after it started, but |
| + // before any data was written. |
| + EXPECT_EQ(temp_path, leaf_handler->response()->head.download_file_path); |
| + EXPECT_EQ(net::URLRequestTestJob::test_url_1(), leaf_handler->start_url()); |
| + EXPECT_TRUE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(net::URLRequestStatus::CANCELED, leaf_handler->status().status()); |
| + EXPECT_EQ(0, leaf_handler->total_bytes_downloaded()); |
| +} |
| + |
| +// Tests that RedirectToFileResourceHandler handles asynchronous write errors. |
| +TEST_F(ResourceLoaderTest, RedirectToFileWriteErrorAsync) { |
| + MockTemporaryFileManager temporary_file_manager; |
| + base::FilePath temp_path = |
| + temporary_file_manager.next_deletable_file()->path(); |
| + net::testing::MockFileStream* mock_file_stream = |
| + temporary_file_manager.next_file_stream(); |
| + mock_file_stream->set_forced_error_async(net::ERR_FAILED); |
| + |
| + // Setup the request. |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest( |
| + net::URLRequestTestJob::test_url_1()); |
| + ResourceHandlerStub* leaf_handler = new ResourceHandlerStub(request.get()); |
| + scoped_ptr<ResourceHandler> resource_handler(leaf_handler); |
| + resource_handler.reset( |
| + new RedirectToFileResourceHandler(resource_handler.Pass(), request.get(), |
| + &temporary_file_manager)); |
| + scoped_ptr<ResourceLoader> loader(new ResourceLoader( |
| + request.Pass(), resource_handler.Pass(), this)); |
| + |
| + // Run it to completion. |
| + loader->StartRequest(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // To downstream, the request was canceled sometime after it started, but |
| + // before any data was written. |
| + EXPECT_EQ(temp_path, leaf_handler->response()->head.download_file_path); |
| + EXPECT_EQ(net::URLRequestTestJob::test_url_1(), leaf_handler->start_url()); |
| + EXPECT_TRUE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(net::URLRequestStatus::CANCELED, leaf_handler->status().status()); |
| + EXPECT_EQ(0, leaf_handler->total_bytes_downloaded()); |
| +} |
| + |
| +// Tests that RedirectToFileHandler defers completion if there are outstanding |
| +// writes and accounts for errors which occur in that time. |
| +TEST_F(ResourceLoaderTest, RedirectToFileDeferCompletion) { |
| + // Program the MockFileStream to error asynchronously, but throttle the |
| + // callback. |
| + MockTemporaryFileManager temporary_file_manager; |
| + base::FilePath temp_path = |
| + temporary_file_manager.next_deletable_file()->path(); |
| + net::testing::MockFileStream* mock_file_stream = |
| + temporary_file_manager.next_file_stream(); |
| + mock_file_stream->set_forced_error_async(net::ERR_FAILED); |
| + mock_file_stream->ThrottleCallbacks(); |
| + |
| + // Setup the request. |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest( |
| + net::URLRequestTestJob::test_url_1()); |
| + net::URLRequest* raw_ptr_to_request = request.get(); |
| + ResourceHandlerStub* leaf_handler = new ResourceHandlerStub(request.get()); |
| + scoped_ptr<ResourceHandler> resource_handler(leaf_handler); |
| + resource_handler.reset( |
| + new RedirectToFileResourceHandler(resource_handler.Pass(), request.get(), |
| + &temporary_file_manager)); |
| + scoped_ptr<ResourceLoader> loader(new ResourceLoader( |
| + request.Pass(), resource_handler.Pass(), this)); |
| + |
| + // Run it as far as it will go. |
| + loader->StartRequest(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // At this point, the request should have completed. |
| + EXPECT_EQ(net::URLRequestStatus::SUCCESS, |
| + raw_ptr_to_request->status().status()); |
| + |
| + // However, the resource loader stack is stuck somewhere after receiving the |
| + // response. |
| + EXPECT_EQ(temp_path, leaf_handler->response()->head.download_file_path); |
| + EXPECT_EQ(net::URLRequestTestJob::test_url_1(), leaf_handler->start_url()); |
| + EXPECT_FALSE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(0, leaf_handler->total_bytes_downloaded()); |
| + |
| + // Now, release the floodgates. |
| + mock_file_stream->ReleaseCallbacks(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Although the URLRequest was successful, the leaf handler sees a failure |
| + // because the write never completed. |
| + EXPECT_TRUE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(net::URLRequestStatus::CANCELED, leaf_handler->status().status()); |
| +} |
| + |
| +// Tests that a RedirectToFileResourceHandler behaves properly when the |
| +// downstream handler defers OnWillStart. |
| +TEST_F(ResourceLoaderTest, RedirectToFileDownstreamDeferStart) { |
| + MockTemporaryFileManager temporary_file_manager; |
| + base::FilePath temp_path = |
| + temporary_file_manager.next_deletable_file()->path(); |
| + |
| + // Setup the request. |
| + scoped_ptr<net::URLRequest> request = CreateTestRequest( |
| + net::URLRequestTestJob::test_url_1()); |
| + ResourceHandlerStub* leaf_handler = new ResourceHandlerStub(request.get()); |
| + scoped_ptr<ResourceHandler> resource_handler(leaf_handler); |
| + resource_handler.reset( |
| + new RedirectToFileResourceHandler(resource_handler.Pass(), request.get(), |
| + &temporary_file_manager)); |
| + scoped_ptr<ResourceLoader> loader(new ResourceLoader( |
| + request.Pass(), resource_handler.Pass(), this)); |
| + |
| + // Defer OnWillStart. |
| + leaf_handler->set_defer_start(true); |
| + |
| + // Run as far as we'll go. |
| + loader->StartRequest(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // The request should have stopped at OnWillStart. |
| + EXPECT_EQ(net::URLRequestTestJob::test_url_1(), leaf_handler->start_url()); |
| + EXPECT_FALSE(leaf_handler->response()); |
| + EXPECT_FALSE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(0, leaf_handler->total_bytes_downloaded()); |
| + |
| + // Now resume the request. Now we complete. |
| + leaf_handler->Resume(); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Check that the handler forwarded all information to the downstream handler. |
| + EXPECT_EQ(temp_path, leaf_handler->response()->head.download_file_path); |
| + EXPECT_EQ(net::URLRequestTestJob::test_url_1(), leaf_handler->start_url()); |
| + EXPECT_TRUE(leaf_handler->received_response_completed()); |
| + EXPECT_EQ(net::URLRequestStatus::SUCCESS, leaf_handler->status().status()); |
| + EXPECT_EQ(net::URLRequestTestJob::test_data_1().size(), |
| + static_cast<size_t>(leaf_handler->total_bytes_downloaded())); |
| + |
| + // Check that the data was written to the file. |
| + std::string contents; |
| + ASSERT_TRUE(base::ReadFileToString(temp_path, &contents)); |
| + EXPECT_EQ(net::URLRequestTestJob::test_data_1(), contents); |
| + |
| + // Release the loader. The file should be gone now. |
| + loader.reset(); |
| + base::RunLoop().RunUntilIdle(); |
| + EXPECT_FALSE(base::PathExists(temp_path)); |
| +} |
| + |
| } // namespace content |