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