@ -16,10 +16,12 @@
package org.springframework.core.io.buffer ;
package org.springframework.core.io.buffer ;
import java.io.IOException ;
import java.io.OutputStream ;
import java.io.OutputStream ;
import java.net.URI ;
import java.net.URI ;
import java.nio.ByteBuffer ;
import java.nio.ByteBuffer ;
import java.nio.channels.AsynchronousFileChannel ;
import java.nio.channels.AsynchronousFileChannel ;
import java.nio.channels.CompletionHandler ;
import java.nio.channels.FileChannel ;
import java.nio.channels.FileChannel ;
import java.nio.channels.ReadableByteChannel ;
import java.nio.channels.ReadableByteChannel ;
import java.nio.channels.WritableByteChannel ;
import java.nio.channels.WritableByteChannel ;
@ -29,7 +31,7 @@ import java.nio.file.Path;
import java.nio.file.Paths ;
import java.nio.file.Paths ;
import java.nio.file.StandardOpenOption ;
import java.nio.file.StandardOpenOption ;
import java.time.Duration ;
import java.time.Duration ;
import java.util.stream.Collectors ;
import java.util.concurrent.CountDownLatch ;
import io.netty.buffer.ByteBuf ;
import io.netty.buffer.ByteBuf ;
import org.junit.Test ;
import org.junit.Test ;
@ -160,9 +162,7 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
. expectComplete ( )
. expectComplete ( )
. verify ( Duration . ofSeconds ( 5 ) ) ;
. verify ( Duration . ofSeconds ( 5 ) ) ;
String result = Files . readAllLines ( tempFile )
String result = String . join ( "" , Files . readAllLines ( tempFile ) ) ;
. stream ( )
. collect ( Collectors . joining ( ) ) ;
assertEquals ( "foobarbazqux" , result ) ;
assertEquals ( "foobarbazqux" , result ) ;
os . close ( ) ;
os . close ( ) ;
@ -188,14 +188,60 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
. expectComplete ( )
. expectComplete ( )
. verify ( Duration . ofSeconds ( 5 ) ) ;
. verify ( Duration . ofSeconds ( 5 ) ) ;
String result = Files . readAllLines ( tempFile )
String result = String . join ( "" , Files . readAllLines ( tempFile ) ) ;
. stream ( )
. collect ( Collectors . joining ( ) ) ;
assertEquals ( "foobarbazqux" , result ) ;
assertEquals ( "foobarbazqux" , result ) ;
channel . close ( ) ;
channel . close ( ) ;
}
}
@Test
public void writeWritableByteChannelErrorInFlux ( ) throws Exception {
DataBuffer foo = stringBuffer ( "foo" ) ;
DataBuffer bar = stringBuffer ( "bar" ) ;
Flux < DataBuffer > flux = Flux . just ( foo , bar ) . concatWith ( Flux . error ( new RuntimeException ( ) ) ) ;
Path tempFile = Files . createTempFile ( "DataBufferUtilsTests" , null ) ;
WritableByteChannel channel = Files . newByteChannel ( tempFile , StandardOpenOption . WRITE ) ;
Flux < DataBuffer > writeResult = DataBufferUtils . write ( flux , channel ) ;
StepVerifier . create ( writeResult )
. consumeNextWith ( stringConsumer ( "foo" ) )
. consumeNextWith ( stringConsumer ( "bar" ) )
. expectError ( )
. verify ( Duration . ofSeconds ( 5 ) ) ;
String result = String . join ( "" , Files . readAllLines ( tempFile ) ) ;
assertEquals ( "foobar" , result ) ;
channel . close ( ) ;
}
@Test
public void writeWritableByteChannelErrorInWrite ( ) throws Exception {
DataBuffer foo = stringBuffer ( "foo" ) ;
DataBuffer bar = stringBuffer ( "bar" ) ;
Flux < DataBuffer > flux = Flux . just ( foo , bar ) ;
WritableByteChannel channel = mock ( WritableByteChannel . class ) ;
when ( channel . write ( any ( ) ) )
. thenAnswer ( invocation - > {
ByteBuffer buffer = invocation . getArgument ( 0 ) ;
int written = buffer . remaining ( ) ;
buffer . position ( buffer . limit ( ) ) ;
return written ;
} )
. thenThrow ( new IOException ( ) ) ;
Flux < DataBuffer > writeResult = DataBufferUtils . write ( flux , channel ) ;
StepVerifier . create ( writeResult )
. consumeNextWith ( stringConsumer ( "foo" ) )
. consumeNextWith ( stringConsumer ( "bar" ) )
. expectError ( IOException . class )
. verify ( ) ;
channel . close ( ) ;
}
@Test
@Test
public void writeAsynchronousFileChannel ( ) throws Exception {
public void writeAsynchronousFileChannel ( ) throws Exception {
DataBuffer foo = stringBuffer ( "foo" ) ;
DataBuffer foo = stringBuffer ( "foo" ) ;
@ -208,7 +254,7 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
AsynchronousFileChannel channel =
AsynchronousFileChannel channel =
AsynchronousFileChannel . open ( tempFile , StandardOpenOption . WRITE ) ;
AsynchronousFileChannel . open ( tempFile , StandardOpenOption . WRITE ) ;
Flux < DataBuffer > writeResult = DataBufferUtils . write ( flux , channel , 0 ) ;
Flux < DataBuffer > writeResult = DataBufferUtils . write ( flux , channel ) ;
StepVerifier . create ( writeResult )
StepVerifier . create ( writeResult )
. consumeNextWith ( stringConsumer ( "foo" ) )
. consumeNextWith ( stringConsumer ( "foo" ) )
. consumeNextWith ( stringConsumer ( "bar" ) )
. consumeNextWith ( stringConsumer ( "bar" ) )
@ -217,14 +263,142 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
. expectComplete ( )
. expectComplete ( )
. verify ( Duration . ofSeconds ( 5 ) ) ;
. verify ( Duration . ofSeconds ( 5 ) ) ;
String result = Files . readAllLines ( tempFile )
String result = String . join ( "" , Files . readAllLines ( tempFile ) ) ;
. stream ( )
. collect ( Collectors . joining ( ) ) ;
assertEquals ( "foobarbazqux" , result ) ;
assertEquals ( "foobarbazqux" , result ) ;
channel . close ( ) ;
channel . close ( ) ;
}
}
@Test
public void writeAsynchronousFileChannelErrorInFlux ( ) throws Exception {
DataBuffer foo = stringBuffer ( "foo" ) ;
DataBuffer bar = stringBuffer ( "bar" ) ;
Flux < DataBuffer > flux =
Flux . just ( foo , bar ) . concatWith ( Mono . error ( new RuntimeException ( ) ) ) ;
Path tempFile = Files . createTempFile ( "DataBufferUtilsTests" , null ) ;
AsynchronousFileChannel channel =
AsynchronousFileChannel . open ( tempFile , StandardOpenOption . WRITE ) ;
Flux < DataBuffer > writeResult = DataBufferUtils . write ( flux , channel ) ;
StepVerifier . create ( writeResult )
. consumeNextWith ( stringConsumer ( "foo" ) )
. consumeNextWith ( stringConsumer ( "bar" ) )
. expectError ( RuntimeException . class )
. verify ( ) ;
String result = String . join ( "" , Files . readAllLines ( tempFile ) ) ;
assertEquals ( "foobar" , result ) ;
channel . close ( ) ;
}
@Test
public void writeAsynchronousFileChannelErrorInWrite ( ) throws Exception {
DataBuffer foo = stringBuffer ( "foo" ) ;
DataBuffer bar = stringBuffer ( "bar" ) ;
Flux < DataBuffer > flux = Flux . just ( foo , bar ) ;
AsynchronousFileChannel channel = mock ( AsynchronousFileChannel . class ) ;
doAnswer ( invocation - > {
ByteBuffer buffer = invocation . getArgument ( 0 ) ;
long pos = invocation . getArgument ( 1 ) ;
CompletionHandler < Integer , ByteBuffer > completionHandler = invocation . getArgument ( 3 ) ;
assertEquals ( 0 , pos ) ;
int written = buffer . remaining ( ) ;
buffer . position ( buffer . limit ( ) ) ;
completionHandler . completed ( written , buffer ) ;
return null ;
} )
. doAnswer ( invocation - > {
ByteBuffer buffer = invocation . getArgument ( 0 ) ;
CompletionHandler < Integer , ByteBuffer > completionHandler =
invocation . getArgument ( 3 ) ;
completionHandler . failed ( new IOException ( ) , buffer ) ;
return null ;
} )
. when ( channel ) . write ( isA ( ByteBuffer . class ) , anyLong ( ) , isA ( ByteBuffer . class ) ,
isA ( CompletionHandler . class ) ) ;
Flux < DataBuffer > writeResult = DataBufferUtils . write ( flux , channel ) ;
StepVerifier . create ( writeResult )
. consumeNextWith ( stringConsumer ( "foo" ) )
. consumeNextWith ( stringConsumer ( "bar" ) )
. expectError ( IOException . class )
. verify ( ) ;
channel . close ( ) ;
}
@Test
public void readAndWriteByteChannel ( ) throws Exception {
Path source = Paths . get (
DataBufferUtilsTests . class . getResource ( "DataBufferUtilsTests.txt" ) . toURI ( ) ) ;
Flux < DataBuffer > sourceFlux =
DataBufferUtils
. readByteChannel ( ( ) - > FileChannel . open ( source , StandardOpenOption . READ ) ,
this . bufferFactory , 3 ) ;
Path destination = Files . createTempFile ( "DataBufferUtilsTests" , null ) ;
WritableByteChannel channel = Files . newByteChannel ( destination , StandardOpenOption . WRITE ) ;
DataBufferUtils . write ( sourceFlux , channel )
. subscribe ( DataBufferUtils . releaseConsumer ( ) ,
throwable - > fail ( throwable . getMessage ( ) ) ,
( ) - > {
try {
String expected = String . join ( "" , Files . readAllLines ( source ) ) ;
String result = String . join ( "" , Files . readAllLines ( destination ) ) ;
assertEquals ( expected , result ) ;
channel . close ( ) ;
}
catch ( IOException e ) {
fail ( e . getMessage ( ) ) ;
}
} ) ;
}
@Test
public void readAndWriteAsynchronousFileChannel ( ) throws Exception {
Path source = Paths . get (
DataBufferUtilsTests . class . getResource ( "DataBufferUtilsTests.txt" ) . toURI ( ) ) ;
Flux < DataBuffer > sourceFlux = DataBufferUtils . readAsynchronousFileChannel (
( ) - > AsynchronousFileChannel . open ( source , StandardOpenOption . READ ) ,
this . bufferFactory , 3 ) ;
Path destination = Files . createTempFile ( "DataBufferUtilsTests" , null ) ;
AsynchronousFileChannel channel =
AsynchronousFileChannel . open ( destination , StandardOpenOption . WRITE ) ;
CountDownLatch latch = new CountDownLatch ( 1 ) ;
DataBufferUtils . write ( sourceFlux , channel )
. subscribe ( DataBufferUtils : : release ,
throwable - > fail ( throwable . getMessage ( ) ) ,
( ) - > {
try {
String expected = String . join ( "" , Files . readAllLines ( source ) ) ;
String result = String . join ( "" , Files . readAllLines ( destination ) ) ;
assertEquals ( expected , result ) ;
channel . close ( ) ;
latch . countDown ( ) ;
}
catch ( IOException e ) {
fail ( e . getMessage ( ) ) ;
}
} ) ;
latch . await ( ) ;
}
@Test
@Test
public void takeUntilByteCount ( ) {
public void takeUntilByteCount ( ) {
@ -314,7 +488,8 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
. thenAnswer ( putByte ( 'c' ) )
. thenAnswer ( putByte ( 'c' ) )
. thenReturn ( - 1 ) ;
. thenReturn ( - 1 ) ;
Flux < DataBuffer > read = DataBufferUtils . readByteChannel ( ( ) - > channel , this . bufferFactory , 1 ) ;
Flux < DataBuffer > read =
DataBufferUtils . readByteChannel ( ( ) - > channel , this . bufferFactory , 1 ) ;
StepVerifier . create ( read )
StepVerifier . create ( read )
. consumeNextWith ( stringConsumer ( "a" ) )
. consumeNextWith ( stringConsumer ( "a" ) )
@ -343,7 +518,8 @@ public class DataBufferUtilsTests extends AbstractDataBufferAllocatingTestCase {
StepVerifier . create ( result )
StepVerifier . create ( result )
. consumeNextWith ( dataBuffer - > {
. consumeNextWith ( dataBuffer - > {
assertEquals ( "foobarbaz" , DataBufferTestUtils . dumpString ( dataBuffer , StandardCharsets . UTF_8 ) ) ;
assertEquals ( "foobarbaz" ,
DataBufferTestUtils . dumpString ( dataBuffer , StandardCharsets . UTF_8 ) ) ;
release ( dataBuffer ) ;
release ( dataBuffer ) ;
} )
} )
. verifyComplete ( ) ;
. verifyComplete ( ) ;