Add --output-dir flag for page_runner.py to specify a custom directory for
[chromium-blink-merge.git] / net / url_request / url_request_file_job_unittest.cc
blob4f7984c2b8bfb1b9ce6ed49d01874057845c4b04
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/url_request/url_request_file_job.h"
7 #include "base/files/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/threading/sequenced_worker_pool.h"
13 #include "net/base/filename_util.h"
14 #include "net/base/net_util.h"
15 #include "net/url_request/url_request.h"
16 #include "net/url_request/url_request_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 namespace net {
21 namespace {
23 // A URLRequestFileJob for testing OnSeekComplete / OnReadComplete callbacks.
24 class URLRequestFileJobWithCallbacks : public URLRequestFileJob {
25 public:
26 URLRequestFileJobWithCallbacks(
27 URLRequest* request,
28 NetworkDelegate* network_delegate,
29 const base::FilePath& file_path,
30 const scoped_refptr<base::TaskRunner>& file_task_runner)
31 : URLRequestFileJob(request,
32 network_delegate,
33 file_path,
34 file_task_runner),
35 seek_position_(0) {
38 int64 seek_position() { return seek_position_; }
39 const std::vector<std::string>& data_chunks() { return data_chunks_; }
41 protected:
42 virtual ~URLRequestFileJobWithCallbacks() {}
44 virtual void OnSeekComplete(int64 result) OVERRIDE {
45 ASSERT_EQ(seek_position_, 0);
46 seek_position_ = result;
49 virtual void OnReadComplete(IOBuffer* buf, int result) OVERRIDE {
50 data_chunks_.push_back(std::string(buf->data(), result));
53 int64 seek_position_;
54 std::vector<std::string> data_chunks_;
57 // A URLRequestJobFactory that will return URLRequestFileJobWithCallbacks
58 // instances for file:// scheme URLs.
59 class CallbacksJobFactory : public URLRequestJobFactory {
60 public:
61 class JobObserver {
62 public:
63 virtual void OnJobCreated(URLRequestFileJobWithCallbacks* job) = 0;
66 CallbacksJobFactory(const base::FilePath& path, JobObserver* observer)
67 : path_(path), observer_(observer) {
70 virtual ~CallbacksJobFactory() {}
72 virtual URLRequestJob* MaybeCreateJobWithProtocolHandler(
73 const std::string& scheme,
74 URLRequest* request,
75 NetworkDelegate* network_delegate) const OVERRIDE {
76 URLRequestFileJobWithCallbacks* job = new URLRequestFileJobWithCallbacks(
77 request,
78 network_delegate,
79 path_,
80 base::MessageLoop::current()->message_loop_proxy());
81 observer_->OnJobCreated(job);
82 return job;
85 virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE {
86 return scheme == "file";
89 virtual bool IsHandledURL(const GURL& url) const OVERRIDE {
90 return IsHandledProtocol(url.scheme());
93 virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE {
94 return false;
97 private:
98 base::FilePath path_;
99 JobObserver* observer_;
102 // Helper function to create a file in |directory| filled with
103 // |content|. Returns true on succes and fills in |path| with the full path to
104 // the file.
105 bool CreateTempFileWithContent(const std::string& content,
106 const base::ScopedTempDir& directory,
107 base::FilePath* path) {
108 if (!directory.IsValid())
109 return false;
111 if (!base::CreateTemporaryFileInDir(directory.path(), path))
112 return false;
114 return base::WriteFile(*path, content.c_str(), content.length());
117 class JobObserverImpl : public CallbacksJobFactory::JobObserver {
118 public:
119 virtual void OnJobCreated(URLRequestFileJobWithCallbacks* job) OVERRIDE {
120 jobs_.push_back(job);
123 typedef std::vector<scoped_refptr<URLRequestFileJobWithCallbacks> > JobList;
125 const JobList& jobs() { return jobs_; }
127 protected:
128 JobList jobs_;
131 // A simple holder for start/end used in http range requests.
132 struct Range {
133 int start;
134 int end;
136 Range() {
137 start = 0;
138 end = 0;
141 Range(int start, int end) {
142 this->start = start;
143 this->end = end;
147 // A superclass for tests of the OnSeekComplete / OnReadComplete functions of
148 // URLRequestFileJob.
149 class URLRequestFileJobEventsTest : public testing::Test {
150 public:
151 URLRequestFileJobEventsTest();
153 protected:
154 // This creates a file with |content| as the contents, and then creates and
155 // runs a URLRequestFileJobWithCallbacks job to get the contents out of it,
156 // and makes sure that the callbacks observed the correct bytes. If a Range
157 // is provided, this function will add the appropriate Range http header to
158 // the request and verify that only the bytes in that range (inclusive) were
159 // observed.
160 void RunRequest(const std::string& content, const Range* range);
162 JobObserverImpl observer_;
163 TestURLRequestContext context_;
164 TestDelegate delegate_;
167 URLRequestFileJobEventsTest::URLRequestFileJobEventsTest() {}
169 void URLRequestFileJobEventsTest::RunRequest(const std::string& content,
170 const Range* range) {
171 base::ScopedTempDir directory;
172 ASSERT_TRUE(directory.CreateUniqueTempDir());
173 base::FilePath path;
174 ASSERT_TRUE(CreateTempFileWithContent(content, directory, &path));
175 CallbacksJobFactory factory(path, &observer_);
176 context_.set_job_factory(&factory);
178 scoped_ptr<URLRequest> request(context_.CreateRequest(
179 FilePathToFileURL(path), DEFAULT_PRIORITY, &delegate_, NULL));
180 if (range) {
181 ASSERT_GE(range->start, 0);
182 ASSERT_GE(range->end, 0);
183 ASSERT_LE(range->start, range->end);
184 ASSERT_LT(static_cast<unsigned int>(range->end), content.length());
185 std::string range_value =
186 base::StringPrintf("bytes=%d-%d", range->start, range->end);
187 request->SetExtraRequestHeaderByName(
188 HttpRequestHeaders::kRange, range_value, true /*overwrite*/);
190 request->Start();
192 base::RunLoop loop;
193 loop.Run();
195 EXPECT_FALSE(delegate_.request_failed());
196 int expected_length =
197 range ? (range->end - range->start + 1) : content.length();
198 EXPECT_EQ(delegate_.bytes_received(), expected_length);
200 std::string expected_content;
201 if (range) {
202 expected_content.insert(0, content, range->start, expected_length);
203 } else {
204 expected_content = content;
206 EXPECT_TRUE(delegate_.data_received() == expected_content);
208 ASSERT_EQ(observer_.jobs().size(), 1u);
209 ASSERT_EQ(observer_.jobs().at(0)->seek_position(), range ? range->start : 0);
211 std::string observed_content;
212 const std::vector<std::string>& chunks =
213 observer_.jobs().at(0)->data_chunks();
214 for (std::vector<std::string>::const_iterator i = chunks.begin();
215 i != chunks.end();
216 ++i) {
217 observed_content.append(*i);
219 EXPECT_EQ(expected_content, observed_content);
222 // Helper function to make a character array filled with |size| bytes of
223 // test content.
224 std::string MakeContentOfSize(int size) {
225 EXPECT_GE(size, 0);
226 std::string result;
227 result.reserve(size);
228 for (int i = 0; i < size; i++) {
229 result.append(1, static_cast<char>(i % 256));
231 return result;
234 TEST_F(URLRequestFileJobEventsTest, TinyFile) {
235 RunRequest(std::string("hello world"), NULL);
238 TEST_F(URLRequestFileJobEventsTest, SmallFile) {
239 RunRequest(MakeContentOfSize(17 * 1024), NULL);
242 TEST_F(URLRequestFileJobEventsTest, BigFile) {
243 RunRequest(MakeContentOfSize(3 * 1024 * 1024), NULL);
246 TEST_F(URLRequestFileJobEventsTest, Range) {
247 // Use a 15KB content file and read a range chosen somewhat arbitrarily but
248 // not aligned on any likely page boundaries.
249 int size = 15 * 1024;
250 Range range(1701, (6 * 1024) + 3);
251 RunRequest(MakeContentOfSize(size), &range);
254 } // namespace
256 } // namespace net