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