1 // Copyright (c) 2006-2009 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 #ifndef NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_ 6 #define NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_ 7 8 #include "net/http/http_transaction.h" 9 10 #include <algorithm> 11 #include <string> 12 13 #include "base/compiler_specific.h" 14 #include "base/message_loop.h" 15 #include "base/string_util.h" 16 #include "net/base/io_buffer.h" 17 #include "net/base/net_errors.h" 18 #include "net/base/load_flags.h" 19 #include "net/base/test_completion_callback.h" 20 #include "net/disk_cache/disk_cache.h" 21 #include "net/http/http_cache.h" 22 #include "net/http/http_request_info.h" 23 #include "net/http/http_response_headers.h" 24 #include "net/http/http_response_info.h" 25 26 //----------------------------------------------------------------------------- 27 // mock transaction data 28 29 // these flags may be combined to form the test_mode field 30 enum { 31 TEST_MODE_NORMAL = 0, 32 TEST_MODE_SYNC_NET_START = 1 << 0, 33 TEST_MODE_SYNC_NET_READ = 1 << 1, 34 TEST_MODE_SYNC_CACHE_START = 1 << 2, 35 TEST_MODE_SYNC_CACHE_READ = 1 << 3, 36 TEST_MODE_SYNC_CACHE_WRITE = 1 << 4, 37 TEST_MODE_SYNC_ALL = TEST_MODE_SYNC_NET_START | TEST_MODE_SYNC_NET_READ | 38 TEST_MODE_SYNC_CACHE_START | TEST_MODE_SYNC_CACHE_READ | 39 TEST_MODE_SYNC_CACHE_WRITE 40 }; 41 42 typedef void (*MockTransactionHandler)(const net::HttpRequestInfo* request, 43 std::string* response_status, 44 std::string* response_headers, 45 std::string* response_data); 46 47 struct MockTransaction { 48 const char* url; 49 const char* method; 50 // If |request_time| is unspecified, the current time will be used. 51 base::Time request_time; 52 const char* request_headers; 53 int load_flags; 54 const char* status; 55 const char* response_headers; 56 // If |response_time| is unspecified, the current time will be used. 57 base::Time response_time; 58 const char* data; 59 int test_mode; 60 MockTransactionHandler handler; 61 int cert_status; 62 }; 63 64 extern const MockTransaction kSimpleGET_Transaction; 65 extern const MockTransaction kSimplePOST_Transaction; 66 extern const MockTransaction kTypicalGET_Transaction; 67 extern const MockTransaction kETagGET_Transaction; 68 extern const MockTransaction kRangeGET_Transaction; 69 70 // returns the mock transaction for the given URL 71 const MockTransaction* FindMockTransaction(const GURL& url); 72 73 // Add/Remove a mock transaction that can be accessed via FindMockTransaction. 74 // There can be only one MockTransaction associated with a given URL. 75 void AddMockTransaction(const MockTransaction* trans); 76 void RemoveMockTransaction(const MockTransaction* trans); 77 78 struct ScopedMockTransaction : MockTransaction { ScopedMockTransactionScopedMockTransaction79 ScopedMockTransaction() { 80 AddMockTransaction(this); 81 } ScopedMockTransactionScopedMockTransaction82 explicit ScopedMockTransaction(const MockTransaction& t) 83 : MockTransaction(t) { 84 AddMockTransaction(this); 85 } ~ScopedMockTransactionScopedMockTransaction86 ~ScopedMockTransaction() { 87 RemoveMockTransaction(this); 88 } 89 }; 90 91 //----------------------------------------------------------------------------- 92 // mock http request 93 94 class MockHttpRequest : public net::HttpRequestInfo { 95 public: MockHttpRequest(const MockTransaction & t)96 explicit MockHttpRequest(const MockTransaction& t) { 97 url = GURL(t.url); 98 method = t.method; 99 extra_headers = t.request_headers; 100 load_flags = t.load_flags; 101 } 102 }; 103 104 //----------------------------------------------------------------------------- 105 // use this class to test completely consuming a transaction 106 107 class TestTransactionConsumer : public CallbackRunner< Tuple1<int> > { 108 public: TestTransactionConsumer(net::HttpTransactionFactory * factory)109 explicit TestTransactionConsumer(net::HttpTransactionFactory* factory) 110 : state_(IDLE), 111 trans_(NULL), 112 error_(net::OK) { 113 // Disregard the error code. 114 factory->CreateTransaction(&trans_); 115 ++quit_counter_; 116 } 117 ~TestTransactionConsumer()118 ~TestTransactionConsumer() { 119 } 120 Start(const net::HttpRequestInfo * request,net::LoadLog * load_log)121 void Start(const net::HttpRequestInfo* request, net::LoadLog* load_log) { 122 state_ = STARTING; 123 int result = trans_->Start(request, this, load_log); 124 if (result != net::ERR_IO_PENDING) 125 DidStart(result); 126 } 127 is_done()128 bool is_done() const { return state_ == DONE; } error()129 int error() const { return error_; } 130 response_info()131 const net::HttpResponseInfo* response_info() const { 132 return trans_->GetResponseInfo(); 133 } content()134 const std::string& content() const { return content_; } 135 136 private: 137 // Callback implementation: RunWithParams(const Tuple1<int> & params)138 virtual void RunWithParams(const Tuple1<int>& params) { 139 int result = params.a; 140 switch (state_) { 141 case STARTING: 142 DidStart(result); 143 break; 144 case READING: 145 DidRead(result); 146 break; 147 default: 148 NOTREACHED(); 149 } 150 } 151 DidStart(int result)152 void DidStart(int result) { 153 if (result != net::OK) { 154 DidFinish(result); 155 } else { 156 Read(); 157 } 158 } 159 DidRead(int result)160 void DidRead(int result) { 161 if (result <= 0) { 162 DidFinish(result); 163 } else { 164 content_.append(read_buf_->data(), result); 165 Read(); 166 } 167 } 168 DidFinish(int result)169 void DidFinish(int result) { 170 state_ = DONE; 171 error_ = result; 172 if (--quit_counter_ == 0) 173 MessageLoop::current()->Quit(); 174 } 175 Read()176 void Read() { 177 state_ = READING; 178 read_buf_ = new net::IOBuffer(1024); 179 int result = trans_->Read(read_buf_, 1024, this); 180 if (result != net::ERR_IO_PENDING) 181 DidRead(result); 182 } 183 184 enum State { 185 IDLE, 186 STARTING, 187 READING, 188 DONE 189 } state_; 190 191 scoped_ptr<net::HttpTransaction> trans_; 192 std::string content_; 193 scoped_refptr<net::IOBuffer> read_buf_; 194 int error_; 195 196 static int quit_counter_; 197 }; 198 199 //----------------------------------------------------------------------------- 200 // mock network layer 201 202 // This transaction class inspects the available set of mock transactions to 203 // find data for the request URL. It supports IO operations that complete 204 // synchronously or asynchronously to help exercise different code paths in the 205 // HttpCache implementation. 206 class MockNetworkTransaction : public net::HttpTransaction { 207 public: MockNetworkTransaction()208 MockNetworkTransaction() : 209 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), data_cursor_(0) { 210 } 211 Start(const net::HttpRequestInfo * request,net::CompletionCallback * callback,net::LoadLog * load_log)212 virtual int Start(const net::HttpRequestInfo* request, 213 net::CompletionCallback* callback, 214 net::LoadLog* load_log) { 215 const MockTransaction* t = FindMockTransaction(request->url); 216 if (!t) 217 return net::ERR_FAILED; 218 219 std::string resp_status = t->status; 220 std::string resp_headers = t->response_headers; 221 std::string resp_data = t->data; 222 if (t->handler) 223 (t->handler)(request, &resp_status, &resp_headers, &resp_data); 224 225 std::string header_data = 226 StringPrintf("%s\n%s\n", resp_status.c_str(), resp_headers.c_str()); 227 std::replace(header_data.begin(), header_data.end(), '\n', '\0'); 228 229 response_.request_time = base::Time::Now(); 230 if (!t->request_time.is_null()) 231 response_.request_time = t->request_time; 232 233 response_.was_cached = false; 234 235 response_.response_time = base::Time::Now(); 236 if (!t->response_time.is_null()) 237 response_.response_time = t->response_time; 238 239 response_.headers = new net::HttpResponseHeaders(header_data); 240 response_.ssl_info.cert_status = t->cert_status; 241 data_ = resp_data; 242 test_mode_ = t->test_mode; 243 244 if (test_mode_ & TEST_MODE_SYNC_NET_START) 245 return net::OK; 246 247 CallbackLater(callback, net::OK); 248 return net::ERR_IO_PENDING; 249 } 250 RestartIgnoringLastError(net::CompletionCallback * callback)251 virtual int RestartIgnoringLastError(net::CompletionCallback* callback) { 252 return net::ERR_FAILED; 253 } 254 RestartWithCertificate(net::X509Certificate * client_cert,net::CompletionCallback * callback)255 virtual int RestartWithCertificate(net::X509Certificate* client_cert, 256 net::CompletionCallback* callback) { 257 return net::ERR_FAILED; 258 } 259 RestartWithAuth(const std::wstring & username,const std::wstring & password,net::CompletionCallback * callback)260 virtual int RestartWithAuth(const std::wstring& username, 261 const std::wstring& password, 262 net::CompletionCallback* callback) { 263 return net::ERR_FAILED; 264 } 265 IsReadyToRestartForAuth()266 virtual bool IsReadyToRestartForAuth() { 267 return false; 268 } 269 Read(net::IOBuffer * buf,int buf_len,net::CompletionCallback * callback)270 virtual int Read(net::IOBuffer* buf, int buf_len, 271 net::CompletionCallback* callback) { 272 int data_len = static_cast<int>(data_.size()); 273 int num = std::min(buf_len, data_len - data_cursor_); 274 if (num) { 275 memcpy(buf->data(), data_.data() + data_cursor_, num); 276 data_cursor_ += num; 277 } 278 if (test_mode_ & TEST_MODE_SYNC_NET_READ) 279 return num; 280 281 CallbackLater(callback, num); 282 return net::ERR_IO_PENDING; 283 } 284 GetResponseInfo()285 virtual const net::HttpResponseInfo* GetResponseInfo() const { 286 return &response_; 287 } 288 GetLoadState()289 virtual net::LoadState GetLoadState() const { 290 NOTREACHED() << "define some mock state transitions"; 291 return net::LOAD_STATE_IDLE; 292 } 293 GetUploadProgress()294 virtual uint64 GetUploadProgress() const { 295 return 0; 296 } 297 298 private: CallbackLater(net::CompletionCallback * callback,int result)299 void CallbackLater(net::CompletionCallback* callback, int result) { 300 MessageLoop::current()->PostTask(FROM_HERE, task_factory_.NewRunnableMethod( 301 &MockNetworkTransaction::RunCallback, callback, result)); 302 } RunCallback(net::CompletionCallback * callback,int result)303 void RunCallback(net::CompletionCallback* callback, int result) { 304 callback->Run(result); 305 } 306 307 ScopedRunnableMethodFactory<MockNetworkTransaction> task_factory_; 308 net::HttpResponseInfo response_; 309 std::string data_; 310 int data_cursor_; 311 int test_mode_; 312 }; 313 314 class MockNetworkLayer : public net::HttpTransactionFactory { 315 public: MockNetworkLayer()316 MockNetworkLayer() : transaction_count_(0) { 317 } 318 CreateTransaction(scoped_ptr<net::HttpTransaction> * trans)319 virtual int CreateTransaction(scoped_ptr<net::HttpTransaction>* trans) { 320 transaction_count_++; 321 trans->reset(new MockNetworkTransaction()); 322 return net::OK; 323 } 324 GetCache()325 virtual net::HttpCache* GetCache() { 326 return NULL; 327 } 328 GetSession()329 virtual net::HttpNetworkSession* GetSession() { 330 return NULL; 331 } 332 Suspend(bool suspend)333 virtual void Suspend(bool suspend) {} 334 transaction_count()335 int transaction_count() const { return transaction_count_; } 336 337 private: 338 int transaction_count_; 339 }; 340 341 342 //----------------------------------------------------------------------------- 343 // helpers 344 345 // read the transaction completely 346 int ReadTransaction(net::HttpTransaction* trans, std::string* result); 347 348 #endif // NET_HTTP_HTTP_TRANSACTION_UNITTEST_H_ 349