001: /*
002: * Copyright (c) xsocket.org, 2006-2008. All rights reserved.
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
019: * The latest copy of this software may be found on http://www.xsocket.org/
020: */
021: package org.xsocket.connection;
022:
023: import java.io.IOException;
024: import java.nio.BufferUnderflowException;
025: import java.util.ArrayList;
026: import java.util.List;
027: import java.util.concurrent.Executors;
028: import java.util.concurrent.ThreadFactory;
029:
030: import org.junit.Assert;
031: import org.junit.Test;
032: import org.xsocket.ILifeCycle;
033: import org.xsocket.QAUtil;
034: import org.xsocket.connection.BlockingConnection;
035: import org.xsocket.connection.IBlockingConnection;
036: import org.xsocket.connection.IConnectHandler;
037: import org.xsocket.connection.IDataHandler;
038: import org.xsocket.connection.IDisconnectHandler;
039: import org.xsocket.connection.INonBlockingConnection;
040: import org.xsocket.connection.IServer;
041: import org.xsocket.connection.Server;
042: import org.xsocket.connection.ConnectionUtils;
043:
044: /**
045: *
046: * @author grro@xsocket.org
047: */
048: public final class OnHandlerMethodsOrderTest {
049:
050: private enum State {
051: CONNECTED, DISCONNECTED
052: };
053:
054: private static final String DELIMITER = "\r\n";
055: private static final int CLIENTS = 20;
056: private static final int LOOPS = 50;
057:
058: private List<String> clientErrors = new ArrayList<String>();
059: private int running = 0;
060:
061: @Test
062: public void testWithoutTimeout() throws Exception {
063: clientErrors = new ArrayList<String>();
064: running = 0;
065:
066: MyHandler hdl = new MyHandler();
067: final IServer server = new Server(hdl);
068: server.setWorkerpool(Executors
069: .newCachedThreadPool(new MyThreadFactory()));
070: ConnectionUtils.start(server);
071:
072: running = CLIENTS;
073: for (int i = 0; i < CLIENTS; i++) {
074: Thread client = new Thread() {
075: @Override
076: public void run() {
077: try {
078: IBlockingConnection connection = new BlockingConnection(
079: "localhost", server.getLocalPort());
080: connection.setAutoflush(false);
081:
082: for (int j = 0; j < LOOPS; j++) {
083: String request = "test";
084: connection.write(request);
085: connection.write(DELIMITER);
086: connection.flush();
087: String result = connection
088: .readStringByDelimiter(DELIMITER,
089: Integer.MAX_VALUE);
090:
091: if (!result.equals(request)) {
092: clientErrors.add("Error send "
093: + request + " but got "
094: + result);
095: }
096: }
097:
098: connection.close();
099:
100: } catch (Exception e) {
101: e.printStackTrace();
102: }
103: running--;
104: }
105: };
106: client.start();
107: }
108:
109: do {
110: QAUtil.sleep(250);
111: } while (running > 0);
112:
113: server.close();
114:
115: validateResult(hdl);
116: }
117:
118: @Test
119: public void testIdleTimeout() throws Exception {
120: clientErrors = new ArrayList<String>();
121: running = 0;
122:
123: MyHandler hdl = new MyHandler();
124: IServer server = new Server(hdl);
125: server.setWorkerpool(Executors
126: .newCachedThreadPool(new MyThreadFactory()));
127: server.setIdleTimeoutMillis(1000);
128: ConnectionUtils.start(server);
129:
130: IBlockingConnection connection = new BlockingConnection(
131: "localhost", server.getLocalPort());
132: connection.setAutoflush(false);
133:
134: String request = "test";
135: connection.write(request);
136: connection.write(DELIMITER);
137: connection.flush();
138:
139: QAUtil.sleep(1500);
140: Assert.assertTrue(hdl.onIdleTimeoutCalled);
141: Assert.assertFalse(hdl.onConnectionTimeoutCalled);
142: Assert.assertTrue(hdl.onDisconnectCalled);
143: validateResult(hdl);
144:
145: server.close();
146: }
147:
148: @Test
149: public void testConnectionTimeout() throws Exception {
150: clientErrors = new ArrayList<String>();
151: running = 0;
152:
153: MyHandler hdl = new MyHandler();
154: IServer server = new Server(hdl);
155: server.setWorkerpool(Executors
156: .newCachedThreadPool(new MyThreadFactory()));
157: server.setIdleTimeoutMillis(5000);
158: server.setConnectionTimeoutMillis(1000);
159: ConnectionUtils.start(server);
160:
161: IBlockingConnection connection = new BlockingConnection(
162: "localhost", server.getLocalPort());
163: connection.setAutoflush(false);
164:
165: String request = "test";
166: connection.write(request);
167: connection.write(DELIMITER);
168: connection.flush();
169:
170: QAUtil.sleep(1500);
171: Assert.assertFalse(hdl.onIdleTimeoutCalled);
172: Assert.assertTrue(hdl.onConnectionTimeoutCalled);
173: Assert.assertTrue(hdl.onDisconnectCalled);
174: validateResult(hdl);
175:
176: server.close();
177:
178: validateResult(hdl);
179: }
180:
181: private void validateResult(MyHandler hdl) {
182:
183: if (clientErrors.size() > 0) {
184: System.out.println("client error occured");
185: for (String error : clientErrors) {
186: System.out.println(error);
187: }
188: }
189:
190: if (hdl.errors.size() > 0) {
191: System.out.println("server error occured");
192: for (String error : hdl.errors) {
193: System.out.println(error);
194: }
195: }
196:
197: Assert.assertTrue("client error occured",
198: clientErrors.size() == 0);
199: Assert.assertTrue("server error occured",
200: hdl.errors.size() == 0);
201: }
202:
203: private static final class MyHandler implements IConnectHandler,
204: IDataHandler, IDisconnectHandler, ILifeCycle,
205: IIdleTimeoutHandler, IConnectionTimeoutHandler {
206:
207: private final List<String> errors = new ArrayList<String>();
208:
209: private boolean isInitialized = false;
210: private boolean isDestroyed = false;
211:
212: private boolean onConnectCalled = false;
213: private boolean onDisconnectCalled = false;
214: private boolean onIdleTimeoutCalled = false;
215: private boolean onConnectionTimeoutCalled = false;
216:
217: public void onInit() {
218: if (Thread.currentThread().getName().startsWith(
219: MyThreadFactory.PREFIX)) {
220: errors
221: .add("[onInit] shouldn't be executed by a worker thread not by "
222: + Thread.currentThread().getName());
223: }
224:
225: if (Thread.currentThread().getName().startsWith(
226: "xDispatcher")) {
227: errors
228: .add("[onInit] shouldn't be executed by a disptacher thread not by "
229: + Thread.currentThread().getName());
230: }
231:
232: if (isInitialized) {
233: errors.add("[onInit] shouldn't be initialized");
234: }
235:
236: if (isDestroyed) {
237: errors.add("[onInit] shouldn't be destroyed");
238: }
239:
240: isInitialized = true;
241: }
242:
243: public boolean onConnect(INonBlockingConnection connection)
244: throws IOException {
245: onConnectCalled = true;
246:
247: if (!Thread.currentThread().getName().startsWith(
248: MyThreadFactory.PREFIX)) {
249: errors
250: .add("[onConnect] should be executed by a worker thread not by "
251: + Thread.currentThread().getName());
252: }
253:
254: if (!isInitialized) {
255: errors.add("[onConnect] should be initialized");
256: }
257:
258: if (isDestroyed) {
259: errors.add("[onConnect] shouldn't be isDestroyed");
260: }
261:
262: State state = (State) connection.getAttachment();
263: if (state != null) {
264: errors.add("[onConnect] connection is in state "
265: + state + ". should be not in a state");
266: } else {
267: connection.setAttachment(State.CONNECTED);
268: }
269:
270: connection.setAutoflush(false);
271: return true;
272: }
273:
274: public boolean onData(INonBlockingConnection connection)
275: throws IOException, BufferUnderflowException {
276: if (!Thread.currentThread().getName().startsWith(
277: MyThreadFactory.PREFIX)) {
278: errors
279: .add("[onData] should be executed by a worker thread not by "
280: + Thread.currentThread().getName());
281: }
282:
283: if (!isInitialized) {
284: errors.add("[onData] should be initialized");
285: }
286:
287: if (isDestroyed) {
288: errors.add("[onData] shouldn't be isDestroyed");
289: }
290:
291: State state = (State) connection.getAttachment();
292: if (state == null) {
293: errors
294: .add("[onData] connection doesn't contains state attachment (state should be connected)");
295: } else {
296: if (state != State.CONNECTED) {
297: errors
298: .add("[on data] connection should be in state connected. current state is "
299: + state);
300: }
301: }
302:
303: connection.write(connection.readByteBufferByDelimiter(
304: DELIMITER, Integer.MAX_VALUE));
305: connection.write(DELIMITER);
306:
307: connection.flush();
308: return true;
309: }
310:
311: public boolean onDisconnect(INonBlockingConnection connection)
312: throws IOException {
313: onDisconnectCalled = true;
314:
315: if (!Thread.currentThread().getName().startsWith(
316: MyThreadFactory.PREFIX)) {
317: errors
318: .add("[onDisconnect] should be executed by a worker thread not by "
319: + Thread.currentThread().getName());
320: }
321:
322: if (!isInitialized) {
323: errors.add("[onDisconnect] should be initialized");
324: }
325:
326: if (isDestroyed) {
327: errors.add("onDisconnect] shouldn't be isDestroyed");
328: }
329:
330: State state = (State) connection.getAttachment();
331: if (state == null) {
332: errors
333: .add("[onDisconnect] connection doesn't contains state attachment (state should be connected)");
334: } else {
335: if (state != State.CONNECTED) {
336: errors
337: .add("[onDisconnect] connection should be in state connected. not in "
338: + state);
339: } else {
340: connection.setAttachment(State.DISCONNECTED);
341: }
342: }
343: return true;
344: }
345:
346: public boolean onConnectionTimeout(
347: INonBlockingConnection connection) throws IOException {
348: onConnectionTimeoutCalled = true;
349:
350: if (!Thread.currentThread().getName().startsWith(
351: MyThreadFactory.PREFIX)) {
352: errors
353: .add("[ConnectionTimeout] should be executed by a worker thread not by "
354: + Thread.currentThread().getName());
355: }
356:
357: if (!isInitialized) {
358: errors
359: .add("[ConnectionTimeout] should be initialized");
360: }
361:
362: if (isDestroyed) {
363: errors
364: .add("ConnectionTimeout] shouldn't be isDestroyed");
365: }
366:
367: State state = (State) connection.getAttachment();
368: if (state == null) {
369: errors
370: .add("[onConnectionTimeout] connection doesn't contains state attachment (state should be connected)");
371: } else {
372: if (state != State.CONNECTED) {
373: errors
374: .add("[ConnectionTimeout] connection should be in state connected. not in "
375: + state);
376: }
377: }
378: return false;
379: }
380:
381: public boolean onIdleTimeout(INonBlockingConnection connection)
382: throws IOException {
383: onIdleTimeoutCalled = true;
384:
385: if (!Thread.currentThread().getName().startsWith(
386: MyThreadFactory.PREFIX)) {
387: errors
388: .add("[ConnectionTimeout] should be executed by a worker thread");
389: }
390:
391: if (!isInitialized) {
392: errors
393: .add("[ConnectionTimeout] should be initialized");
394: }
395:
396: if (isDestroyed) {
397: errors
398: .add("ConnectionTimeout] shouldn't be isDestroyed");
399: }
400:
401: State state = (State) connection.getAttachment();
402: if (state == null) {
403: errors
404: .add("[onIdleTimeout] connection doesn't contains state attachment (state should be connected)");
405: } else {
406: if (state != State.CONNECTED) {
407: errors
408: .add("[IdleTimeout] connection should be in state connected. not in "
409: + state);
410: }
411: }
412:
413: return false;
414: }
415:
416: public void onDestroy() {
417: if (Thread.currentThread().getName().startsWith(
418: MyThreadFactory.PREFIX)) {
419: errors
420: .add("[onInit] shouldn't be executed by a worker thread not by "
421: + Thread.currentThread().getName());
422: }
423: if (Thread.currentThread().getName().startsWith(
424: "xDispatcher")) {
425: errors
426: .add("[onInit] shouldn't be executed by a disptacher thread");
427: }
428:
429: if (!isInitialized) {
430: errors.add("[onDestroy] should be initialized");
431: }
432:
433: if (isDestroyed) {
434: errors.add("onDestroy] shouldn't be isDestroyed");
435: }
436:
437: isInitialized = true;
438:
439: }
440:
441: List<String> getErrors() {
442: return errors;
443: }
444: }
445:
446: private static class MyThreadFactory implements ThreadFactory {
447:
448: static final String PREFIX = "WORKER";
449: private int num = 0;
450:
451: public Thread newThread(Runnable r) {
452: Thread t = new Thread(r);
453: t.setName(PREFIX + (++num));
454: t.setDaemon(true);
455: t.setPriority(Thread.NORM_PRIORITY);
456: return t;
457: }
458: }
459: }
|