|
43 | 43 | import java.util.concurrent.TimeoutException; |
44 | 44 | import java.util.concurrent.atomic.AtomicBoolean; |
45 | 45 | import java.util.concurrent.atomic.AtomicReference; |
| 46 | +import java.util.stream.Stream; |
46 | 47 | import javax.net.ssl.SSLEngine; |
47 | 48 | import org.junit.jupiter.api.AfterAll; |
48 | 49 | import org.junit.jupiter.api.BeforeAll; |
49 | 50 | import org.junit.jupiter.api.Test; |
| 51 | +import org.junit.jupiter.params.ParameterizedTest; |
| 52 | +import org.junit.jupiter.params.provider.Arguments; |
| 53 | +import org.junit.jupiter.params.provider.MethodSource; |
50 | 54 | import org.mockito.Mockito; |
51 | 55 | import org.slf4j.Logger; |
| 56 | +import software.amazon.awssdk.http.nio.netty.internal.ChannelDiagnostics; |
52 | 57 | import software.amazon.awssdk.http.nio.netty.internal.MockChannel; |
53 | 58 |
|
54 | 59 | public class NettyUtilsTest { |
@@ -274,108 +279,96 @@ public void closedChannelMessage_with_nullParentChannelAttribute() throws Except |
274 | 279 | .isEqualTo(NettyUtils.CLOSED_CHANNEL_ERROR_MESSAGE); |
275 | 280 | } |
276 | 281 |
|
277 | | - @Test |
278 | | - public void decorateException_with_TimeoutException() { |
| 282 | + private static Stream<Arguments> decorateExceptionWrappedCases() { |
| 283 | + return Stream.of( |
| 284 | + Arguments.of(new TimeoutException("...Acquire operation took longer..."), |
| 285 | + Throwable.class, TimeoutException.class), |
| 286 | + Arguments.of(new IllegalStateException("...Too many outstanding acquire operations..."), |
| 287 | + Throwable.class, IllegalStateException.class), |
| 288 | + Arguments.of(new ReadTimeoutException(), |
| 289 | + IOException.class, ReadTimeoutException.class), |
| 290 | + Arguments.of(new WriteTimeoutException(), |
| 291 | + IOException.class, WriteTimeoutException.class), |
| 292 | + Arguments.of(new ClosedChannelException(), |
| 293 | + IOException.class, ClosedChannelException.class), |
| 294 | + Arguments.of(new IOException("...Connection reset by peer..."), |
| 295 | + IOException.class, IOException.class) |
| 296 | + ); |
| 297 | + } |
279 | 298 |
|
| 299 | + @ParameterizedTest |
| 300 | + @MethodSource("decorateExceptionWrappedCases") |
| 301 | + public void decorateException_wrapsException(Throwable input, |
| 302 | + Class<? extends Throwable> expectedType, |
| 303 | + Class<? extends Throwable> expectedCauseType) { |
280 | 304 | Channel channel = mock(Channel.class); |
281 | | - Throwable timeoutException = new TimeoutException("...Acquire operation took longer..."); |
282 | | - Throwable output = NettyUtils.decorateException(channel, timeoutException); |
| 305 | + Throwable output = NettyUtils.decorateException(channel, input); |
283 | 306 |
|
284 | | - assertThat(output).isInstanceOf(Throwable.class); |
285 | | - assertThat(output.getCause()).isInstanceOf(TimeoutException.class); |
| 307 | + assertThat(output).isInstanceOf(expectedType); |
| 308 | + assertThat(output.getCause()).isInstanceOf(expectedCauseType); |
286 | 309 | assertThat(output.getMessage()).isNotNull(); |
287 | 310 | } |
288 | 311 |
|
289 | | - @Test |
290 | | - public void decorateException_with_TimeoutException_noMsg() { |
291 | | - |
292 | | - Channel channel = mock(Channel.class); |
293 | | - Throwable timeoutException = new TimeoutException(); |
294 | | - Throwable output = NettyUtils.decorateException(channel, timeoutException); |
295 | | - |
296 | | - assertThat(output).isInstanceOf(TimeoutException.class); |
297 | | - assertThat(output.getCause()).isNull(); |
| 312 | + private static Stream<Arguments> decorateExceptionPassthroughCases() { |
| 313 | + return Stream.of( |
| 314 | + Arguments.of(new TimeoutException()), |
| 315 | + Arguments.of(new IllegalStateException()), |
| 316 | + Arguments.of(new IOException()) |
| 317 | + ); |
298 | 318 | } |
299 | 319 |
|
300 | | - @Test |
301 | | - public void decorateException_with_IllegalStateException() { |
302 | | - |
| 320 | + @ParameterizedTest |
| 321 | + @MethodSource("decorateExceptionPassthroughCases") |
| 322 | + public void decorateException_noMatchingMessage_returnsOriginal(Throwable input) { |
303 | 323 | Channel channel = mock(Channel.class); |
304 | | - Throwable illegalStateException = new IllegalStateException("...Too many outstanding acquire operations..."); |
305 | | - Throwable output = NettyUtils.decorateException(channel, illegalStateException); |
| 324 | + Throwable output = NettyUtils.decorateException(channel, input); |
306 | 325 |
|
307 | | - assertThat(output).isInstanceOf(Throwable.class); |
308 | | - assertThat(output.getCause()).isInstanceOf(IllegalStateException.class); |
309 | | - assertThat(output.getMessage()).isNotNull(); |
| 326 | + assertThat(output).isSameAs(input); |
310 | 327 | } |
311 | 328 |
|
312 | | - @Test |
313 | | - public void decorateException_with_IllegalStateException_noMsg() { |
314 | | - |
315 | | - Channel channel = mock(Channel.class); |
316 | | - Throwable illegalStateException = new IllegalStateException(); |
317 | | - Throwable output = NettyUtils.decorateException(channel, illegalStateException); |
318 | | - |
319 | | - assertThat(output).isInstanceOf(IllegalStateException.class); |
320 | | - assertThat(output.getCause()).isNull(); |
| 329 | + private static Stream<Arguments> channelDiagnosticsExceptionCases() { |
| 330 | + return Stream.of( |
| 331 | + Arguments.of(new ReadTimeoutException(), "Read timed out"), |
| 332 | + Arguments.of(new WriteTimeoutException(), "Write timed out") |
| 333 | + ); |
321 | 334 | } |
322 | 335 |
|
323 | | - @Test |
324 | | - public void decorateException_with_ReadTimeoutException() { |
325 | | - |
| 336 | + @ParameterizedTest |
| 337 | + @MethodSource("channelDiagnosticsExceptionCases") |
| 338 | + public void decorateException_includesChannelDiagnostics(Throwable input, String expectedPrefix) { |
326 | 339 | Channel channel = mock(Channel.class); |
327 | | - Throwable readTimeoutException = new ReadTimeoutException(); |
328 | | - Throwable output = NettyUtils.decorateException(channel, readTimeoutException); |
329 | | - |
330 | | - assertThat(output).isInstanceOf(IOException.class); |
331 | | - assertThat(output.getCause()).isInstanceOf(ReadTimeoutException.class); |
332 | | - assertThat(output.getMessage()).isNotNull(); |
333 | | - } |
334 | | - |
335 | | - @Test |
336 | | - public void decorateException_with_WriteTimeoutException() { |
| 340 | + Attribute attribute = mock(Attribute.class); |
| 341 | + ChannelDiagnostics diagnostics = new ChannelDiagnostics(channel); |
| 342 | + when(channel.attr(any())).thenReturn(attribute); |
| 343 | + when(attribute.get()).thenReturn(diagnostics); |
| 344 | + when(channel.parent()).thenReturn(null); |
337 | 345 |
|
338 | | - Channel channel = mock(Channel.class); |
339 | | - Throwable writeTimeoutException = new WriteTimeoutException(); |
340 | | - Throwable output = NettyUtils.decorateException(channel, writeTimeoutException); |
| 346 | + Throwable output = NettyUtils.decorateException(channel, input); |
341 | 347 |
|
342 | 348 | assertThat(output).isInstanceOf(IOException.class); |
343 | | - assertThat(output.getCause()).isInstanceOf(WriteTimeoutException.class); |
344 | | - assertThat(output.getMessage()).isNotNull(); |
| 349 | + assertThat(output.getMessage()).startsWith(expectedPrefix); |
| 350 | + assertThat(output.getMessage()).contains("Channel Information:"); |
345 | 351 | } |
346 | 352 |
|
347 | 353 | @Test |
348 | | - public void decorateException_with_ClosedChannelException() { |
349 | | - |
350 | | - Channel channel = mock(Channel.class); |
351 | | - Throwable closedChannelException = new ClosedChannelException(); |
352 | | - Throwable output = NettyUtils.decorateException(channel, closedChannelException); |
353 | | - |
354 | | - assertThat(output).isInstanceOf(IOException.class); |
355 | | - assertThat(output.getCause()).isInstanceOf(ClosedChannelException.class); |
356 | | - assertThat(output.getMessage()).isNotNull(); |
| 354 | + public void errorMessageWithChannelDiagnostics_nullChannel_returnsBaseMessage() { |
| 355 | + assertThat(NettyUtils.errorMessageWithChannelDiagnostics(null, "test message")) |
| 356 | + .isEqualTo("test message"); |
357 | 357 | } |
358 | 358 |
|
359 | 359 | @Test |
360 | | - public void decorateException_with_IOException_reset() { |
361 | | - |
| 360 | + public void errorMessageWithChannelDiagnostics_withDiagnostics_appendsChannelInfo() { |
362 | 361 | Channel channel = mock(Channel.class); |
363 | | - Throwable closedChannelException = new IOException("...Connection reset by peer..."); |
364 | | - Throwable output = NettyUtils.decorateException(channel, closedChannelException); |
365 | | - |
366 | | - assertThat(output).isInstanceOf(IOException.class); |
367 | | - assertThat(output.getCause()).isInstanceOf(IOException.class); |
368 | | - assertThat(output.getMessage()).isNotNull(); |
369 | | - } |
370 | | - |
371 | | - @Test |
372 | | - public void decorateException_with_IOException_noMsg() { |
| 362 | + Attribute attribute = mock(Attribute.class); |
| 363 | + ChannelDiagnostics diagnostics = new ChannelDiagnostics(channel); |
| 364 | + when(channel.attr(any())).thenReturn(attribute); |
| 365 | + when(attribute.get()).thenReturn(diagnostics); |
| 366 | + when(channel.parent()).thenReturn(null); |
373 | 367 |
|
374 | | - Channel channel = mock(Channel.class); |
375 | | - Throwable closedChannelException = new IOException(); |
376 | | - Throwable output = NettyUtils.decorateException(channel, closedChannelException); |
| 368 | + String result = NettyUtils.errorMessageWithChannelDiagnostics(channel, "custom error"); |
377 | 369 |
|
378 | | - assertThat(output).isInstanceOf(IOException.class); |
379 | | - assertThat(output.getCause()).isNull(); |
| 370 | + assertThat(result).startsWith("custom error"); |
| 371 | + assertThat(result).contains("Channel Information:"); |
380 | 372 | } |
| 373 | + |
381 | 374 | } |
0 commit comments