PageRenderTime 41ms CodeModel.GetById 13ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

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