blob: 25e1edcf0cfcda40010e5802d5d6cf37ea48f423 [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"
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020024
25namespace webrtc {
26namespace testing {
27
28using namespace rtc;
29
30///////////////////////////////////////////////////////////////////////////////
31// StreamSink - Monitor asynchronously signalled events from StreamInterface
32// or AsyncSocket (which should probably be a StreamInterface.
33///////////////////////////////////////////////////////////////////////////////
34
35// Note: Any event that is an error is treaded as SSE_ERROR instead of that
36// event.
37
38enum StreamSinkEvent {
Yves Gerey665174f2018-06-19 15:03:05 +020039 SSE_OPEN = SE_OPEN,
40 SSE_READ = SE_READ,
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020041 SSE_WRITE = SE_WRITE,
42 SSE_CLOSE = SE_CLOSE,
43 SSE_ERROR = 16
44};
45
46class StreamSink : public sigslot::has_slots<> {
47 public:
Steve Anton9de3aac2017-10-24 10:08:26 -070048 StreamSink();
49 ~StreamSink() override;
50
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020051 void Monitor(StreamInterface* stream) {
Yves Gerey665174f2018-06-19 15:03:05 +020052 stream->SignalEvent.connect(this, &StreamSink::OnEvent);
53 events_.erase(stream);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020054 }
55 void Unmonitor(StreamInterface* stream) {
Yves Gerey665174f2018-06-19 15:03:05 +020056 stream->SignalEvent.disconnect(this);
57 // In case you forgot to unmonitor a previous object with this address
58 events_.erase(stream);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020059 }
Yves Gerey665174f2018-06-19 15:03:05 +020060 bool Check(StreamInterface* stream,
61 StreamSinkEvent event,
62 bool reset = true) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020063 return DoCheck(stream, event, reset);
64 }
65 int Events(StreamInterface* stream, bool reset = true) {
66 return DoEvents(stream, reset);
67 }
68
69 void Monitor(AsyncSocket* socket) {
Yves Gerey665174f2018-06-19 15:03:05 +020070 socket->SignalConnectEvent.connect(this, &StreamSink::OnConnectEvent);
71 socket->SignalReadEvent.connect(this, &StreamSink::OnReadEvent);
72 socket->SignalWriteEvent.connect(this, &StreamSink::OnWriteEvent);
73 socket->SignalCloseEvent.connect(this, &StreamSink::OnCloseEvent);
74 // In case you forgot to unmonitor a previous object with this address
75 events_.erase(socket);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020076 }
77 void Unmonitor(AsyncSocket* socket) {
Yves Gerey665174f2018-06-19 15:03:05 +020078 socket->SignalConnectEvent.disconnect(this);
79 socket->SignalReadEvent.disconnect(this);
80 socket->SignalWriteEvent.disconnect(this);
81 socket->SignalCloseEvent.disconnect(this);
82 events_.erase(socket);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020083 }
84 bool Check(AsyncSocket* socket, StreamSinkEvent event, bool reset = true) {
85 return DoCheck(socket, event, reset);
86 }
87 int Events(AsyncSocket* socket, bool reset = true) {
88 return DoEvents(socket, reset);
89 }
90
91 private:
Yves Gerey665174f2018-06-19 15:03:05 +020092 typedef std::map<void*, int> EventMap;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +020093
94 void OnEvent(StreamInterface* stream, int events, int error) {
95 if (error) {
96 events = SSE_ERROR;
97 }
98 AddEvents(stream, events);
99 }
Yves Gerey665174f2018-06-19 15:03:05 +0200100 void OnConnectEvent(AsyncSocket* socket) { AddEvents(socket, SSE_OPEN); }
101 void OnReadEvent(AsyncSocket* socket) { AddEvents(socket, SSE_READ); }
102 void OnWriteEvent(AsyncSocket* socket) { AddEvents(socket, SSE_WRITE); }
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200103 void OnCloseEvent(AsyncSocket* socket, int error) {
104 AddEvents(socket, (0 == error) ? SSE_CLOSE : SSE_ERROR);
105 }
106
107 void AddEvents(void* obj, int events) {
108 EventMap::iterator it = events_.find(obj);
109 if (events_.end() == it) {
110 events_.insert(EventMap::value_type(obj, events));
111 } else {
112 it->second |= events;
113 }
114 }
115 bool DoCheck(void* obj, StreamSinkEvent event, bool reset) {
116 EventMap::iterator it = events_.find(obj);
117 if ((events_.end() == it) || (0 == (it->second & event))) {
118 return false;
119 }
120 if (reset) {
121 it->second &= ~event;
122 }
123 return true;
124 }
125 int DoEvents(void* obj, bool reset) {
126 EventMap::iterator it = events_.find(obj);
127 if (events_.end() == it)
128 return 0;
129 int events = it->second;
130 if (reset) {
131 it->second = 0;
132 }
133 return events;
134 }
135
136 EventMap events_;
137};
138
139///////////////////////////////////////////////////////////////////////////////
140// StreamSource - Implements stream interface and simulates asynchronous
141// events on the stream, without a network. Also buffers written data.
142///////////////////////////////////////////////////////////////////////////////
143
144class StreamSource : public StreamInterface {
Yves Gerey665174f2018-06-19 15:03:05 +0200145 public:
146 StreamSource();
147 ~StreamSource() override;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200148
Yves Gerey665174f2018-06-19 15:03:05 +0200149 void Clear() {
150 readable_data_.clear();
151 written_data_.clear();
152 state_ = SS_CLOSED;
153 read_block_ = 0;
154 write_block_ = SIZE_UNKNOWN;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200155 }
Yves Gerey665174f2018-06-19 15:03:05 +0200156 void QueueString(const char* data) { QueueData(data, strlen(data)); }
Niels Möller00f934a2017-12-14 13:30:46 +0100157#if defined(__GNUC__)
158 // Note: Implicit |this| argument counts as the first argument.
159 __attribute__((__format__(__printf__, 2, 3)))
160#endif
Yves Gerey665174f2018-06-19 15:03:05 +0200161 void
162 QueueStringF(const char* format, ...) {
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200163 va_list args;
164 va_start(args, format);
165 char buffer[1024];
Niels Mölleraba06332018-10-16 15:14:15 +0200166 size_t len = vsnprintf(buffer, sizeof(buffer), format, args);
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200167 RTC_CHECK(len < sizeof(buffer) - 1);
168 va_end(args);
169 QueueData(buffer, len);
170 }
171 void QueueData(const char* data, size_t len) {
172 readable_data_.insert(readable_data_.end(), data, data + len);
173 if ((SS_OPEN == state_) && (readable_data_.size() == len)) {
174 SignalEvent(this, SE_READ, 0);
175 }
176 }
177 std::string ReadData() {
178 std::string data;
179 // avoid accessing written_data_[0] if it is undefined
180 if (written_data_.size() > 0) {
181 data.insert(0, &written_data_[0], written_data_.size());
182 }
183 written_data_.clear();
184 return data;
185 }
186 void SetState(StreamState state) {
187 int events = 0;
188 if ((SS_OPENING == state_) && (SS_OPEN == state)) {
189 events |= SE_OPEN;
190 if (!readable_data_.empty()) {
191 events |= SE_READ;
192 }
193 } else if ((SS_CLOSED != state_) && (SS_CLOSED == state)) {
194 events |= SE_CLOSE;
195 }
196 state_ = state;
197 if (events) {
198 SignalEvent(this, events, 0);
199 }
200 }
201 // Will cause Read to block when there are pos bytes in the read queue.
202 void SetReadBlock(size_t pos) { read_block_ = pos; }
203 // Will cause Write to block when there are pos bytes in the write queue.
204 void SetWriteBlock(size_t pos) { write_block_ = pos; }
205
Steve Anton9de3aac2017-10-24 10:08:26 -0700206 StreamState GetState() const override;
207 StreamResult Read(void* buffer,
208 size_t buffer_len,
209 size_t* read,
210 int* error) override;
211 StreamResult Write(const void* data,
212 size_t data_len,
213 size_t* written,
214 int* error) override;
215 void Close() override;
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200216
Steve Anton9de3aac2017-10-24 10:08:26 -0700217 private:
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200218 typedef std::vector<char> Buffer;
219 Buffer readable_data_, written_data_;
220 StreamState state_;
221 size_t read_block_, write_block_;
222};
223
Henrik Kjellanderec78f1c2017-06-29 07:52:50 +0200224} // namespace testing
225} // namespace webrtc
226
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200227#endif // RTC_BASE_TESTUTILS_H_