OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | |
rvargas (doing something else)
2014/04/08 16:53:45
I think we don't use (c) anynmore
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Done.
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "net/url_request/url_request_file_job.h" | |
6 | |
7 #include "base/files/scoped_temp_dir.h" | |
8 #include "base/run_loop.h" | |
9 #include "base/strings/stringprintf.h" | |
10 #include "base/threading/sequenced_worker_pool.h" | |
11 #include "net/base/net_util.h" | |
12 #include "net/url_request/url_request_test_util.h" | |
13 #include "testing/gtest/include/gtest/gtest.h" | |
14 | |
15 namespace net { | |
16 namespace { | |
17 | |
18 // A URLRequestFileJob for testing OnSeekComplete / OnReadComplete callbacks. | |
19 class URLRequestFileJobWithCallbacks : public URLRequestFileJob { | |
20 public: | |
21 URLRequestFileJobWithCallbacks( | |
22 URLRequest* request, | |
23 NetworkDelegate* network_delegate, | |
24 const base::FilePath& file_path, | |
25 const scoped_refptr<base::TaskRunner>& file_task_runner) | |
26 : URLRequestFileJob(request, | |
27 network_delegate, | |
28 file_path, | |
29 file_task_runner), | |
30 seek_position_(0) {} | |
rvargas (doing something else)
2014/04/08 16:53:45
nit: {
}
(this is not a single line anymore)
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Done.
| |
31 | |
32 int64 seek_position() { return seek_position_; } | |
33 const std::vector<std::string>& data_chunks() { return data_chunks_; } | |
34 | |
35 protected: | |
36 virtual ~URLRequestFileJobWithCallbacks() {} | |
37 | |
38 virtual void OnSeekComplete(int64 result) OVERRIDE { | |
39 ASSERT_EQ(seek_position_, 0); | |
40 seek_position_ = result; | |
41 } | |
42 | |
43 virtual void OnReadComplete(IOBuffer* buf, int result) OVERRIDE { | |
44 data_chunks_.push_back(std::string(buf->data(), result)); | |
45 } | |
46 | |
47 int64 seek_position_; | |
48 std::vector<std::string> data_chunks_; | |
49 }; | |
50 | |
51 // A URLRequestJobFactory that will return URLRequestFileJobWithCallbacks | |
52 // instances for file:// scheme URLs. | |
53 class CallbacksJobFactory : public URLRequestJobFactory { | |
54 public: | |
55 class JobObserver { | |
56 public: | |
57 virtual void OnJobCreated(URLRequestFileJobWithCallbacks* job) = 0; | |
58 }; | |
59 | |
60 CallbacksJobFactory(const base::FilePath& path, JobObserver* observer) | |
61 : path_(path), observer_(observer) {} | |
rvargas (doing something else)
2014/04/08 16:53:45
nit: {
}
(this is not a single line anymore)
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Done.
| |
62 | |
63 virtual ~CallbacksJobFactory() {} | |
64 | |
65 virtual URLRequestJob* MaybeCreateJobWithProtocolHandler( | |
66 const std::string& scheme, | |
67 URLRequest* request, | |
68 NetworkDelegate* network_delegate) const OVERRIDE { | |
69 URLRequestFileJobWithCallbacks* job = new URLRequestFileJobWithCallbacks( | |
70 request, | |
71 network_delegate, | |
72 path_, | |
73 base::MessageLoop::current()->message_loop_proxy()); | |
74 observer_->OnJobCreated(job); | |
75 return job; | |
76 } | |
77 | |
78 virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE { | |
79 return scheme == "file"; | |
80 } | |
81 | |
82 virtual bool IsHandledURL(const GURL& url) const OVERRIDE { | |
83 return IsHandledProtocol(url.scheme()); | |
84 } | |
85 | |
86 virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE { | |
87 return false; | |
88 } | |
89 | |
90 private: | |
91 base::FilePath path_; | |
92 JobObserver* observer_; | |
93 }; | |
94 | |
95 // Helper function to create a file in |directory| named |filename| filled with | |
96 // |content|. Returns true on succes and fills in |path| with the full path to | |
97 // the file. If |directory| does not exist yet, it will be created. | |
98 bool CreateTempFileWithContent(const std::string& filename, | |
99 const std::string& content, | |
100 base::ScopedTempDir* directory, | |
101 base::FilePath* path) { | |
102 if (directory == NULL || path == NULL || !IsStringASCII(filename)) | |
103 return false; | |
104 if (!directory->IsValid() && !directory->CreateUniqueTempDir()) | |
105 return false; | |
106 *path = directory->path().AppendASCII(filename); | |
107 | |
108 base::File file(*path, | |
109 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND); | |
rvargas (doing something else)
2014/04/08 16:53:45
Why not CREATE and WRITE? Appending to a file seem
| |
110 int bytes_written = file.WriteAtCurrentPos(content.c_str(), content.length()); | |
rvargas (doing something else)
2014/04/08 16:53:45
file.Write(0, ...) ? (assuming CREATE and WRITE)
rvargas (doing something else)
2014/04/08 16:53:45
should check that the file is valid before using i
| |
111 if (bytes_written <= 0 || (unsigned)bytes_written != content.length()) | |
112 return false; | |
113 file.Close(); | |
rvargas (doing something else)
2014/04/08 16:53:45
no need to close.
btw, this whole block should pr
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Ah, much simpler, thanks for the tip. Done. (this
| |
114 | |
115 return true; | |
116 } | |
117 | |
118 // A superclass for tests of the OnSeekComplete / OnReadComplete functions of | |
119 // URLRequestFileJob. | |
120 class URLRequestFileJobEventsTest : public testing::Test { | |
rvargas (doing something else)
2014/04/08 16:53:45
nit: I think this class is too long to have an inl
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Good point. I've moved the JobObserverImpl and Ran
| |
121 public: | |
122 URLRequestFileJobEventsTest() {} | |
123 | |
124 class JobObserverImpl : public CallbacksJobFactory::JobObserver { | |
125 public: | |
126 virtual void OnJobCreated(URLRequestFileJobWithCallbacks* job) OVERRIDE { | |
127 jobs_.push_back(job); | |
128 } | |
129 | |
130 typedef std::vector<scoped_refptr<URLRequestFileJobWithCallbacks> > JobList; | |
131 | |
132 const JobList& jobs() { return jobs_; } | |
133 | |
134 protected: | |
135 JobList jobs_; | |
136 }; | |
137 | |
138 // A simple holder for start/end used in http range requests. | |
139 struct Range { | |
140 int start; | |
141 int end; | |
142 | |
143 Range() { | |
144 start = 0; | |
145 end = 0; | |
146 } | |
147 | |
148 Range(int start, int end) { | |
149 this->start = start; | |
150 this->end = end; | |
151 } | |
152 }; | |
153 | |
154 protected: | |
155 // This creates a file with |content| as the contents, and then creates and | |
156 // runs a URLRequestFileJobWithCallbacks job to get the contents out of it, | |
157 // and makes sure that the callbacks observed the correct bytes. If a Range | |
158 // is provided, this function will add the appropriate Range http header to | |
159 // the request and verify that only the bytes in that range (inclusive) were | |
160 // observed. | |
161 void RunRequest(const std::string& content, const Range* range) { | |
162 base::ScopedTempDir directory; | |
163 base::FilePath path; | |
164 ASSERT_TRUE( | |
165 CreateTempFileWithContent("file.dat", content, &directory, &path)); | |
166 CallbacksJobFactory factory(path, &observer_); | |
167 context_.set_job_factory(&factory); | |
168 | |
169 TestURLRequest request( | |
170 FilePathToFileURL(path), DEFAULT_PRIORITY, &delegate_, &context_); | |
171 if (range) { | |
172 ASSERT_GE(range->start, 0); | |
173 ASSERT_GE(range->end, 0); | |
174 ASSERT_LT((unsigned)range->end, content.length()); | |
rvargas (doing something else)
2014/04/08 16:53:45
nit:c++ cast
rvargas (doing something else)
2014/04/08 16:53:45
+ assert start <= end ?
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Done.
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Done.
| |
175 std::string range_value = | |
176 base::StringPrintf("bytes=%d-%d", range->start, range->end); | |
177 request.SetExtraRequestHeaderByName( | |
178 HttpRequestHeaders::kRange, range_value, true /*overwrite*/); | |
179 } | |
180 request.Start(); | |
181 | |
182 base::RunLoop loop; | |
183 loop.Run(); | |
184 | |
185 EXPECT_FALSE(delegate_.request_failed()); | |
186 int expected_length = | |
187 range ? (range->end - range->start + 1) : content.length(); | |
188 EXPECT_EQ(delegate_.bytes_received(), expected_length); | |
189 | |
190 std::string expected_content; | |
191 if (range) { | |
192 expected_content.insert(0, content, range->start, expected_length); | |
193 } else { | |
194 expected_content = content; | |
195 } | |
196 EXPECT_TRUE(delegate_.data_received() == expected_content); | |
rvargas (doing something else)
2014/04/08 16:53:45
Doesn't this beeps and prints garbage when it fail
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Nope- notice I used EXPECT_TRUE on single boolean
rvargas (doing something else)
2014/04/09 23:48:50
yes, I missed that!
| |
197 | |
198 ASSERT_EQ(observer_.jobs().size(), 1u); | |
199 ASSERT_EQ(observer_.jobs().at(0)->seek_position(), | |
200 range ? range->start : 0); | |
201 | |
202 std::string observed_content; | |
203 const std::vector<std::string>& chunks = | |
204 observer_.jobs().at(0)->data_chunks(); | |
205 for (std::vector<std::string>::const_iterator i = chunks.begin(); | |
206 i != chunks.end(); | |
207 ++i) { | |
208 observed_content.append(*i); | |
209 } | |
210 EXPECT_EQ(expected_content, observed_content); | |
211 EXPECT_TRUE(expected_content == observed_content); | |
212 } | |
213 | |
214 JobObserverImpl observer_; | |
215 TestURLRequestContext context_; | |
216 TestDelegate delegate_; | |
217 }; | |
218 | |
219 // Helper function to make a character array filled with |size| bytes of | |
220 // test content. | |
221 std::string MakeContentOfSize(int size) { | |
222 std::string result; | |
223 for (int i = 0; i < size; i++) { | |
224 result.append(1, static_cast<char>(i % 256)); | |
rvargas (doing something else)
2014/04/08 16:53:45
does it make sense to preallocate the string (cons
asargent_no_longer_on_chrome
2014/04/09 20:59:59
Yes, good idea. Done.
| |
225 } | |
226 return result; | |
227 } | |
228 | |
229 TEST_F(URLRequestFileJobEventsTest, TinyFile) { | |
230 RunRequest(std::string("hello world"), NULL); | |
231 } | |
232 | |
233 TEST_F(URLRequestFileJobEventsTest, SmallFile) { | |
234 RunRequest(MakeContentOfSize(17 * 1024), NULL); | |
235 } | |
236 | |
237 TEST_F(URLRequestFileJobEventsTest, BigFile) { | |
238 RunRequest(MakeContentOfSize(3 * 1024 * 1024), NULL); | |
239 } | |
240 | |
241 TEST_F(URLRequestFileJobEventsTest, Range) { | |
242 // Use a 15KB content file and read a range chosen somewhat arbitrarily but | |
243 // not aligned on any likely page boundaries. | |
244 int size = 15 * 1024; | |
245 Range range(1701, (6 * 1024) + 3); | |
246 RunRequest(MakeContentOfSize(size), &range); | |
247 } | |
248 | |
249 } // namespace | |
rvargas (doing something else)
2014/04/08 16:53:45
nit: do you mind keeping the actual tests outside
| |
250 } // namespace net | |
OLD | NEW |