blob: 42ca2c7d1a407a11f6b5cddff22cd3f9ab5b9864 [file] [log] [blame]
package org.apache.maven.surefire.api.util.internal;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousByteChannel;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.NonReadableChannelException;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.ShutdownChannelGroupException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static java.nio.file.Files.write;
import static org.fest.assertions.Assertions.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
* The tests for {@link Channels#newChannel(InputStream)} and {@link Channels#newBufferedChannel(InputStream)}.
*/
public class ChannelsReaderTest
{
@Rule
public final ExpectedException ee = ExpectedException.none();
@Rule
public final TemporaryFolder tmp = TemporaryFolder.builder()
.assureDeletion()
.build();
@Test
public void exactBufferSize() throws Exception
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
ReadableByteChannel channel = Channels.newChannel( is );
ByteBuffer bb = ByteBuffer.allocate( 3 );
int countWritten = channel.read( bb );
assertThat( countWritten )
.isEqualTo( 3 );
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 3 );
assertThat( bb.remaining() )
.isEqualTo( 0 );
assertThat( bb.limit() )
.isEqualTo( 3 );
assertThat( bb.capacity() )
.isEqualTo( 3 );
bb.flip();
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 0 );
assertThat( bb.remaining() )
.isEqualTo( 3 );
assertThat( bb.limit() )
.isEqualTo( 3 );
assertThat( bb.capacity() )
.isEqualTo( 3 );
assertThat( bb.array() )
.isEqualTo( new byte[] {1, 2, 3} );
assertThat( channel.isOpen() )
.isTrue();
channel.close();
assertThat( channel.isOpen() )
.isFalse();
}
@Test
public void bufferedChannel() throws Exception
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
ReadableByteChannel channel = Channels.newBufferedChannel( is );
ByteBuffer bb = ByteBuffer.allocate( 4 );
int countWritten = channel.read( bb );
assertThat( countWritten )
.isEqualTo( 3 );
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 3 );
assertThat( bb.remaining() )
.isEqualTo( 1 );
assertThat( bb.limit() )
.isEqualTo( 4 );
assertThat( bb.capacity() )
.isEqualTo( 4 );
bb.flip();
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 0 );
assertThat( bb.remaining() )
.isEqualTo( 3 );
assertThat( bb.limit() )
.isEqualTo( 3 );
assertThat( bb.capacity() )
.isEqualTo( 4 );
assertThat( bb.array() )
.isEqualTo( new byte[] {1, 2, 3, 0} );
assertThat( channel.isOpen() )
.isTrue();
channel.close();
assertThat( channel.isOpen() )
.isFalse();
}
@Test
public void biggerBuffer() throws Exception
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
ReadableByteChannel channel = Channels.newChannel( is );
ByteBuffer bb = ByteBuffer.allocate( 4 );
int countWritten = channel.read( bb );
assertThat( countWritten )
.isEqualTo( 3 );
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 3 );
assertThat( bb.remaining() )
.isEqualTo( 1 );
assertThat( bb.limit() )
.isEqualTo( 4 );
assertThat( bb.capacity() )
.isEqualTo( 4 );
bb.flip();
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 0 );
assertThat( bb.remaining() )
.isEqualTo( 3 );
assertThat( bb.limit() )
.isEqualTo( 3 );
assertThat( bb.capacity() )
.isEqualTo( 4 );
assertThat( bb.array() )
.isEqualTo( new byte[] {1, 2, 3, 0} );
assertThat( channel.isOpen() )
.isTrue();
channel.close();
assertThat( channel.isOpen() )
.isFalse();
}
@Test
public void shouldFailAfterClosed() throws IOException
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
ReadableByteChannel channel = Channels.newChannel( is );
channel.close();
assertThat( channel.isOpen() ).isFalse();
ee.expect( ClosedChannelException.class );
channel.read( ByteBuffer.allocate( 0 ) );
}
@Test
public void shouldFailIfNotReadable() throws IOException
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
ReadableByteChannel channel = Channels.newChannel( is );
ee.expect( NonReadableChannelException.class );
channel.read( ByteBuffer.allocate( 0 ).asReadOnlyBuffer() );
}
@Test
public void shouldFailIOnDirectBuffer() throws IOException
{
ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} );
ReadableByteChannel channel = Channels.newChannel( is );
ee.expect( NonReadableChannelException.class );
channel.read( ByteBuffer.allocateDirect( 0 ) );
}
@Test
public void shouldUseFileChannel() throws IOException
{
File f = tmp.newFile();
write( f.toPath(), new byte[] {1, 2, 3} );
FileInputStream is = new FileInputStream( f );
ReadableByteChannel channel = Channels.newChannel( is );
ByteBuffer bb = ByteBuffer.allocate( 4 );
int countWritten = channel.read( bb );
assertThat( channel.isOpen() )
.isTrue();
channel.close();
assertThat( channel.isOpen() )
.isFalse();
assertThat( countWritten )
.isEqualTo( 3 );
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 3 );
assertThat( bb.remaining() )
.isEqualTo( 1 );
assertThat( bb.limit() )
.isEqualTo( 4 );
assertThat( bb.capacity() )
.isEqualTo( 4 );
bb.flip();
assertThat( bb.arrayOffset() )
.isEqualTo( 0 );
assertThat( bb.position() )
.isEqualTo( 0 );
assertThat( bb.remaining() )
.isEqualTo( 3 );
assertThat( bb.limit() )
.isEqualTo( 3 );
assertThat( bb.capacity() )
.isEqualTo( 4 );
assertThat( bb.array() )
.isEqualTo( new byte[] {1, 2, 3, 0} );
}
@Test( expected = IndexOutOfBoundsException.class )
public void shouldValidateInput1() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
InputStream is = Channels.newInputStream( channel );
is.read( new byte[0], -1, 0 );
}
@Test( expected = IndexOutOfBoundsException.class )
public void shouldValidateInput2() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
InputStream is = Channels.newInputStream( channel );
is.read( new byte[0], 0, -1 );
}
@Test( expected = IndexOutOfBoundsException.class )
public void shouldValidateInput3() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
InputStream is = Channels.newInputStream( channel );
is.read( new byte[0], 1, 0 );
}
@Test( expected = IndexOutOfBoundsException.class )
public void shouldValidateInput4() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
InputStream is = Channels.newInputStream( channel );
is.read( new byte[0], 0, 1 );
}
@Test
public void shouldClose() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
when( channel.isOpen() ).thenReturn( true );
InputStream is = Channels.newInputStream( channel );
is.close();
verify( channel, times( 1 ) ).close();
}
@Test
public void shouldNotClose() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
when( channel.isOpen() ).thenReturn( false );
InputStream is = Channels.newInputStream( channel );
is.close();
verify( channel, never() ).close();
}
@Test
public void shouldAlreadyClosed() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
when( channel.isOpen() ).thenReturn( true );
doThrow( ClosedChannelException.class ).when( channel ).close();
InputStream is = Channels.newInputStream( channel );
is.close();
verify( channel ).close();
}
@Test
public void shouldReadZeroLength() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
InputStream is = Channels.newInputStream( channel );
is.read( new byte[] { 5 }, 0, 0 );
verifyZeroInteractions( channel );
}
@Test
public void shouldReadArray() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
when( channel.read( any( ByteBuffer.class ) ) )
.thenAnswer( new Answer<Future<Integer>>()
{
@Override
public Future<Integer> answer( InvocationOnMock invocation ) throws Throwable
{
ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0];
bb.put( (byte) 3 );
bb.put( (byte) 4 );
Future<Integer> future = mock( Future.class );
when( future.get() ).thenReturn( 2 );
return future;
}
} );
InputStream is = Channels.newInputStream( channel );
ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass( ByteBuffer.class );
byte[] b = new byte[] { 1, 2, 0, 0, 5 };
is.read( b, 2, 2 );
verify( channel ).read( captured.capture() );
verifyNoMoreInteractions( channel );
assertThat( captured.getAllValues() )
.hasSize( 1 );
assertThat( captured.getAllValues().get( 0 ).array() )
.containsOnly( new byte[] { 1, 2, 3, 4, 5 } );
assertThat( captured.getAllValues().get( 0 ).arrayOffset() )
.isEqualTo( 0 );
assertThat( captured.getAllValues().get( 0 ).position() )
.isEqualTo( 4 );
assertThat( captured.getAllValues().get( 0 ).limit() )
.isEqualTo( 4 );
assertThat( captured.getAllValues().get( 0 ).capacity() )
.isEqualTo( 5 );
}
@Test
public void shouldRead() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
when( channel.read( any( ByteBuffer.class ) ) )
.thenAnswer( new Answer<Future<Integer>>()
{
@Override
public Future<Integer> answer( InvocationOnMock invocation ) throws Throwable
{
ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0];
bb.put( (byte) 3 );
Future<Integer> future = mock( Future.class );
when( future.get() ).thenReturn( 1 );
return future;
}
} );
InputStream is = Channels.newInputStream( channel );
ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass( ByteBuffer.class );
int b = is.read();
assertThat( b )
.isEqualTo( 3 );
verify( channel ).read( captured.capture() );
verifyNoMoreInteractions( channel );
assertThat( captured.getAllValues() )
.hasSize( 1 );
assertThat( captured.getAllValues().get( 0 ).array() )
.containsOnly( new byte[] { 3 } );
assertThat( captured.getAllValues().get( 0 ).arrayOffset() )
.isEqualTo( 0 );
assertThat( captured.getAllValues().get( 0 ).position() )
.isEqualTo( 1 );
assertThat( captured.getAllValues().get( 0 ).limit() )
.isEqualTo( 1 );
assertThat( captured.getAllValues().get( 0 ).capacity() )
.isEqualTo( 1 );
}
@Test
public void shouldThrowExceptionOnRead() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
when( channel.read( any( ByteBuffer.class ) ) )
.thenThrow( ShutdownChannelGroupException.class );
InputStream is = Channels.newInputStream( channel );
ee.expect( IOException.class );
ee.expectCause( instanceOf( ShutdownChannelGroupException.class ) );
is.read( new byte[1], 0, 1 );
}
@Test
public void shouldThrowExceptionOnFuture1() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
Future<Integer> future = mock( Future.class );
when( future.get() )
.thenThrow( new ExecutionException( new InterruptedIOException() ) );
when( channel.read( any( ByteBuffer.class ) ) )
.thenReturn( future );
InputStream is = Channels.newInputStream( channel );
ee.expect( InterruptedIOException.class );
is.read( new byte[1], 0, 1 );
}
@Test
public void shouldThrowExceptionOnFuture2() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
Future<Integer> future = mock( Future.class );
when( future.get() )
.thenThrow( new ExecutionException( new RuntimeException( "msg" ) ) );
when( channel.read( any( ByteBuffer.class ) ) )
.thenReturn( future );
InputStream is = Channels.newInputStream( channel );
ee.expect( IOException.class );
ee.expectCause( instanceOf( RuntimeException.class ) );
ee.expectMessage( "msg" );
is.read( new byte[1], 0, 1 );
}
@Test
public void shouldThrowExceptionOnFuture3() throws Exception
{
AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class );
Future<Integer> future = mock( Future.class );
when( future.get() )
.thenThrow( new ExecutionException( "msg", null ) );
when( channel.read( any( ByteBuffer.class ) ) )
.thenReturn( future );
InputStream is = Channels.newInputStream( channel );
ee.expect( IOException.class );
ee.expectMessage( "msg" );
is.read( new byte[1], 0, 1 );
}
}