1 // Eris Online RPG Protocol Library
2 // Copyright (C) 2007 Alistair Riddoch
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software Foundation,
16 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18 // $Id$
19
20 #ifdef NDEBUG
21 #undef NDEBUG
22 #endif
23 #ifndef DEBUG
24 #define DEBUG
25 #endif
26
27 #include <Eris/BaseConnection.h>
28 #include <Eris/Exceptions.h>
29 #include <Eris/Log.h>
30
31 #include "SignalFlagger.h"
32
33 #include <Atlas/Codecs/XML.h>
34 #include <Atlas/Net/Stream.h>
35 #include <Atlas/Message/QueuedDecoder.h>
36 #include <Atlas/Objects/objectFactory.h>
37 #include <Atlas/Objects/Encoder.h>
38
39 #include <skstream/skstream.h>
40
41 #include <cstdlib>
42
43 #include <cassert>
44
45 class TestBaseConnection : public Eris::BaseConnection {
46 public:
47 bool failure;
48 bool timeout;
49
TestBaseConnection(Atlas::Bridge * b)50 TestBaseConnection(Atlas::Bridge * b) : Eris::BaseConnection("test", "1", b), failure(false), timeout(false) { }
51
handleFailure(const std::string & msg)52 virtual void handleFailure(const std::string & msg) {
53 failure = true;
54 }
55
handleTimeout(const std::string & msg)56 virtual void handleTimeout(const std::string & msg) {
57 timeout = true;
58 }
59
test_setStatus(Eris::BaseConnection::Status sc)60 void test_setStatus(Eris::BaseConnection::Status sc) {
61 setStatus(sc);
62 }
63
test_onConnect()64 void test_onConnect() {
65 onConnect();
66 }
67
test_hardDisconnect(bool flag)68 void test_hardDisconnect(bool flag) {
69 hardDisconnect(flag);
70 }
71
test_onConnectTimeout()72 void test_onConnectTimeout() {
73 onConnectTimeout();
74 }
75
test_onNegotiateTimeout()76 void test_onNegotiateTimeout() {
77 onNegotiateTimeout();
78 }
79
setup_stream()80 void setup_stream() {
81 _stream = new tcp_socket_stream;
82 }
83
setup_codec()84 void setup_codec() {
85 m_codec = new Atlas::Codecs::XML(*_stream, *_bridge);
86 }
87
setup_encode()88 void setup_encode() {
89 _encode = new Atlas::Objects::ObjectsEncoder(*m_codec);
90 }
91
setup_sc()92 void setup_sc() {
93 _sc = new Atlas::Net::StreamConnect(_clientName, *_stream);
94 }
95 };
96
writeLog(Eris::LogLevel,const std::string & msg)97 static void writeLog(Eris::LogLevel, const std::string & msg)
98 {
99 std::cerr << msg << std::endl << std::flush;
100 }
101
main()102 int main()
103 {
104 Eris::Logged.connect(sigc::ptr_fun(writeLog));
105
106 Atlas::Objects::Factories * f = Atlas::Objects::Factories::instance();
107 assert(!f->hasFactory("unseen"));
108
109 {
110 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
111 }
112
113 // Make sure the op classes have been installed, and the initial
114 // constructor code path has been tested.
115 assert(f->hasFactory("unseen"));
116 assert(f->hasFactory("attack"));
117
118 // Test the other code path when a second connection is created.
119 {
120 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
121 }
122
123 // Test isConnected.
124 {
125 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
126
127 assert(!tbc.isConnected());
128 }
129
130 // Test getFileDescriptor.
131 {
132 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
133
134 try {
135 tbc.getFileDescriptor();
136
137 std::cerr << "FAIL: BaseConnection::getFileDescriptor() should throw Eris::InvalidOperation" << std::endl << "FAIL: when not coonected." << std::endl << std::flush;
138 abort();
139 }
140 catch (Eris::InvalidOperation & eio) {
141 }
142 }
143
144 // Test getStatus().
145 {
146 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
147
148 assert(tbc.getStatus() == Eris::BaseConnection::DISCONNECTED);
149 }
150
151 // Test setStatus().
152 {
153 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
154
155 assert(tbc.getStatus() == Eris::BaseConnection::DISCONNECTED);
156
157 tbc.test_setStatus(Eris::BaseConnection::CONNECTED);
158
159 assert(tbc.getStatus() == Eris::BaseConnection::CONNECTED);
160
161 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTED);
162 }
163
164 // Test alternate path through desctructor using setStatus()
165 {
166 TestBaseConnection * tbc = new TestBaseConnection(new Atlas::Message::QueuedDecoder);
167
168 assert(tbc->getStatus() == Eris::BaseConnection::DISCONNECTED);
169
170 tbc->setup_stream();
171 tbc->setup_codec();
172 tbc->setup_encode();
173 tbc->test_setStatus(Eris::BaseConnection::CONNECTED);
174
175 // The destructor will throw in hardDisconnect();
176 try {
177 delete tbc;
178 abort();
179 }
180 catch (Eris::InvalidOperation & eio) {
181 }
182 }
183
184 // Test connect() and verify getStatus() changes.
185 {
186 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
187
188 assert(tbc.getStatus() == Eris::BaseConnection::DISCONNECTED);
189
190 int ret = tbc.connect("localhost", 6723);
191
192 assert(ret == 0);
193
194 assert(tbc.getStatus() == Eris::BaseConnection::CONNECTING);
195 }
196
197 // Test onConnect() does nothing.
198 {
199 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
200
201 tbc.test_onConnect();
202 }
203
204 // Test onConnect() emits the signal.
205 {
206 SignalFlagger onConnect_checker;
207
208 assert(!onConnect_checker.flagged());
209
210 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
211
212 tbc.Connected.connect(sigc::mem_fun(onConnect_checker,
213 &SignalFlagger::set));
214
215 assert(!onConnect_checker.flagged());
216
217 tbc.test_onConnect();
218
219 assert(onConnect_checker.flagged());
220 }
221
222 // Test hardDisconnect() does nothing.
223 {
224 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
225
226 tbc.test_hardDisconnect(true);
227 }
228
229 // Test hardDisconnect() throws in polldefault when connected
230 {
231 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
232
233 // Add members to be consistent with connected state.
234 tbc.setup_stream();
235 tbc.setup_codec();
236 tbc.setup_encode();
237 // Make the state different
238 tbc.test_setStatus(Eris::BaseConnection::CONNECTED);
239
240 try {
241 tbc.test_hardDisconnect(true);
242 }
243 catch (Eris::InvalidOperation & eio) {
244 }
245
246 // Make it disconnected again, or we crash on destructor
247 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTED);
248 }
249
250 // Test hardDisconnect() throws in polldefault when disconnecting
251 {
252 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
253
254 // Add members to be consistent with disconnecting state.
255 tbc.setup_stream();
256 tbc.setup_codec();
257 tbc.setup_encode();
258 // Make the state different
259 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTING);
260
261 try {
262 tbc.test_hardDisconnect(true);
263 }
264 catch (Eris::InvalidOperation & eio) {
265 }
266
267 // Make it disconnected again, or we crash on destructor
268 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTED);
269 }
270
271 // Test hardDisconnect() throws in polldefault when negotiating
272 {
273 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
274
275 // Add members to be consistent with negotiating state.
276 tbc.setup_stream();
277 tbc.setup_sc();
278 // Make the state different
279 tbc.test_setStatus(Eris::BaseConnection::NEGOTIATE);
280
281 try {
282 tbc.test_hardDisconnect(true);
283 }
284 catch (Eris::InvalidOperation & eio) {
285 }
286
287 // Make it disconnected again, or we crash on destructor
288 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTED);
289 }
290
291 // Test hardDisconnect() throws in polldefault when negotiating
292 {
293 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
294
295 // Add members to be consistent with connecting state.
296 tbc.setup_stream();
297 // Make the state different
298 tbc.test_setStatus(Eris::BaseConnection::CONNECTING);
299
300 try {
301 tbc.test_hardDisconnect(true);
302 }
303 catch (Eris::InvalidOperation & eio) {
304 }
305
306 // Make it disconnected again, or we crash on destructor
307 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTED);
308 }
309
310 // Test hardDisconnect() throws in polldefault when negotiating
311 {
312 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
313
314 // Add members to be consistent with connecting state.
315 tbc.setup_stream();
316 // Make the state different
317 tbc.test_setStatus(Eris::BaseConnection::INVALID_STATUS);
318
319 try {
320 tbc.test_hardDisconnect(true);
321 }
322 catch (Eris::InvalidOperation & eio) {
323 }
324
325 // Make it disconnected again, or we crash on destructor
326 tbc.test_setStatus(Eris::BaseConnection::DISCONNECTED);
327 }
328
329 // Test onConnectTimeout()
330 {
331 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
332
333 tbc.test_onConnectTimeout();
334
335 assert(tbc.timeout);
336 }
337
338 // Test onNegotiateTimeout()
339 {
340 TestBaseConnection tbc(new Atlas::Message::QueuedDecoder);
341
342 tbc.test_onNegotiateTimeout();
343
344 assert(tbc.timeout);
345 }
346
347 return 0;
348 }
349