Skip to content

Commit 7af4c50

Browse files
authored
Catch UncheckedIOException and throw as IOException (#5201)
* InputStreamSubscriber catch and throw UncheckedIOException as IOException * Use utils helper in test
1 parent fe578e9 commit 7af4c50

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,8 @@
650650
<includeModule>netty-nio-client</includeModule>
651651
<includeModule>url-connection-client</includeModule>
652652
<includeModule>cloudwatch-metric-publisher</includeModule>
653-
<includeModule>utils</includeModule>
653+
<!-- TODO revert - Temporarily disable utils to add throws IOException to InputStreamSubscriber.read() -->
654+
<!-- <includeModule>utils</includeModule> -->
654655
<includeModule>imds</includeModule>
655656

656657
<!-- High level libraries -->

utils/src/main/java/software/amazon/awssdk/utils/async/InputStreamSubscriber.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515

1616
package software.amazon.awssdk.utils.async;
1717

18+
import java.io.IOException;
1819
import java.io.InputStream;
20+
import java.io.UncheckedIOException;
1921
import java.nio.ByteBuffer;
2022
import java.util.Queue;
2123
import java.util.concurrent.CancellationException;
@@ -25,6 +27,7 @@
2527
import org.reactivestreams.Subscriber;
2628
import org.reactivestreams.Subscription;
2729
import software.amazon.awssdk.annotations.SdkProtectedApi;
30+
import software.amazon.awssdk.annotations.SdkTestInternalApi;
2831
import software.amazon.awssdk.utils.SdkAutoCloseable;
2932
import software.amazon.awssdk.utils.async.ByteBufferStoringSubscriber.TransferResult;
3033

@@ -55,6 +58,11 @@ public InputStreamSubscriber() {
5558
this.delegate = new ByteBufferStoringSubscriber(BUFFER_SIZE);
5659
}
5760

61+
@SdkTestInternalApi
62+
public InputStreamSubscriber(ByteBufferStoringSubscriber delegate) {
63+
this.delegate = delegate;
64+
}
65+
5866
@Override
5967
public void onSubscribe(Subscription s) {
6068
synchronized (subscribeLock) {
@@ -90,9 +98,15 @@ public void onComplete() {
9098
}
9199

92100
@Override
93-
public int read() {
101+
public int read() throws IOException {
94102
singleByte.clear();
95-
TransferResult transferResult = delegate.blockingTransferTo(singleByte);
103+
104+
TransferResult transferResult;
105+
try {
106+
transferResult = delegate.blockingTransferTo(singleByte);
107+
} catch (UncheckedIOException e) {
108+
throw e.getCause();
109+
}
96110

97111
if (singleByte.hasRemaining()) {
98112
assert transferResult == TransferResult.END_OF_STREAM;
@@ -103,18 +117,25 @@ public int read() {
103117
}
104118

105119
@Override
106-
public int read(byte[] b) {
120+
public int read(byte[] b) throws IOException {
107121
return read(b, 0, b.length);
108122
}
109123

110124
@Override
111-
public int read(byte[] bytes, int off, int len) {
125+
public int read(byte[] bytes, int off, int len) throws IOException {
112126
if (len == 0) {
113127
return 0;
114128
}
115129

116130
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes, off, len);
117-
TransferResult transferResult = delegate.blockingTransferTo(byteBuffer);
131+
132+
TransferResult transferResult;
133+
try {
134+
transferResult = delegate.blockingTransferTo(byteBuffer);
135+
} catch (UncheckedIOException e) {
136+
throw e.getCause();
137+
}
138+
118139
int dataTransferred = byteBuffer.position() - off;
119140

120141
if (dataTransferred == 0) {

utils/src/test/java/software/amazon/awssdk/utils/async/InputStreamSubscriberTest.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
1919
import static org.assertj.core.api.Assertions.assertThatThrownBy;
20+
import static org.mockito.ArgumentMatchers.any;
2021
import static org.mockito.ArgumentMatchers.anyLong;
2122
import static org.mockito.Mockito.doAnswer;
2223
import static org.mockito.Mockito.mock;
24+
import static org.mockito.Mockito.when;
2325

26+
import java.io.IOException;
27+
import java.io.UncheckedIOException;
2428
import java.nio.ByteBuffer;
2529
import java.util.ArrayList;
2630
import java.util.List;
@@ -41,6 +45,7 @@
4145
import org.mockito.stubbing.Answer;
4246
import org.reactivestreams.Subscriber;
4347
import org.reactivestreams.Subscription;
48+
import software.amazon.awssdk.utils.FunctionalUtils;
4449
import software.amazon.awssdk.utils.ThreadFactoryBuilder;
4550

4651
public class InputStreamSubscriberTest {
@@ -54,7 +59,7 @@ public void setup() {
5459
}
5560

5661
@Test
57-
public void onComplete_returnsEndOfStream_onRead() {
62+
public void onComplete_returnsEndOfStream_onRead() throws IOException {
5863
publisher.subscribe(subscriber);
5964
publisher.complete();
6065
assertThat(subscriber.read()).isEqualTo(-1);
@@ -74,7 +79,7 @@ public void onError_throws_onRead() {
7479
}
7580

7681
@Test
77-
public void onComplete_afterOnNext_returnsEndOfStream() {
82+
public void onComplete_afterOnNext_returnsEndOfStream() throws IOException {
7883
publisher.subscribe(subscriber);
7984
publisher.send(byteBufferOfLength(1));
8085
publisher.complete();
@@ -83,7 +88,7 @@ public void onComplete_afterOnNext_returnsEndOfStream() {
8388
}
8489

8590
@Test
86-
public void onComplete_afterEmptyOnNext_returnsEndOfStream() {
91+
public void onComplete_afterEmptyOnNext_returnsEndOfStream() throws IOException {
8792
publisher.subscribe(subscriber);
8893
publisher.send(byteBufferOfLength(0));
8994
publisher.send(byteBufferOfLength(0));
@@ -93,14 +98,14 @@ public void onComplete_afterEmptyOnNext_returnsEndOfStream() {
9398
}
9499

95100
@Test
96-
public void read_afterOnNext_returnsData() {
101+
public void read_afterOnNext_returnsData() throws IOException {
97102
publisher.subscribe(subscriber);
98103
publisher.send(byteBufferWithByte(10));
99104
assertThat(subscriber.read()).isEqualTo(10);
100105
}
101106

102107
@Test
103-
public void readBytes_afterOnNext_returnsData() {
108+
public void readBytes_afterOnNext_returnsData() throws IOException {
104109
publisher.subscribe(subscriber);
105110
publisher.send(byteBufferWithByte(10));
106111
publisher.send(byteBufferWithByte(20));
@@ -112,7 +117,7 @@ public void readBytes_afterOnNext_returnsData() {
112117
}
113118

114119
@Test
115-
public void readBytesWithOffset_afterOnNext_returnsData() {
120+
public void readBytesWithOffset_afterOnNext_returnsData() throws IOException {
116121
publisher.subscribe(subscriber);
117122
publisher.send(byteBufferWithByte(10));
118123
publisher.send(byteBufferWithByte(20));
@@ -133,7 +138,7 @@ public void read_afterClose_fails() {
133138
}
134139

135140
@Test
136-
public void readByteArray_0Len_returns0() {
141+
public void readByteArray_0Len_returns0() throws IOException {
137142
publisher.subscribe(subscriber);
138143

139144
assertThat(subscriber.read(new byte[1], 0, 0)).isEqualTo(0);
@@ -211,6 +216,18 @@ public void stochastic_methodCallsSeemThreadSafe(Consumer<InputStreamSubscriber>
211216
}
212217
}
213218

219+
@Test
220+
public void read_uncheckedIOException_isThrownAsIOException() {
221+
ByteBufferStoringSubscriber byteBufferStoringSubscriber = mock(ByteBufferStoringSubscriber.class);
222+
when(byteBufferStoringSubscriber.blockingTransferTo(any()))
223+
.thenThrow(new UncheckedIOException(new IOException("Not wrapped as UncheckedIOException")));
224+
InputStreamSubscriber errorSubscriber = new InputStreamSubscriber(byteBufferStoringSubscriber);
225+
226+
assertThatThrownBy(() -> errorSubscriber.read(new byte[1]))
227+
.isInstanceOf(IOException.class).hasMessage("Not wrapped as UncheckedIOException");
228+
229+
}
230+
214231
public static Consumer<InputStreamSubscriber> subscriberOnNext() {
215232
return s -> s.onNext(ByteBuffer.allocate(1));
216233
}
@@ -224,11 +241,11 @@ public static Consumer<InputStreamSubscriber> subscriberOnError() {
224241
}
225242

226243
public static Consumer<InputStreamSubscriber> subscriberRead1() {
227-
return s -> s.read();
244+
return s -> FunctionalUtils.invokeSafely(() -> s.read());
228245
}
229246

230247
public static Consumer<InputStreamSubscriber> subscriberReadArray() {
231-
return s -> s.read(new byte[4]);
248+
return s -> FunctionalUtils.invokeSafely(() -> s.read(new byte[4]));
232249
}
233250

234251
public static Consumer<InputStreamSubscriber> subscriberClose() {

0 commit comments

Comments
 (0)