Roll src/third_party/WebKit 57aef96:a1089e6 (svn 201978:201979)
[chromium-blink-merge.git] / net / url_request / url_request_file_job_unittest.cc
blob06acd3283c6551e9c5932d920996754caa9f8ab4
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/thread_task_runner_handle.h"
13 #include "base/threading/sequenced_worker_pool.h"
14 #include "net/base/filename_util.h"
15 #include "net/base/net_util.h"
16 #include "net/url_request/url_request.h"
17 #include "net/url_request/url_request_test_util.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace net {
22 namespace {
24 // A URLRequestFileJob for testing OnSeekComplete / OnReadComplete callbacks.
25 class URLRequestFileJobWithCallbacks : public URLRequestFileJob {
26 public:
27 URLRequestFileJobWithCallbacks(
28 URLRequest* request,
29 NetworkDelegate* network_delegate,
30 const base::FilePath& file_path,
31 const scoped_refptr<base::TaskRunner>& file_task_runner)
32 : URLRequestFileJob(request,
33 network_delegate,
34 file_path,
35 file_task_runner),
36 seek_position_(0) {
39 int64 seek_position() { return seek_position_; }
40 const std::vector<std::string>& data_chunks() { return data_chunks_; }
42 protected:
43 ~URLRequestFileJobWithCallbacks() override {}
45 void OnSeekComplete(int64 result) override {
46 ASSERT_EQ(seek_position_, 0);
47 seek_position_ = result;
50 void OnReadComplete(IOBuffer* buf, int result) override {
51 data_chunks_.push_back(std::string(buf->data(), result));
54 int64 seek_position_;
55 std::vector<std::string> data_chunks_;
58 // A URLRequestJobFactory that will return URLRequestFileJobWithCallbacks
59 // instances for file:// scheme URLs.
60 class CallbacksJobFactory : public URLRequestJobFactory {
61 public:
62 class JobObserver {
63 public:
64 virtual void OnJobCreated(URLRequestFileJobWithCallbacks* job) = 0;
67 CallbacksJobFactory(const base::FilePath& path, JobObserver* observer)
68 : path_(path), observer_(observer) {
71 ~CallbacksJobFactory() override {}
73 URLRequestJob* MaybeCreateJobWithProtocolHandler(
74 const std::string& scheme,
75 URLRequest* request,
76 NetworkDelegate* network_delegate) const override {
77 URLRequestFileJobWithCallbacks* job = new URLRequestFileJobWithCallbacks(
78 request, network_delegate, path_, base::ThreadTaskRunnerHandle::Get());
79 observer_->OnJobCreated(job);
80 return job;
83 URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
84 NetworkDelegate* network_delegate,
85 const GURL& location) const override {
86 return nullptr;
89 URLRequestJob* MaybeInterceptResponse(
90 URLRequest* request,
91 NetworkDelegate* network_delegate) const override {
92 return nullptr;
95 bool IsHandledProtocol(const std::string& scheme) const override {
96 return scheme == "file";
99 bool IsHandledURL(const GURL& url) const override {
100 return IsHandledProtocol(url.scheme());
103 bool IsSafeRedirectTarget(const GURL& location) const override {
104 return false;
107 private:
108 base::FilePath path_;
109 JobObserver* observer_;
112 // Helper function to create a file in |directory| filled with
113 // |content|. Returns true on succes and fills in |path| with the full path to
114 // the file.
115 bool CreateTempFileWithContent(const std::string& content,
116 const base::ScopedTempDir& directory,
117 base::FilePath* path) {
118 if (!directory.IsValid())
119 return false;
121 if (!base::CreateTemporaryFileInDir(directory.path(), path))
122 return false;
124 return base::WriteFile(*path, content.c_str(), content.length());
127 class JobObserverImpl : public CallbacksJobFactory::JobObserver {
128 public:
129 void OnJobCreated(URLRequestFileJobWithCallbacks* job) override {
130 jobs_.push_back(job);
133 typedef std::vector<scoped_refptr<URLRequestFileJobWithCallbacks> > JobList;
135 const JobList& jobs() { return jobs_; }
137 protected:
138 JobList jobs_;
141 // A simple holder for start/end used in http range requests.
142 struct Range {
143 int start;
144 int end;
146 Range() {
147 start = 0;
148 end = 0;
151 Range(int start, int end) {
152 this->start = start;
153 this->end = end;
157 // A superclass for tests of the OnSeekComplete / OnReadComplete functions of
158 // URLRequestFileJob.
159 class URLRequestFileJobEventsTest : public testing::Test {
160 public:
161 URLRequestFileJobEventsTest();
163 protected:
164 // This creates a file with |content| as the contents, and then creates and
165 // runs a URLRequestFileJobWithCallbacks job to get the contents out of it,
166 // and makes sure that the callbacks observed the correct bytes. If a Range
167 // is provided, this function will add the appropriate Range http header to
168 // the request and verify that only the bytes in that range (inclusive) were
169 // observed.
170 void RunRequest(const std::string& content, const Range* range);
172 JobObserverImpl observer_;
173 TestURLRequestContext context_;
174 TestDelegate delegate_;
177 URLRequestFileJobEventsTest::URLRequestFileJobEventsTest() {}
179 void URLRequestFileJobEventsTest::RunRequest(const std::string& content,
180 const Range* range) {
181 base::ScopedTempDir directory;
182 ASSERT_TRUE(directory.CreateUniqueTempDir());
183 base::FilePath path;
184 ASSERT_TRUE(CreateTempFileWithContent(content, directory, &path));
185 CallbacksJobFactory factory(path, &observer_);
186 context_.set_job_factory(&factory);
188 scoped_ptr<URLRequest> request(context_.CreateRequest(
189 FilePathToFileURL(path), DEFAULT_PRIORITY, &delegate_));
190 if (range) {
191 ASSERT_GE(range->start, 0);
192 ASSERT_GE(range->end, 0);
193 ASSERT_LE(range->start, range->end);
194 ASSERT_LT(static_cast<unsigned int>(range->end), content.length());
195 std::string range_value =
196 base::StringPrintf("bytes=%d-%d", range->start, range->end);
197 request->SetExtraRequestHeaderByName(
198 HttpRequestHeaders::kRange, range_value, true /*overwrite*/);
200 request->Start();
202 base::RunLoop loop;
203 loop.Run();
205 EXPECT_FALSE(delegate_.request_failed());
206 int expected_length =
207 range ? (range->end - range->start + 1) : content.length();
208 EXPECT_EQ(delegate_.bytes_received(), expected_length);
210 std::string expected_content;
211 if (range) {
212 expected_content.insert(0, content, range->start, expected_length);
213 } else {
214 expected_content = content;
216 EXPECT_TRUE(delegate_.data_received() == expected_content);
218 ASSERT_EQ(observer_.jobs().size(), 1u);
219 ASSERT_EQ(observer_.jobs().at(0)->seek_position(), range ? range->start : 0);
221 std::string observed_content;
222 const std::vector<std::string>& chunks =
223 observer_.jobs().at(0)->data_chunks();
224 for (std::vector<std::string>::const_iterator i = chunks.begin();
225 i != chunks.end();
226 ++i) {
227 observed_content.append(*i);
229 EXPECT_EQ(expected_content, observed_content);
232 // Helper function to make a character array filled with |size| bytes of
233 // test content.
234 std::string MakeContentOfSize(int size) {
235 EXPECT_GE(size, 0);
236 std::string result;
237 result.reserve(size);
238 for (int i = 0; i < size; i++) {
239 result.append(1, static_cast<char>(i % 256));
241 return result;
244 TEST_F(URLRequestFileJobEventsTest, TinyFile) {
245 RunRequest(std::string("hello world"), NULL);
248 TEST_F(URLRequestFileJobEventsTest, SmallFile) {
249 RunRequest(MakeContentOfSize(17 * 1024), NULL);
252 TEST_F(URLRequestFileJobEventsTest, BigFile) {
253 RunRequest(MakeContentOfSize(3 * 1024 * 1024), NULL);
256 TEST_F(URLRequestFileJobEventsTest, Range) {
257 // Use a 15KB content file and read a range chosen somewhat arbitrarily but
258 // not aligned on any likely page boundaries.
259 int size = 15 * 1024;
260 Range range(1701, (6 * 1024) + 3);
261 RunRequest(MakeContentOfSize(size), &range);
264 } // namespace
266 } // namespace net