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