/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ByteBufferSlicePool; import org.xnio.Pooled; /** * Test for {@link BufferPipeOutputStream}. * * @author <a href="mailto:flavia.rainone@jboss.com">Flavia Rainone</a> * */ public class BufferPipeOutputStreamTestCase { private BufferPipeOutputStream stream; private TestBufferWriter bufferWriter; @Before public void init() throws IOException { bufferWriter = new TestBufferWriter(); stream = new BufferPipeOutputStream(bufferWriter); } @Test public void writeAndFlush() throws IOException { stream.write("test".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); List<Pooled<ByteBuffer>> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(1, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "test"); } @Test public void writeBytesAndFlush() throws IOException { stream.write('b'); stream.write('y'); stream.write('t'); stream.write('e'); stream.write('s'); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); List<Pooled<ByteBuffer>> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(1, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "bytes"); } @Test public void writeAndFlushRepeatedly() throws IOException { // flush empty stream stream.flush(); // nothing happens assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.write("test".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); stream.write("repeatedly".getBytes("UTF-8")); assertEquals(2, bufferWriter.getAcceptedBuffers().size()); // flush more than once, flush should be idempotent stream.flush(); stream.flush(); stream.write("again".getBytes("UTF-8")); assertEquals(3, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("and again".getBytes("UTF-8")); assertEquals(5, bufferWriter.getAcceptedBuffers().size()); stream.flush(); List<Pooled<ByteBuffer>> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(6, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "test"); assertAcceptedMessage(acceptedBuffers.get(1).getResource(), "repea"); assertAcceptedMessage(acceptedBuffers.get(2).getResource(), "tedly"); assertAcceptedMessage(acceptedBuffers.get(3).getResource(), "again"); assertAcceptedMessage(acceptedBuffers.get(4).getResource(), "and a"); assertAcceptedMessage(acceptedBuffers.get(5).getResource(), "gain"); } @Test public void writeBytesAndFlushRepeatedly() throws IOException { stream.write("r".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); stream.write("e".getBytes("UTF-8")); assertEquals(1, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("p".getBytes("UTF-8")); assertEquals(2, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("e".getBytes("UTF-8")); assertEquals(3, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("a".getBytes("UTF-8")); assertEquals(4, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("t".getBytes("UTF-8")); assertEquals(5, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("e".getBytes("UTF-8")); assertEquals(6, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("d".getBytes("UTF-8")); assertEquals(7, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("l".getBytes("UTF-8")); assertEquals(8, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("y".getBytes("UTF-8")); assertEquals(9, bufferWriter.getAcceptedBuffers().size()); // flush more than once, flush should be idempotent stream.flush(); stream.flush(); List<Pooled<ByteBuffer>> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(10, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "r"); assertAcceptedMessage(acceptedBuffers.get(1).getResource(), "e"); assertAcceptedMessage(acceptedBuffers.get(2).getResource(), "p"); assertAcceptedMessage(acceptedBuffers.get(3).getResource(), "e"); assertAcceptedMessage(acceptedBuffers.get(4).getResource(), "a"); assertAcceptedMessage(acceptedBuffers.get(5).getResource(), "t"); assertAcceptedMessage(acceptedBuffers.get(6).getResource(), "e"); assertAcceptedMessage(acceptedBuffers.get(7).getResource(), "d"); assertAcceptedMessage(acceptedBuffers.get(8).getResource(), "l"); assertAcceptedMessage(acceptedBuffers.get(9).getResource(), "y"); } @Test public void closeEmptyStream() throws IOException { assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); stream.close(); assertClosedChannel(true, true, 1, ""); } @Test public void close() throws IOException { assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); stream.write("test".getBytes()); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); stream.close(); assertClosedChannel(true, true, 1, "test"); } @Test public void bufferWriterAcceptThrowsIOException() throws IOException { stream.write("12345".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); bufferWriter.throwIOExceptionOnAccept(); IOException exceptionThrownByAccept = null; try { stream.write("won't accept".getBytes("UTF-8")); } catch (IOException e) { exceptionThrownByAccept = e; } assertNotNull(exceptionThrownByAccept); assertClosedChannel(true, false, 0); } @Test public void bufferWriterFlushThrowsIOException() throws IOException { stream.write('1'); stream.write("23456".getBytes("UTF-8")); List<Pooled<ByteBuffer>> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(1, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "12345"); assertFalse(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); bufferWriter.throwIOExceptionOnFlush(); IOException exceptionThrownByFlush = null; try { stream.flush(); } catch (IOException e) { exceptionThrownByFlush= e; } assertNotNull(exceptionThrownByFlush); acceptedBuffers.get(0).getResource().flip(); assertClosedChannel(false, false, 2, "12345", "6"); } private void assertClosedChannel(boolean flushed, boolean flushedEof, int numberOfAcceptedBuffers, String... bufferContents) throws IOException { List<Pooled<ByteBuffer>> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(numberOfAcceptedBuffers, acceptedBuffers.size()); for (int i = 0; i < bufferContents.length; i++) { assertAcceptedMessage(acceptedBuffers.get(i).getResource(), bufferContents[i]); } assertEquals(flushed, bufferWriter.isFlushed()); assertEquals(flushedEof, bufferWriter.isEof()); // close is idempotent stream.close(); assertEquals(numberOfAcceptedBuffers, bufferWriter.getAcceptedBuffers().size()); assertEquals(flushed, bufferWriter.isFlushed()); assertEquals(flushedEof, bufferWriter.isEof()); // can't write IOException cantWriteException = null; try { stream.write("can't write this".getBytes()); } catch (IOException e) { cantWriteException = e; } assertNotNull(cantWriteException); cantWriteException = null; try { stream.write('a'); } catch (IOException e) { cantWriteException = e; } assertNotNull(cantWriteException); // flushing is useless after closed stream.flush(); assertEquals(numberOfAcceptedBuffers, bufferWriter.getAcceptedBuffers().size()); assertEquals(flushed, bufferWriter.isFlushed()); assertEquals(flushedEof, bufferWriter.isEof()); } private static final void assertAcceptedMessage(ByteBuffer dst, String... message) { final StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } assertEquals(stringBuffer.toString(), Buffers.getModifiedUtf8(dst)); } private static class TestBufferWriter implements BufferPipeOutputStream.BufferWriter { private ByteBufferSlicePool bufferPool = new ByteBufferSlicePool(5, 10); private List<Pooled<ByteBuffer>> acceptedBuffers = new ArrayList<Pooled<ByteBuffer>>(); private boolean eof = false;; private boolean flushed = true; private boolean throwIOExceptionOnAccept = false; private boolean throwIOExceptionOnFlush = false; @Override public Pooled<ByteBuffer> getBuffer(boolean firstBuffer) throws IOException { return bufferPool.allocate(); } @Override public void accept(Pooled<ByteBuffer> pooledBuffer, boolean eof) throws IOException { if (throwIOExceptionOnAccept) { throwIOExceptionOnAccept = false; throw new IOException("test requested bufferWriter to throw IOException on accept"); } acceptedBuffers.add(pooledBuffer); this.eof = this.eof || eof; flushed = false; } @Override public void flush() throws IOException { if (throwIOExceptionOnFlush) { throwIOExceptionOnFlush = false; throw new IOException("test requested bufferWriter to throw IOException on flush"); } flushed = true; } public boolean isFlushed() { return flushed; } public List<Pooled<ByteBuffer>> getAcceptedBuffers() { return acceptedBuffers; } public boolean isEof() { return eof; } public void throwIOExceptionOnAccept() { throwIOExceptionOnAccept = true; } public void throwIOExceptionOnFlush() { throwIOExceptionOnFlush = true; } } }