OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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. | |
4 | |
5 #include <string.h> | |
6 #include <algorithm> | |
7 #include <string> | |
8 #include <vector> | |
9 #include "base/message_loop.h" | |
10 #include "googleurl/src/gurl.h" | |
11 #include "net/base/filter.h" | |
12 #include "net/base/io_buffer.h" | |
13 #include "net/url_request/url_request.h" | |
14 #include "net/url_request/url_request_job.h" | |
15 #include "net/url_request/url_request_job_tracker.h" | |
16 #include "net/url_request/url_request_status.h" | |
17 #include "net/url_request/url_request_test_util.h" | |
18 #include "testing/gmock/include/gmock/gmock.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 #include "testing/platform_test.h" | |
21 | |
22 using testing::Eq; | |
23 using testing::InSequence; | |
24 using testing::NotNull; | |
25 using testing::StrictMock; | |
26 | |
27 namespace net { | |
28 namespace { | |
29 | |
30 const char kBasic[] = "Hello\n"; | |
31 | |
32 // The above string "Hello\n", gzip compressed. | |
33 const unsigned char kCompressed[] = { | |
34 0x1f, 0x8b, 0x08, 0x08, 0x38, 0x18, 0x2e, 0x4c, 0x00, 0x03, 0x63, | |
35 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x2e, 0x68, | |
36 0x74, 0x6d, 0x6c, 0x00, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xe7, 0x02, | |
37 0x00, 0x16, 0x35, 0x96, 0x31, 0x06, 0x00, 0x00, 0x00 | |
38 }; | |
39 | |
40 bool GetResponseBody(const GURL& url, std::string* out_body) { | |
41 if (url.spec() == "test:basic") { | |
42 *out_body = kBasic; | |
43 } else if (url.spec() == "test:compressed") { | |
44 out_body->assign(reinterpret_cast<const char*>(kCompressed), | |
45 sizeof(kCompressed)); | |
46 } else { | |
47 return false; | |
48 } | |
49 | |
50 return true; | |
51 } | |
52 | |
53 class MockJobObserver : public URLRequestJobTracker::JobObserver { | |
54 public: | |
55 MOCK_METHOD1(OnJobAdded, void(URLRequestJob* job)); | |
56 MOCK_METHOD1(OnJobRemoved, void(URLRequestJob* job)); | |
57 MOCK_METHOD2(OnJobDone, void(URLRequestJob* job, | |
58 const URLRequestStatus& status)); | |
59 MOCK_METHOD3(OnJobRedirect, void(URLRequestJob* job, | |
60 const GURL& location, | |
61 int status_code)); | |
62 MOCK_METHOD3(OnBytesRead, void(URLRequestJob* job, | |
63 const char* buf, | |
64 int byte_count)); | |
65 }; | |
66 | |
67 // A URLRequestJob that returns static content for given URLs. We do | |
68 // not use URLRequestTestJob here because URLRequestTestJob fakes | |
69 // async operations by calling ReadRawData synchronously in an async | |
70 // callback. This test requires a URLRequestJob that returns false for | |
71 // async reads, in order to exercise the real async read codepath. | |
72 class URLRequestJobTrackerTestJob : public URLRequestJob { | |
73 public: | |
74 URLRequestJobTrackerTestJob(URLRequest* request, bool async_reads) | |
75 : URLRequestJob(request), async_reads_(async_reads) {} | |
76 | |
77 void Start() { | |
78 ASSERT_TRUE(GetResponseBody(request_->url(), &response_data_)); | |
79 | |
80 // Start reading asynchronously so that all error reporting and data | |
81 // callbacks happen as they would for network requests. | |
82 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
83 this, &URLRequestJobTrackerTestJob::NotifyHeadersComplete)); | |
84 } | |
85 | |
86 bool ReadRawData(IOBuffer* buf, int buf_size, | |
87 int *bytes_read) { | |
88 const size_t bytes_to_read = std::min( | |
89 response_data_.size(), static_cast<size_t>(buf_size)); | |
90 | |
91 // Regardless of whether we're performing a sync or async read, | |
92 // copy the data into the caller's buffer now. That way we don't | |
93 // have to hold on to the buffers in the async case. | |
94 memcpy(buf->data(), response_data_.data(), bytes_to_read); | |
95 response_data_.erase(0, bytes_to_read); | |
96 | |
97 if (async_reads_) { | |
98 SetStatus(URLRequestStatus(URLRequestStatus::IO_PENDING, 0)); | |
99 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | |
100 this, &URLRequestJobTrackerTestJob::OnReadCompleted, | |
101 bytes_to_read)); | |
102 } else { | |
103 SetStatus(URLRequestStatus()); | |
104 *bytes_read = bytes_to_read; | |
105 } | |
106 return !async_reads_; | |
107 } | |
108 | |
109 void OnReadCompleted(int status) { | |
110 if (status == 0) { | |
111 NotifyDone(URLRequestStatus()); | |
112 } else if (status > 0) { | |
113 SetStatus(URLRequestStatus()); | |
114 } else { | |
115 ASSERT_FALSE(true) << "Unexpected OnReadCompleted callback."; | |
116 } | |
117 | |
118 NotifyReadComplete(status); | |
119 } | |
120 | |
121 Filter* SetupFilter() const { | |
122 return request_->url().spec() == "test:compressed" | |
123 ? Filter::GZipFactory() : NULL; | |
124 } | |
125 | |
126 // The data to send, will be set in Start(). | |
127 std::string response_data_; | |
128 | |
129 // Should reads be synchronous or asynchronous? | |
130 const bool async_reads_; | |
131 }; | |
132 | |
133 // Google Mock Matcher to check two URLRequestStatus instances for | |
134 // equality. | |
135 MATCHER_P(StatusEq, other, "") { | |
136 return (arg.status() == other.status() && | |
137 arg.os_error() == other.os_error()); | |
138 } | |
139 | |
140 // Google Mock Matcher to check that two blocks of memory are equal. | |
141 MATCHER_P2(MemEq, other, len, "") { | |
142 return memcmp(arg, other, len) == 0; | |
143 } | |
144 | |
145 class URLRequestJobTrackerTest : public PlatformTest { | |
146 protected: | |
147 static void SetUpTestCase() { | |
148 URLRequest::RegisterProtocolFactory("test", &Factory); | |
149 } | |
150 | |
151 virtual void SetUp() { | |
152 g_async_reads = true; | |
153 } | |
154 | |
155 void AssertJobTrackerCallbacks(const char* url) { | |
156 InSequence seq; | |
157 testing::StrictMock<MockJobObserver> observer; | |
158 | |
159 const GURL gurl(url); | |
160 std::string body; | |
161 ASSERT_TRUE(GetResponseBody(gurl, &body)); | |
162 | |
163 // We expect to receive one call for each method on the JobObserver, | |
164 // in the following order: | |
165 EXPECT_CALL(observer, OnJobAdded(NotNull())); | |
166 EXPECT_CALL(observer, OnBytesRead(NotNull(), | |
167 MemEq(body.data(), body.size()), | |
168 Eq(static_cast<int>(body.size())))); | |
169 EXPECT_CALL(observer, OnJobDone(NotNull(), | |
170 StatusEq(URLRequestStatus()))); | |
171 EXPECT_CALL(observer, OnJobRemoved(NotNull())); | |
172 | |
173 // Attach our observer and perform the resource fetch. | |
174 g_url_request_job_tracker.AddObserver(&observer); | |
175 Fetch(gurl); | |
176 g_url_request_job_tracker.RemoveObserver(&observer); | |
177 } | |
178 | |
179 void Fetch(const GURL& url) { | |
180 TestDelegate d; | |
181 { | |
182 URLRequest request(url, &d); | |
183 request.Start(); | |
184 MessageLoop::current()->RunAllPending(); | |
185 } | |
186 | |
187 // A few sanity checks to make sure that the delegate also | |
188 // receives the expected callbacks. | |
189 EXPECT_EQ(1, d.response_started_count()); | |
190 EXPECT_FALSE(d.received_data_before_response()); | |
191 EXPECT_STREQ(kBasic, d.data_received().c_str()); | |
192 } | |
193 | |
194 static URLRequest::ProtocolFactory Factory; | |
195 static bool g_async_reads; | |
196 }; | |
197 | |
198 // static | |
199 URLRequestJob* URLRequestJobTrackerTest::Factory( | |
200 URLRequest* request, | |
201 const std::string& scheme) { | |
202 return new URLRequestJobTrackerTestJob(request, g_async_reads); | |
203 } | |
204 | |
205 // static | |
206 bool URLRequestJobTrackerTest::g_async_reads = true; | |
207 | |
208 TEST_F(URLRequestJobTrackerTest, BasicAsync) { | |
209 g_async_reads = true; | |
210 AssertJobTrackerCallbacks("test:basic"); | |
211 } | |
212 | |
213 TEST_F(URLRequestJobTrackerTest, BasicSync) { | |
214 g_async_reads = false; | |
215 AssertJobTrackerCallbacks("test:basic"); | |
216 } | |
217 | |
218 TEST_F(URLRequestJobTrackerTest, CompressedAsync) { | |
219 g_async_reads = true; | |
220 AssertJobTrackerCallbacks("test:compressed"); | |
221 } | |
222 | |
223 TEST_F(URLRequestJobTrackerTest, CompressedSync) { | |
224 g_async_reads = false; | |
225 AssertJobTrackerCallbacks("test:compressed"); | |
226 } | |
227 | |
228 } // namespace | |
229 } // namespace net | |
OLD | NEW |