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