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