| Index: net/url_request/url_request_simple_job_unittest.cc
 | 
| diff --git a/net/url_request/url_request_simple_job_unittest.cc b/net/url_request/url_request_simple_job_unittest.cc
 | 
| index 7fbdefb4e887aa1984e85bba8ba64adad9189f1c..4be4c428912b37996fcf377aa79e663575fc86b4 100644
 | 
| --- a/net/url_request/url_request_simple_job_unittest.cc
 | 
| +++ b/net/url_request/url_request_simple_job_unittest.cc
 | 
| @@ -5,6 +5,8 @@
 | 
|  #include "base/memory/scoped_ptr.h"
 | 
|  #include "base/run_loop.h"
 | 
|  #include "base/strings/stringprintf.h"
 | 
| +#include "base/threading/sequenced_worker_pool.h"
 | 
| +#include "base/threading/worker_pool.h"
 | 
|  #include "net/base/request_priority.h"
 | 
|  #include "net/url_request/url_request_job.h"
 | 
|  #include "net/url_request/url_request_job_factory.h"
 | 
| @@ -26,45 +28,100 @@ static_assert(kRangeFirstPosition > 0 &&
 | 
|                        static_cast<int>(arraysize(kTestData) - 1),
 | 
|                "invalid range");
 | 
|  
 | 
| +// This function does nothing.
 | 
| +void DoNothing() {
 | 
| +}
 | 
| +
 | 
|  class MockSimpleJob : public URLRequestSimpleJob {
 | 
|   public:
 | 
| -  MockSimpleJob(URLRequest* request, NetworkDelegate* network_delegate)
 | 
| -      : URLRequestSimpleJob(request, network_delegate) {
 | 
| -  }
 | 
| +  MockSimpleJob(URLRequest* request,
 | 
| +                NetworkDelegate* network_delegate,
 | 
| +                scoped_refptr<base::TaskRunner> task_runner,
 | 
| +                std::string data)
 | 
| +      : URLRequestSimpleJob(request, network_delegate),
 | 
| +        data_(data),
 | 
| +        task_runner_(task_runner) {}
 | 
|  
 | 
|   protected:
 | 
| +  // URLRequestSimpleJob implementation:
 | 
|    int GetData(std::string* mime_type,
 | 
|                std::string* charset,
 | 
|                std::string* data,
 | 
|                const CompletionCallback& callback) const override {
 | 
|      mime_type->assign("text/plain");
 | 
|      charset->assign("US-ASCII");
 | 
| -    data->assign(kTestData);
 | 
| +    data->assign(data_);
 | 
|      return OK;
 | 
|    }
 | 
|  
 | 
| +  base::TaskRunner* GetTaskRunner() const override {
 | 
| +    return task_runner_.get();
 | 
| +  }
 | 
| +
 | 
|   private:
 | 
|    ~MockSimpleJob() override {}
 | 
|  
 | 
| -  std::string data_;
 | 
| +  const std::string data_;
 | 
| +
 | 
| +  scoped_refptr<base::TaskRunner> task_runner_;
 | 
|  
 | 
|    DISALLOW_COPY_AND_ASSIGN(MockSimpleJob);
 | 
|  };
 | 
|  
 | 
| +class CancelURLRequestDelegate : public net::URLRequest::Delegate {
 | 
| + public:
 | 
| +  explicit CancelURLRequestDelegate()
 | 
| +      : buf_(new IOBuffer(kBufferSize)), run_loop_(new base::RunLoop) {}
 | 
| +
 | 
| +  void OnResponseStarted(net::URLRequest* request) override {
 | 
| +    int bytes_read = 0;
 | 
| +    EXPECT_FALSE(request->Read(buf_.get(), kBufferSize, &bytes_read));
 | 
| +    EXPECT_TRUE(request->status().is_io_pending());
 | 
| +    request->Cancel();
 | 
| +    run_loop_->Quit();
 | 
| +  }
 | 
| +
 | 
| +  void OnReadCompleted(URLRequest* request, int bytes_read) override {}
 | 
| +
 | 
| +  void WaitUntilHeadersReceived() const { run_loop_->Run(); }
 | 
| +
 | 
| + private:
 | 
| +  static const int kBufferSize = 4096;
 | 
| +  scoped_refptr<IOBuffer> buf_;
 | 
| +  scoped_ptr<base::RunLoop> run_loop_;
 | 
| +};
 | 
| +
 | 
|  class SimpleJobProtocolHandler :
 | 
|      public URLRequestJobFactory::ProtocolHandler {
 | 
|   public:
 | 
| +  SimpleJobProtocolHandler(scoped_refptr<base::TaskRunner> task_runner)
 | 
| +      : task_runner_(task_runner) {}
 | 
|    URLRequestJob* MaybeCreateJob(
 | 
|        URLRequest* request,
 | 
|        NetworkDelegate* network_delegate) const override {
 | 
| -    return new MockSimpleJob(request, network_delegate);
 | 
| +    if (request->url().spec() == "data:empty")
 | 
| +      return new MockSimpleJob(request, network_delegate, task_runner_, "");
 | 
| +    return new MockSimpleJob(request, network_delegate, task_runner_,
 | 
| +                             kTestData);
 | 
|    }
 | 
| +
 | 
| + private:
 | 
| +  scoped_refptr<base::TaskRunner> task_runner_;
 | 
| +
 | 
| +  ~SimpleJobProtocolHandler() override {}
 | 
|  };
 | 
|  
 | 
|  class URLRequestSimpleJobTest : public ::testing::Test {
 | 
|   public:
 | 
| -  URLRequestSimpleJobTest() : context_(true) {
 | 
| -    job_factory_.SetProtocolHandler("data", new SimpleJobProtocolHandler());
 | 
| +  URLRequestSimpleJobTest()
 | 
| +      : worker_pool_(
 | 
| +            new base::SequencedWorkerPool(1, "URLRequestSimpleJobTest")),
 | 
| +        task_runner_(worker_pool_->GetSequencedTaskRunnerWithShutdownBehavior(
 | 
| +            worker_pool_->GetSequenceToken(),
 | 
| +            base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)),
 | 
| +        context_(true) {
 | 
| +    job_factory_.SetProtocolHandler("data",
 | 
| +                                    new SimpleJobProtocolHandler(task_runner_));
 | 
|      context_.set_job_factory(&job_factory_);
 | 
|      context_.Init();
 | 
|  
 | 
| @@ -72,6 +129,8 @@ class URLRequestSimpleJobTest : public ::testing::Test {
 | 
|          GURL("data:test"), DEFAULT_PRIORITY, &delegate_, NULL);
 | 
|    }
 | 
|  
 | 
| +  ~URLRequestSimpleJobTest() override { worker_pool_->Shutdown(); }
 | 
| +
 | 
|    void StartRequest(const HttpRequestHeaders* headers) {
 | 
|      if (headers)
 | 
|        request_->SetExtraRequestHeaders(*headers);
 | 
| @@ -82,9 +141,13 @@ class URLRequestSimpleJobTest : public ::testing::Test {
 | 
|      EXPECT_FALSE(request_->is_pending());
 | 
|    }
 | 
|  
 | 
| +  void TearDown() override { worker_pool_->Shutdown(); }
 | 
| +
 | 
|   protected:
 | 
| -  URLRequestJobFactoryImpl job_factory_;
 | 
| +  scoped_refptr<base::SequencedWorkerPool> worker_pool_;
 | 
| +  scoped_refptr<base::SequencedTaskRunner> task_runner_;
 | 
|    TestURLRequestContext context_;
 | 
| +  URLRequestJobFactoryImpl job_factory_;
 | 
|    TestDelegate delegate_;
 | 
|    scoped_ptr<URLRequest> request_;
 | 
|  };
 | 
| @@ -140,4 +203,28 @@ TEST_F(URLRequestSimpleJobTest, InvalidRangeRequest) {
 | 
|    EXPECT_EQ(kTestData, delegate_.data_received());
 | 
|  }
 | 
|  
 | 
| +TEST_F(URLRequestSimpleJobTest, EmptyDataRequest) {
 | 
| +  request_ = context_.CreateRequest(GURL("data:empty"), DEFAULT_PRIORITY,
 | 
| +                                    &delegate_, NULL);
 | 
| +  StartRequest(nullptr);
 | 
| +  ASSERT_TRUE(request_->status().is_success());
 | 
| +  EXPECT_EQ("", delegate_.data_received());
 | 
| +}
 | 
| +
 | 
| +TEST_F(URLRequestSimpleJobTest, CancelAfterFirstRead) {
 | 
| +  scoped_ptr<CancelURLRequestDelegate> cancel_delegate(
 | 
| +      new CancelURLRequestDelegate());
 | 
| +  request_ = context_.CreateRequest(GURL("data:cancel"), DEFAULT_PRIORITY,
 | 
| +                                    cancel_delegate.get(), NULL);
 | 
| +  request_->Start();
 | 
| +  cancel_delegate->WaitUntilHeadersReceived();
 | 
| +
 | 
| +  // Feed a dummy task to the SequencedTaskRunner to make sure that the
 | 
| +  // callbacks which are invoked in ReadRawData have completed safely.
 | 
| +  base::RunLoop run_loop;
 | 
| +  EXPECT_TRUE(task_runner_->PostTaskAndReply(FROM_HERE, base::Bind(&DoNothing),
 | 
| +                                             run_loop.QuitClosure()));
 | 
| +  run_loop.Run();
 | 
| +}
 | 
| +
 | 
|  }  // namespace net
 | 
| 
 |