/* * Copyright 2009-2010 Brian S O'Neill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.cojen.dirmi; import java.io.EOFException; import java.io.IOException; import org.junit.*; import static org.junit.Assert.*; /** * * * @author Brian S O'Neill */ public class TestPipes extends AbstractTestSuite { public static void main(String[] args) { org.junit.runner.JUnitCore.main(TestPipes.class.getName()); } protected SessionStrategy createSessionStrategy(Environment env) throws Exception { return new PipedSessionStrategy(env, null, new RemotePipesServer()); } @Test public void basic() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; assertFalse(pipes instanceof RemotePipesServer); Pipe pipe = pipes.basic(null); pipe.writeInt(123456789); pipe.flush(); int i = pipe.readInt(); assertEquals(123456789, i); } @Test public void echoBytes() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(byte[].class, null); byte[] bytes = "hello".getBytes(); pipe.writeInt(bytes.length); pipe.write(bytes); pipe.flush(); byte[] response = new byte[bytes.length]; pipe.readFully(response); assertArrayEquals(bytes, response); } @Test public void echoBoolean() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(boolean.class, null); pipe.writeBoolean(false); pipe.flush(); assertEquals(false, pipe.readBoolean()); pipe = pipes.echo(boolean.class, null); pipe.writeBoolean(true); pipe.flush(); assertEquals(true, pipe.readBoolean()); } @Test public void echoByte() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(byte.class, null); pipe.writeByte(-99); pipe.flush(); assertEquals(-99, pipe.readByte()); } @Test public void echoShort() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(short.class, null); pipe.writeShort(-9999); pipe.flush(); assertEquals(-9999, pipe.readShort()); } @Test public void echoChar() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(char.class, null); pipe.writeChar('A'); pipe.flush(); assertEquals('A', pipe.readChar()); } @Test public void echoInt() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(int.class, null); pipe.writeInt(-999999999); pipe.flush(); assertEquals(-999999999, pipe.readInt()); } @Test public void echoLong() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(long.class, null); pipe.writeLong(-999999999999999999L); pipe.flush(); assertEquals(-999999999999999999L, pipe.readLong()); } @Test public void echoFloat() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(float.class, null); pipe.writeFloat((float) Math.PI); pipe.flush(); assertTrue((float) Math.PI == pipe.readFloat()); } @Test public void echoDouble() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(double.class, null); pipe.writeDouble(Math.PI); pipe.flush(); assertTrue(Math.PI == pipe.readDouble()); } @Test public void echoUTF() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(String.class, null); pipe.writeUTF("hello\u1234"); pipe.flush(); assertEquals("hello\u1234", pipe.readUTF()); } @Test public void echoThrowable() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(Throwable.class, null); Throwable obj = new IllegalArgumentException("illegal"); pipe.writeThrowable(obj); pipe.flush(); assertEquals(obj.toString(), pipe.readThrowable().toString()); } @Test public void echoObject() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(Object.class, null); Object obj = new java.math.BigDecimal(Math.E); pipe.writeObject(obj); pipe.flush(); assertEquals(obj, pipe.readObject()); } @Test public void pipeClose() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(int.class, null); pipe.writeInt(50); pipe.flush(); // Wait for remote close to reach local pipe. Thread.sleep(1000); assertEquals(50, pipe.readInt()); // Pipe not locally closed, so returns EOF. assertEquals(-1, pipe.read()); assertEquals(-1, pipe.read()); try { pipe.readObject(); fail(); } catch (EOFException e) { } // After locally closing pipe, reads throw non-EOF exception. pipe.close(); try { pipe.getInputStream().read(); fail(); } catch (EOFException e) { fail(); } catch (IOException e) { } try { pipe.read(); fail(); } catch (EOFException e) { fail(); } catch (IOException e) { } try { pipe.readObject(); fail(); } catch (EOFException e) { fail(); } catch (IOException e) { } // Due to buffering in ObjectOutputStream, need to flush to force an // exception to be thrown. try { pipe.write(1); pipe.writeObject("hello"); pipe.flush(); fail(); } catch (IOException e) { } } @Test public void pipeClose2() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(int.class, null); pipe.writeInt(50); pipe.flush(); // Wait for remote close to reach local pipe. Thread.sleep(1000); assertEquals(50, pipe.readInt()); pipe.write(1); try { pipe.flush(); } catch (IOException e) { } } @Test public void pipeClose3() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echo(int.class, null); pipe.writeInt(50); pipe.flush(); // Wait for remote close to reach local pipe. Thread.sleep(1000); assertEquals(50, pipe.readInt()); try { // Write failure is not immediately detected with sockets, so write // a bunch of times to ensure send buffer is filled. for (int i=0; i<1000000; i++) { pipe.write(1); } fail(); } catch (IOException e) { } // Failed writes force input to be closed too now. try { pipe.read(); fail(); } catch (IOException e) { } } @Test public void pipeClose4() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; Pipe pipe = pipes.echoNoClose(null, 50); assertEquals(50, pipe.readInt()); // After locally closing pipe, reads throw non-EOF exception. pipe.close(); // This behavior is completely wrong, but this is how ObjectInputStream // behaves. I call it a bug, but the object streams don't define their // close behavior. assertEquals(-1, pipe.read()); try { pipe.readObject(); fail(); } catch (EOFException e) { fail(); } catch (IOException e) { } // After throwing an exception, further reads appear to fail correctly. try { pipe.read(); fail(); } catch (EOFException e) { fail(); } catch (IOException e) { } } @Test public void concurrentClose() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; final Pipe pipe = pipes.open(null); Thread reader = new Thread("pipe reader") { public void run() { try { // This blocks because nothing is written. pipe.read(); } catch (Exception e) { } } }; Thread closer = new Thread("pipe closer") { public void run() { try { sleep(5000); } catch (InterruptedException e) { } try { pipe.close(); } catch (Exception e) { } } }; reader.start(); closer.start(); for (int i=0; i<100; i++) { if (!reader.isAlive()) { return; } Thread.sleep(100); } fail("Close didn't interrupt blocked read"); } @Test public void requestReply() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; setRequestValue(pipes, 10); { Pipe pipe = pipes.requestReply(null); pipe.writeInt(123); int reply = pipe.readInt(); assertEquals(123 + 1, reply); pipe.close(); } { Pipe pipe = pipes.requestReply(null); pipe.writeInt(123); pipe.readInt(); try { pipe.writeInt(124); fail(); } catch (IOException e) { } pipe.close(); } { Pipe pipe = pipes.requestReply(null); pipe.writeInt(123); int reply = pipe.readInt(); assertEquals(123 + 1, reply); assertEquals(-1, pipe.read()); pipe.close(); // Make sure that reading EOF doesn't mess up recycled channel. for (int i=0; i<10; i++) { assertEquals(10, pipes.getRequestValue()); } } } private void setRequestValue(RemotePipes pipes, int value) throws Exception { pipes.setRequestValue(value); for (int i=0; i<10; i++) { if (pipes.getRequestValue() == value) { break; } Thread.sleep(100); } assertEquals(value, pipes.getRequestValue()); } @Test public void requestOnly() throws Exception { requestOnly(false); } @Test public void requestOnlyEOF() throws Exception { requestOnly(true); } private void requestOnly(boolean readEOF) throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; setRequestValue(pipes, 0); { Pipe pipe = pipes.requestOnly(null, readEOF); pipe.writeInt(123); pipe.close(); int expect = readEOF ? -1 : 123; for (int i=0; i<10; i++) { if (pipes.getRequestValue() != expect) { Thread.sleep(100); } } for (int i=0; i<10; i++) { assertEquals(expect, pipes.getRequestValue()); } } { Pipe pipe = pipes.requestOnly(null, readEOF); pipe.close(); for (int i=0; i<10; i++) { if (pipes.getRequestValue() != Integer.MIN_VALUE) { Thread.sleep(100); } } assertEquals(Integer.MIN_VALUE, pipes.getRequestValue()); } } @Test public void replyOnly() throws Exception { RemotePipes pipes = (RemotePipes) sessionStrategy.remoteServer; setRequestValue(pipes, 10); { Pipe pipe = pipes.replyOnly(null); int reply = pipe.readInt(); assertEquals(111, reply); pipe.close(); } { Pipe pipe = pipes.replyOnly(null); pipe.readInt(); try { pipe.writeInt(124); fail(); } catch (IOException e) { } pipe.close(); } { Pipe pipe = pipes.replyOnly(null); int reply = pipe.readInt(); assertEquals(111, reply); assertEquals(-1, pipe.read()); pipe.close(); // Make sure that reading EOF doesn't mess up recycled channel. for (int i=0; i<10; i++) { assertEquals(10, pipes.getRequestValue()); } } } }