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