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 39namespace testing { 40 41using 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 51enum 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 59class 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 158class StreamSource : public StreamInterface { 159public: 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 264private: 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 276class SocketTestClient : public sigslot::has_slots<> { 277public: 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 322private: 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 383class 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 425inline 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. 441inline 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 456inline rtc::Pathname GetGoogle3Directory() { 457 return GetSiblingDirectory("google3"); 458} 459 460inline rtc::Pathname GetTalkDirectory() { 461 return GetSiblingDirectory("talk"); 462} 463 464/////////////////////////////////////////////////////////////////////////////// 465// Unittest predicates which are similar to STREQ, but for raw memory 466/////////////////////////////////////////////////////////////////////////////// 467 468inline 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 506inline 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) 601struct 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. 613inline 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