blob: 2ab4a35956a059eacb743915b5ae28a7254cb5b8 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#ifndef RTC_BASE_TESTUTILS_H_
12#define RTC_BASE_TESTUTILS_H_
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020014// Utilities for testing rtc infrastructure in unittests
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020016#include <algorithm>
17#include <map>
18#include <memory>
19#include <vector>
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "rtc_base/asyncsocket.h"
21#include "rtc_base/checks.h"
22#include "rtc_base/gunit.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "rtc_base/stream.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "rtc_base/stringutils.h"
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020025
26namespace webrtc {
27namespace testing {
28
29using namespace rtc;
30
31///////////////////////////////////////////////////////////////////////////////
32// StreamSink - Monitor asynchronously signalled events from StreamInterface
33// or AsyncSocket (which should probably be a StreamInterface.
34///////////////////////////////////////////////////////////////////////////////
35
36// Note: Any event that is an error is treaded as SSE_ERROR instead of that
37// event.
38
39enum StreamSinkEvent {
Yves Gerey665174f2018-06-19 15:03:05 +020040 SSE_OPEN = SE_OPEN,
41 SSE_READ = SE_READ,
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020042 SSE_WRITE = SE_WRITE,
43 SSE_CLOSE = SE_CLOSE,
44 SSE_ERROR = 16
45};
46
47class StreamSink : public sigslot::has_slots<> {
48 public:
Steve Anton9de3aac2017-10-24 10:08:26 -070049 StreamSink();
50 ~StreamSink() override;
51
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020052 void Monitor(StreamInterface* stream) {
Yves Gerey665174f2018-06-19 15:03:05 +020053 stream->SignalEvent.connect(this, &StreamSink::OnEvent);
54 events_.erase(stream);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020055 }
56 void Unmonitor(StreamInterface* stream) {
Yves Gerey665174f2018-06-19 15:03:05 +020057 stream->SignalEvent.disconnect(this);
58 // In case you forgot to unmonitor a previous object with this address
59 events_.erase(stream);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020060 }
Yves Gerey665174f2018-06-19 15:03:05 +020061 bool Check(StreamInterface* stream,
62 StreamSinkEvent event,
63 bool reset = true) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020064 return DoCheck(stream, event, reset);
65 }
66 int Events(StreamInterface* stream, bool reset = true) {
67 return DoEvents(stream, reset);
68 }
69
70 void Monitor(AsyncSocket* socket) {
Yves Gerey665174f2018-06-19 15:03:05 +020071 socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent);
72 socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent);
73 socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent);
74 socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent);
75 // In case you forgot to unmonitor a previous object with this address
76 events_.erase(socket);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020077 }
78 void Unmonitor(AsyncSocket* socket) {
Yves Gerey665174f2018-06-19 15:03:05 +020079 socket->SignalConnectEvent.disconnect(this);
80 socket->SignalReadEvent.disconnect(this);
81 socket->SignalWriteEvent.disconnect(this);
82 socket->SignalCloseEvent.disconnect(this);
83 events_.erase(socket);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020084 }
85 bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) {
86 return DoCheck(socket, event, reset);
87 }
88 int Events(AsyncSocket* socket, bool reset = true) {
89 return DoEvents(socket, reset);
90 }
91
92 private:
Yves Gerey665174f2018-06-19 15:03:05 +020093 typedef std::map<void*, int> EventMap;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020094
95 void OnEvent(StreamInterface* stream, int events, int error) {
96 if (error) {
97 events = SSE_ERROR;
98 }
99 AddEvents(stream, events);
100 }
Yves Gerey665174f2018-06-19 15:03:05 +0200101 void OnConnectEvent(AsyncSocket* socket) { AddEvents(socket, SSE_OPEN); }
102 void OnReadEvent(AsyncSocket* socket) { AddEvents(socket, SSE_READ); }
103 void OnWriteEvent(AsyncSocket* socket) { AddEvents(socket, SSE_WRITE); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200104 void OnCloseEvent(AsyncSocket* socket, int error) {
105 AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR);
106 }
107
108 void AddEvents(void* obj, int events) {
109 EventMap::iterator it = events_.find(obj);
110 if (events_.end() == it) {
111 events_.insert(EventMap::value_type(obj, events));
112 } else {
113 it->second |= events;
114 }
115 }
116 bool DoCheck(void* obj, StreamSinkEvent event, bool reset) {
117 EventMap::iterator it = events_.find(obj);
118 if ((events_.end() == it) || (0 == (it->second & event))) {
119 return false;
120 }
121 if (reset) {
122 it->second &= ~event;
123 }
124 return true;
125 }
126 int DoEvents(void* obj, bool reset) {
127 EventMap::iterator it = events_.find(obj);
128 if (events_.end() == it)
129 return 0;
130 int events = it->second;
131 if (reset) {
132 it->second = 0;
133 }
134 return events;
135 }
136
137 EventMap events_;
138};
139
140///////////////////////////////////////////////////////////////////////////////
141// StreamSource - Implements stream interface and simulates asynchronous
142// events on the stream, without a network. Also buffers written data.
143///////////////////////////////////////////////////////////////////////////////
144
145class StreamSource : public StreamInterface {
Yves Gerey665174f2018-06-19 15:03:05 +0200146 public:
147 StreamSource();
148 ~StreamSource() override;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200149
Yves Gerey665174f2018-06-19 15:03:05 +0200150 void Clear() {
151 readable_data_.clear();
152 written_data_.clear();
153 state_ = SS_CLOSED;
154 read_block_ = 0;
155 write_block_ = SIZE_UNKNOWN;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200156 }
Yves Gerey665174f2018-06-19 15:03:05 +0200157 void QueueString(const char* data) { QueueData(data, strlen(data)); }
Niels Möller00f934a2017-12-14 13:30:46 +0100158#if defined(__GNUC__)
159 // Note: Implicit |this| argument counts as the first argument.
160 __attribute__((__format__(__printf__, 2, 3)))
161#endif
Yves Gerey665174f2018-06-19 15:03:05 +0200162 void
163 QueueStringF(const char* format, ...) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200164 va_list args;
165 va_start(args, format);
166 char buffer[1024];
167 size_t len = vsprintfn(buffer, sizeof(buffer), format, args);
168 RTC_CHECK(len < sizeof(buffer) - 1);
169 va_end(args);
170 QueueData(buffer, len);
171 }
172 void QueueData(const char* data, size_t len) {
173 readable_data_.insert(readable_data_.end(), data, data + len);
174 if ((SS_OPEN == state_) && (readable_data_.size() == len)) {
175 SignalEvent(this, SE_READ, 0);
176 }
177 }
178 std::string ReadData() {
179 std::string data;
180 // avoid accessing written_data_[0] if it is undefined
181 if (written_data_.size() > 0) {
182 data.insert(0, &written_data_[0], written_data_.size());
183 }
184 written_data_.clear();
185 return data;
186 }
187 void SetState(StreamState state) {
188 int events = 0;
189 if ((SS_OPENING == state_) && (SS_OPEN == state)) {
190 events |= SE_OPEN;
191 if (!readable_data_.empty()) {
192 events |= SE_READ;
193 }
194 } else if ((SS_CLOSED != state_) && (SS_CLOSED == state)) {
195 events |= SE_CLOSE;
196 }
197 state_ = state;
198 if (events) {
199 SignalEvent(this, events, 0);
200 }
201 }
202 // Will cause Read to block when there are pos bytes in the read queue.
203 void SetReadBlock(size_t pos) { read_block_ = pos; }
204 // Will cause Write to block when there are pos bytes in the write queue.
205 void SetWriteBlock(size_t pos) { write_block_ = pos; }
206
Steve Anton9de3aac2017-10-24 10:08:26 -0700207 StreamState GetState() const override;
208 StreamResult Read(void* buffer,
209 size_t buffer_len,
210 size_t* read,
211 int* error) override;
212 StreamResult Write(const void* data,
213 size_t data_len,
214 size_t* written,
215 int* error) override;
216 void Close() override;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200217
Steve Anton9de3aac2017-10-24 10:08:26 -0700218 private:
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200219 typedef std::vector<char> Buffer;
220 Buffer readable_data_, written_data_;
221 StreamState state_;
222 size_t read_block_, write_block_;
223};
224
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200225} // namespace testing
226} // namespace webrtc
227
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200228#endif // RTC_BASE_TESTUTILS_H_