1 /* 2 * libjingle 3 * Copyright 2004--2011, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #ifndef TALK_BASE_TESTUTILS_H__ 29 #define TALK_BASE_TESTUTILS_H__ 30 31 // Utilities for testing talk_base infrastructure in unittests 32 33 #ifdef LINUX 34 #include <X11/Xlib.h> 35 // X defines a few macros that stomp on types that gunit.h uses. 36 #undef None 37 #undef Bool 38 #endif 39 40 #include <map> 41 #include <vector> 42 #include "talk/base/asyncsocket.h" 43 #include "talk/base/common.h" 44 #include "talk/base/gunit.h" 45 #include "talk/base/nethelpers.h" 46 #include "talk/base/stream.h" 47 #include "talk/base/stringencode.h" 48 #include "talk/base/stringutils.h" 49 #include "talk/base/thread.h" 50 51 namespace testing { 52 53 using namespace talk_base; 54 55 /////////////////////////////////////////////////////////////////////////////// 56 // StreamSink - Monitor asynchronously signalled events from StreamInterface 57 // or AsyncSocket (which should probably be a StreamInterface. 58 /////////////////////////////////////////////////////////////////////////////// 59 60 // Note: Any event that is an error is treaded as SSE_ERROR instead of that 61 // event. 62 63 enum StreamSinkEvent { 64 SSE_OPEN = SE_OPEN, 65 SSE_READ = SE_READ, 66 SSE_WRITE = SE_WRITE, 67 SSE_CLOSE = SE_CLOSE, 68 SSE_ERROR = 16 69 }; 70 71 class StreamSink : public sigslot::has_slots<> { 72 public: 73 void Monitor(StreamInterface* stream) { 74 stream->SignalEvent.connect(this, &StreamSink::OnEvent); 75 events_.erase(stream); 76 } 77 void Unmonitor(StreamInterface* stream) { 78 stream->SignalEvent.disconnect(this); 79 // In case you forgot to unmonitor a previous object with this address 80 events_.erase(stream); 81 } 82 bool Check(StreamInterface* stream, StreamSinkEvent event, bool reset = true) { 83 return DoCheck(stream, event, reset); 84 } 85 int Events(StreamInterface* stream, bool reset = true) { 86 return DoEvents(stream, reset); 87 } 88 89 void Monitor(AsyncSocket* socket) { 90 socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent); 91 socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent); 92 socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent); 93 socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent); 94 // In case you forgot to unmonitor a previous object with this address 95 events_.erase(socket); 96 } 97 void Unmonitor(AsyncSocket* socket) { 98 socket->SignalConnectEvent.disconnect(this); 99 socket->SignalReadEvent.disconnect(this); 100 socket->SignalWriteEvent.disconnect(this); 101 socket->SignalCloseEvent.disconnect(this); 102 events_.erase(socket); 103 } 104 bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) { 105 return DoCheck(socket, event, reset); 106 } 107 int Events(AsyncSocket* socket, bool reset = true) { 108 return DoEvents(socket, reset); 109 } 110 111 private: 112 typedef std::map<void*,int> EventMap; 113 114 void OnEvent(StreamInterface* stream, int events, int error) { 115 if (error) { 116 events = SSE_ERROR; 117 } 118 AddEvents(stream, events); 119 } 120 void OnConnectEvent(AsyncSocket* socket) { 121 AddEvents(socket, SSE_OPEN); 122 } 123 void OnReadEvent(AsyncSocket* socket) { 124 AddEvents(socket, SSE_READ); 125 } 126 void OnWriteEvent(AsyncSocket* socket) { 127 AddEvents(socket, SSE_WRITE); 128 } 129 void OnCloseEvent(AsyncSocket* socket, int error) { 130 AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR); 131 } 132 133 void AddEvents(void* obj, int events) { 134 EventMap::iterator it = events_.find(obj); 135 if (events_.end() == it) { 136 events_.insert(EventMap::value_type(obj, events)); 137 } else { 138 it->second |= events; 139 } 140 } 141 bool DoCheck(void* obj, StreamSinkEvent event, bool reset) { 142 EventMap::iterator it = events_.find(obj); 143 if ((events_.end() == it) || (0 == (it->second & event))) { 144 return false; 145 } 146 if (reset) { 147 it->second &= ~event; 148 } 149 return true; 150 } 151 int DoEvents(void* obj, bool reset) { 152 EventMap::iterator it = events_.find(obj); 153 if (events_.end() == it) 154 return 0; 155 int events = it->second; 156 if (reset) { 157 it->second = 0; 158 } 159 return events; 160 } 161 162 EventMap events_; 163 }; 164 165 /////////////////////////////////////////////////////////////////////////////// 166 // StreamSource - Implements stream interface and simulates asynchronous 167 // events on the stream, without a network. Also buffers written data. 168 /////////////////////////////////////////////////////////////////////////////// 169 170 class StreamSource : public StreamInterface { 171 public: 172 StreamSource() { 173 Clear(); 174 } 175 176 void Clear() { 177 readable_data_.clear(); 178 written_data_.clear(); 179 state_ = SS_CLOSED; 180 read_block_ = 0; 181 write_block_ = SIZE_UNKNOWN; 182 } 183 void QueueString(const char* data) { 184 QueueData(data, strlen(data)); 185 } 186 void QueueStringF(const char* format, ...) { 187 va_list args; 188 va_start(args, format); 189 char buffer[1024]; 190 size_t len = vsprintfn(buffer, sizeof(buffer), format, args); 191 ASSERT(len < sizeof(buffer) - 1); 192 va_end(args); 193 QueueData(buffer, len); 194 } 195 void QueueData(const char* data, size_t len) { 196 readable_data_.insert(readable_data_.end(), data, data + len); 197 if ((SS_OPEN == state_) && (readable_data_.size() == len)) { 198 SignalEvent(this, SE_READ, 0); 199 } 200 } 201 std::string ReadData() { 202 std::string data; 203 // avoid accessing written_data_[0] if it is undefined 204 if (written_data_.size() > 0) { 205 data.insert(0, &written_data_[0], written_data_.size()); 206 } 207 written_data_.clear(); 208 return data; 209 } 210 void SetState(StreamState state) { 211 int events = 0; 212 if ((SS_OPENING == state_) && (SS_OPEN == state)) { 213 events |= SE_OPEN; 214 if (!readable_data_.empty()) { 215 events |= SE_READ; 216 } 217 } else if ((SS_CLOSED != state_) && (SS_CLOSED == state)) { 218 events |= SE_CLOSE; 219 } 220 state_ = state; 221 if (events) { 222 SignalEvent(this, events, 0); 223 } 224 } 225 // Will cause Read to block when there are pos bytes in the read queue. 226 void SetReadBlock(size_t pos) { read_block_ = pos; } 227 // Will cause Write to block when there are pos bytes in the write queue. 228 void SetWriteBlock(size_t pos) { write_block_ = pos; } 229 230 virtual StreamState GetState() const { return state_; } 231 virtual StreamResult Read(void* buffer, size_t buffer_len, 232 size_t* read, int* error) { 233 if (SS_CLOSED == state_) { 234 if (error) *error = -1; 235 return SR_ERROR; 236 } 237 if ((SS_OPENING == state_) || (readable_data_.size() <= read_block_)) { 238 return SR_BLOCK; 239 } 240 size_t count = _min(buffer_len, readable_data_.size() - read_block_); 241 memcpy(buffer, &readable_data_[0], count); 242 size_t new_size = readable_data_.size() - count; 243 // Avoid undefined access beyond the last element of the vector. 244 // This only happens when new_size is 0. 245 if (count < readable_data_.size()) { 246 memmove(&readable_data_[0], &readable_data_[count], new_size); 247 } 248 readable_data_.resize(new_size); 249 if (read) *read = count; 250 return SR_SUCCESS; 251 } 252 virtual StreamResult Write(const void* data, size_t data_len, 253 size_t* written, int* error) { 254 if (SS_CLOSED == state_) { 255 if (error) *error = -1; 256 return SR_ERROR; 257 } 258 if (SS_OPENING == state_) { 259 return SR_BLOCK; 260 } 261 if (SIZE_UNKNOWN != write_block_) { 262 if (written_data_.size() >= write_block_) { 263 return SR_BLOCK; 264 } 265 if (data_len > (write_block_ - written_data_.size())) { 266 data_len = write_block_ - written_data_.size(); 267 } 268 } 269 if (written) *written = data_len; 270 const char* cdata = static_cast<const char*>(data); 271 written_data_.insert(written_data_.end(), cdata, cdata + data_len); 272 return SR_SUCCESS; 273 } 274 virtual void Close() { state_ = SS_CLOSED; } 275 276 private: 277 typedef std::vector<char> Buffer; 278 Buffer readable_data_, written_data_; 279 StreamState state_; 280 size_t read_block_, write_block_; 281 }; 282 283 /////////////////////////////////////////////////////////////////////////////// 284 // SocketTestClient 285 // Creates a simulated client for testing. Works on real and virtual networks. 286 /////////////////////////////////////////////////////////////////////////////// 287 288 class SocketTestClient : public sigslot::has_slots<> { 289 public: 290 SocketTestClient() { 291 Init(NULL, AF_INET); 292 } 293 SocketTestClient(AsyncSocket* socket) { 294 Init(socket, socket->GetLocalAddress().family()); 295 } 296 SocketTestClient(const SocketAddress& address) { 297 Init(NULL, address.family()); 298 socket_->Connect(address); 299 } 300 301 AsyncSocket* socket() { return socket_.get(); } 302 303 void QueueString(const char* data) { 304 QueueData(data, strlen(data)); 305 } 306 void QueueStringF(const char* format, ...) { 307 va_list args; 308 va_start(args, format); 309 char buffer[1024]; 310 size_t len = vsprintfn(buffer, sizeof(buffer), format, args); 311 ASSERT(len < sizeof(buffer) - 1); 312 va_end(args); 313 QueueData(buffer, len); 314 } 315 void QueueData(const char* data, size_t len) { 316 send_buffer_.insert(send_buffer_.end(), data, data + len); 317 if (Socket::CS_CONNECTED == socket_->GetState()) { 318 Flush(); 319 } 320 } 321 std::string ReadData() { 322 std::string data(&recv_buffer_[0], recv_buffer_.size()); 323 recv_buffer_.clear(); 324 return data; 325 } 326 327 bool IsConnected() const { 328 return (Socket::CS_CONNECTED == socket_->GetState()); 329 } 330 bool IsClosed() const { 331 return (Socket::CS_CLOSED == socket_->GetState()); 332 } 333 334 private: 335 typedef std::vector<char> Buffer; 336 337 void Init(AsyncSocket* socket, int family) { 338 if (!socket) { 339 socket = Thread::Current()->socketserver() 340 ->CreateAsyncSocket(family, SOCK_STREAM); 341 } 342 socket_.reset(socket); 343 socket_->SignalConnectEvent.connect(this, 344 &SocketTestClient::OnConnectEvent); 345 socket_->SignalReadEvent.connect(this, &SocketTestClient::OnReadEvent); 346 socket_->SignalWriteEvent.connect(this, &SocketTestClient::OnWriteEvent); 347 socket_->SignalCloseEvent.connect(this, &SocketTestClient::OnCloseEvent); 348 } 349 350 void Flush() { 351 size_t sent = 0; 352 while (sent < send_buffer_.size()) { 353 int result = socket_->Send(&send_buffer_[sent], 354 send_buffer_.size() - sent); 355 if (result > 0) { 356 sent += result; 357 } else { 358 break; 359 } 360 } 361 size_t new_size = send_buffer_.size() - sent; 362 memmove(&send_buffer_[0], &send_buffer_[sent], new_size); 363 send_buffer_.resize(new_size); 364 } 365 366 void OnConnectEvent(AsyncSocket* socket) { 367 if (!send_buffer_.empty()) { 368 Flush(); 369 } 370 } 371 void OnReadEvent(AsyncSocket* socket) { 372 char data[64 * 1024]; 373 int result = socket_->Recv(data, ARRAY_SIZE(data)); 374 if (result > 0) { 375 recv_buffer_.insert(recv_buffer_.end(), data, data + result); 376 } 377 } 378 void OnWriteEvent(AsyncSocket* socket) { 379 if (!send_buffer_.empty()) { 380 Flush(); 381 } 382 } 383 void OnCloseEvent(AsyncSocket* socket, int error) { 384 } 385 386 scoped_ptr<AsyncSocket> socket_; 387 Buffer send_buffer_, recv_buffer_; 388 }; 389 390 /////////////////////////////////////////////////////////////////////////////// 391 // SocketTestServer 392 // Creates a simulated server for testing. Works on real and virtual networks. 393 /////////////////////////////////////////////////////////////////////////////// 394 395 class SocketTestServer : public sigslot::has_slots<> { 396 public: 397 SocketTestServer(const SocketAddress& address) 398 : socket_(Thread::Current()->socketserver() 399 ->CreateAsyncSocket(address.family(), SOCK_STREAM)) 400 { 401 socket_->SignalReadEvent.connect(this, &SocketTestServer::OnReadEvent); 402 socket_->Bind(address); 403 socket_->Listen(5); 404 } 405 virtual ~SocketTestServer() { 406 clear(); 407 } 408 409 size_t size() const { return clients_.size(); } 410 SocketTestClient* client(size_t index) const { return clients_[index]; } 411 SocketTestClient* operator[](size_t index) const { return client(index); } 412 413 void clear() { 414 for (size_t i=0; i<clients_.size(); ++i) { 415 delete clients_[i]; 416 } 417 clients_.clear(); 418 } 419 420 private: 421 void OnReadEvent(AsyncSocket* socket) { 422 AsyncSocket* accepted = 423 static_cast<AsyncSocket*>(socket_->Accept(NULL)); 424 if (!accepted) 425 return; 426 clients_.push_back(new SocketTestClient(accepted)); 427 } 428 429 scoped_ptr<AsyncSocket> socket_; 430 std::vector<SocketTestClient*> clients_; 431 }; 432 433 /////////////////////////////////////////////////////////////////////////////// 434 // Generic Utilities 435 /////////////////////////////////////////////////////////////////////////////// 436 437 inline bool ReadFile(const char* filename, std::string* contents) { 438 FILE* fp = fopen(filename, "rb"); 439 if (!fp) 440 return false; 441 char buffer[1024*64]; 442 size_t read; 443 contents->clear(); 444 while ((read = fread(buffer, 1, sizeof(buffer), fp))) { 445 contents->append(buffer, read); 446 } 447 bool success = (0 != feof(fp)); 448 fclose(fp); 449 return success; 450 } 451 452 /////////////////////////////////////////////////////////////////////////////// 453 // Unittest predicates which are similar to STREQ, but for raw memory 454 /////////////////////////////////////////////////////////////////////////////// 455 456 inline AssertionResult CmpHelperMemEq(const char* expected_expression, 457 const char* expected_length_expression, 458 const char* actual_expression, 459 const char* actual_length_expression, 460 const void* expected, 461 size_t expected_length, 462 const void* actual, 463 size_t actual_length) 464 { 465 if ((expected_length == actual_length) 466 && (0 == memcmp(expected, actual, expected_length))) { 467 return AssertionSuccess(); 468 } 469 470 Message msg; 471 msg << "Value of: " << actual_expression 472 << " [" << actual_length_expression << "]"; 473 if (true) { //!actual_value.Equals(actual_expression)) { 474 size_t buffer_size = actual_length * 2 + 1; 475 char* buffer = STACK_ARRAY(char, buffer_size); 476 hex_encode(buffer, buffer_size, 477 reinterpret_cast<const char*>(actual), actual_length); 478 msg << "\n Actual: " << buffer << " [" << actual_length << "]"; 479 } 480 481 msg << "\nExpected: " << expected_expression 482 << " [" << expected_length_expression << "]"; 483 if (true) { //!expected_value.Equals(expected_expression)) { 484 size_t buffer_size = expected_length * 2 + 1; 485 char* buffer = STACK_ARRAY(char, buffer_size); 486 hex_encode(buffer, buffer_size, 487 reinterpret_cast<const char*>(expected), expected_length); 488 msg << "\nWhich is: " << buffer << " [" << expected_length << "]"; 489 } 490 491 return AssertionFailure(msg); 492 } 493 494 inline AssertionResult CmpHelperFileEq(const char* expected_expression, 495 const char* expected_length_expression, 496 const char* actual_filename, 497 const void* expected, 498 size_t expected_length, 499 const char* filename) 500 { 501 std::string contents; 502 if (!ReadFile(filename, &contents)) { 503 Message msg; 504 msg << "File '" << filename << "' could not be read."; 505 return AssertionFailure(msg); 506 } 507 return CmpHelperMemEq(expected_expression, expected_length_expression, 508 actual_filename, "", 509 expected, expected_length, 510 contents.c_str(), contents.size()); 511 } 512 513 #define EXPECT_MEMEQ(expected, expected_length, actual, actual_length) \ 514 EXPECT_PRED_FORMAT4(::testing::CmpHelperMemEq, expected, expected_length, \ 515 actual, actual_length) 516 517 #define ASSERT_MEMEQ(expected, expected_length, actual, actual_length) \ 518 ASSERT_PRED_FORMAT4(::testing::CmpHelperMemEq, expected, expected_length, \ 519 actual, actual_length) 520 521 #define EXPECT_FILEEQ(expected, expected_length, filename) \ 522 EXPECT_PRED_FORMAT3(::testing::CmpHelperFileEq, expected, expected_length, \ 523 filename) 524 525 #define ASSERT_FILEEQ(expected, expected_length, filename) \ 526 ASSERT_PRED_FORMAT3(::testing::CmpHelperFileEq, expected, expected_length, \ 527 filename) 528 529 /////////////////////////////////////////////////////////////////////////////// 530 // Helpers for initializing constant memory with integers in a particular byte 531 // order 532 /////////////////////////////////////////////////////////////////////////////// 533 534 #define BYTE_CAST(x) static_cast<uint8>((x) & 0xFF) 535 536 // Declare a N-bit integer as a little-endian sequence of bytes 537 #define LE16(x) BYTE_CAST(((uint16)x) >> 0), BYTE_CAST(((uint16)x) >> 8) 538 539 #define LE32(x) BYTE_CAST(((uint32)x) >> 0), BYTE_CAST(((uint32)x) >> 8), \ 540 BYTE_CAST(((uint32)x) >> 16), BYTE_CAST(((uint32)x) >> 24) 541 542 #define LE64(x) BYTE_CAST(((uint64)x) >> 0), BYTE_CAST(((uint64)x) >> 8), \ 543 BYTE_CAST(((uint64)x) >> 16), BYTE_CAST(((uint64)x) >> 24), \ 544 BYTE_CAST(((uint64)x) >> 32), BYTE_CAST(((uint64)x) >> 40), \ 545 BYTE_CAST(((uint64)x) >> 48), BYTE_CAST(((uint64)x) >> 56) 546 547 // Declare a N-bit integer as a big-endian (Internet) sequence of bytes 548 #define BE16(x) BYTE_CAST(((uint16)x) >> 8), BYTE_CAST(((uint16)x) >> 0) 549 550 #define BE32(x) BYTE_CAST(((uint32)x) >> 24), BYTE_CAST(((uint32)x) >> 16), \ 551 BYTE_CAST(((uint32)x) >> 8), BYTE_CAST(((uint32)x) >> 0) 552 553 #define BE64(x) BYTE_CAST(((uint64)x) >> 56), BYTE_CAST(((uint64)x) >> 48), \ 554 BYTE_CAST(((uint64)x) >> 40), BYTE_CAST(((uint64)x) >> 32), \ 555 BYTE_CAST(((uint64)x) >> 24), BYTE_CAST(((uint64)x) >> 16), \ 556 BYTE_CAST(((uint64)x) >> 8), BYTE_CAST(((uint64)x) >> 0) 557 558 // Declare a N-bit integer as a this-endian (local machine) sequence of bytes 559 #ifndef BIG_ENDIAN 560 #define BIG_ENDIAN 1 561 #endif // BIG_ENDIAN 562 563 #if BIG_ENDIAN 564 #define TE16 BE16 565 #define TE32 BE32 566 #define TE64 BE64 567 #else // !BIG_ENDIAN 568 #define TE16 LE16 569 #define TE32 LE32 570 #define TE64 LE64 571 #endif // !BIG_ENDIAN 572 573 /////////////////////////////////////////////////////////////////////////////// 574 575 // Helpers for determining if X/screencasting is available (on linux). 576 577 #define MAYBE_SKIP_SCREENCAST_TEST() \ 578 if (!testing::IsScreencastingAvailable()) { \ 579 LOG(LS_WARNING) << "Skipping test, since it doesn't have the requisite " \ 580 << "X environment for screen capture."; \ 581 return; \ 582 } \ 583 584 #ifdef LINUX 585 struct XDisplay { 586 XDisplay() : display_(XOpenDisplay(NULL)) { } 587 ~XDisplay() { if (display_) XCloseDisplay(display_); } 588 bool IsValid() const { return display_ != NULL; } 589 operator Display*() { return display_; } 590 private: 591 Display* display_; 592 }; 593 #endif 594 595 // Returns true if screencasting is available. When false, anything that uses 596 // screencasting features may fail. 597 inline bool IsScreencastingAvailable() { 598 #ifdef LINUX 599 XDisplay display; 600 if (!display.IsValid()) { 601 LOG(LS_WARNING) << "No X Display available."; 602 return false; 603 } 604 #endif 605 return true; 606 } 607 } // namespace testing 608 609 #endif // TALK_BASE_TESTUTILS_H__ 610