| 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 |