/test/kilim/test/TestIO.java

http://github.com/kilim/kilim · Java · 182 lines · 142 code · 19 blank · 21 comment · 11 complexity · e88dd3cf96628cd7cb9e1d1d263e3143 MD5 · raw file

  1. /* Copyright (c) 2006, Sriram Srinivasan
  2. *
  3. * You may distribute this software under the terms of the license
  4. * specified in the file "License"
  5. */
  6. package kilim.test;
  7. import java.io.ByteArrayOutputStream;
  8. import java.io.DataInputStream;
  9. import java.io.DataOutputStream;
  10. import java.io.IOException;
  11. import java.io.OutputStream;
  12. import java.net.InetSocketAddress;
  13. import java.nio.ByteBuffer;
  14. import java.nio.channels.SocketChannel;
  15. import junit.framework.TestCase;
  16. import kilim.Pausable;
  17. import kilim.Scheduler;
  18. import kilim.nio.NioSelectorScheduler;
  19. import kilim.nio.SessionTask;
  20. public class TestIO extends TestCase {
  21. static final int ITERS = 10;
  22. static final int NCLIENTS = 100;
  23. NioSelectorScheduler nio;
  24. int port;
  25. private static boolean dbg = false;
  26. @Override
  27. protected void setUp() throws Exception {
  28. nio = new NioSelectorScheduler(); // Starts a single thread that manages the select loop
  29. port = nio.listen(0, EchoServer.class, Scheduler.getDefaultScheduler()); //
  30. }
  31. @Override
  32. protected void tearDown() throws Exception {
  33. nio.shutdown();
  34. Thread.sleep(500); // Allow the socket to be closed
  35. }
  36. public static void main(String [] args) throws Exception {
  37. dbg = true;
  38. TestIO test = new TestIO();
  39. test.setUp();
  40. test.testParallelEchoes();
  41. test.testDelay();
  42. test.tearDown();
  43. Scheduler.getDefaultScheduler().shutdown();
  44. }
  45. /**
  46. * Launch many ping clients, each of which is paired with its own instance of {@link EchoServer}.
  47. * @throws IOException
  48. */
  49. public void testParallelEchoes() throws IOException {
  50. try {
  51. for (int i = 0; i < NCLIENTS; i++) {
  52. if (dbg) System.out.println(i);
  53. client(port);
  54. }
  55. } catch (IOException e) {
  56. e.printStackTrace();
  57. fail("IOException " + e.getClass() + ":" + e.getMessage());
  58. }
  59. }
  60. public void testDelay() throws IOException {
  61. SocketChannel sc = SocketChannel.open();
  62. try {
  63. sc.socket().connect(new InetSocketAddress("localhost", port));
  64. String s = "Iteration #0. DONE"; // Only because EchoServer checks for it.
  65. byte[] sbytes = s.getBytes();
  66. ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
  67. DataOutputStream dos = new DataOutputStream(baos);
  68. dos.writeInt(sbytes.length);
  69. dos.write(sbytes);
  70. byte[] sendbuf = baos.toByteArray();
  71. // Now write the bytes in little dribs and drabs and delaying in between. This tests fill's yield.
  72. OutputStream os = sc.socket().getOutputStream();
  73. sendChunkWithDelay(os, sendbuf, 0, 1); // splitting the length prefix
  74. sendChunkWithDelay(os, sendbuf, 1, 2);
  75. sendChunkWithDelay(os, sendbuf, 3, 4);
  76. sendChunkWithDelay(os, sendbuf, 7, 3);
  77. sendChunkWithDelay(os, sendbuf, 10, sendbuf.length - 10); // the rest
  78. // Ideally, would like to simulate flow control on the rcv end as well, but would have to turn off
  79. // socket buffering on the EchoServer side of things.
  80. String rs = rcv(sc);
  81. assertEquals(s, rs);
  82. } catch (IOException e) {
  83. e.printStackTrace();
  84. fail("IOException " + e.getClass() + ":" + e.getMessage());
  85. }
  86. }
  87. public void sendChunkWithDelay(OutputStream os, byte[] sendbuf, int offset, int len) throws IOException {
  88. os.write(sendbuf, offset, len);
  89. os.flush();
  90. try {Thread.sleep(100);} catch (InterruptedException ignore) {}
  91. }
  92. /**
  93. * test client side utility function. uses blocking Java I/O to send a length-prefixed string.
  94. */
  95. static void send(SocketChannel sc, String s) throws IOException {
  96. byte[] bytes = s.getBytes();
  97. int len = bytes.length;
  98. DataOutputStream dos = new DataOutputStream(sc.socket().getOutputStream());
  99. dos.writeInt(len);
  100. dos.write(bytes);
  101. dos.flush();
  102. }
  103. /**
  104. * test client side utility function. uses blocking Java I/O to rcv a length-prefixed string.
  105. */
  106. static String rcv(SocketChannel sc) throws IOException {
  107. // rcv
  108. DataInputStream dis = new DataInputStream(sc.socket().getInputStream());
  109. byte[] bytes = new byte[100];
  110. int len = dis.readInt();
  111. assertTrue(len < bytes.length);
  112. int offset = 0;
  113. while (len > 0) {
  114. int n = dis.read(bytes, offset, len);
  115. if (n == -1) {
  116. throw new IOException("Unexpected termination");
  117. }
  118. len -= n;
  119. offset += n;
  120. }
  121. return new String(bytes, 0, offset); // offset contains the length.
  122. }
  123. static void client(int port) throws IOException {
  124. SocketChannel sc = SocketChannel.open();
  125. try {
  126. // Client using regular JDK I/O API.
  127. sc.socket().connect(new InetSocketAddress("localhost", port));
  128. for (int i = 0 ; i < ITERS; i++) {
  129. String s = "Iteration #" + i;
  130. if (i == ITERS-1) {s += " DONE";}
  131. send(sc, s);
  132. String rs = rcv(sc);
  133. assertEquals(s, rs);
  134. }
  135. } finally {
  136. sc.close();
  137. }
  138. }
  139. public static class EchoServer extends SessionTask {
  140. @Override
  141. public void execute() throws Pausable, Exception {
  142. ByteBuffer buf = ByteBuffer.allocate(100);
  143. while (true) {
  144. buf.clear();
  145. buf = endpoint.fillMessage(buf, 4, /*lengthIncludesItself*/ false);
  146. buf.flip();
  147. int strlen = buf.getInt();
  148. String s= new String(buf.array(), 4, strlen);
  149. //System.out.println ("Rcvd: " + s);
  150. if (!s.startsWith("Iteration #")) {
  151. endpoint.close();
  152. break;
  153. }
  154. buf.position(0); // reset read pos
  155. endpoint.write(buf); // echo.
  156. if (s.endsWith("DONE")) {
  157. endpoint.close();
  158. break;
  159. }
  160. }
  161. }
  162. }
  163. }