|
8 | 8 | import static org.junit.Assert.assertEquals; |
9 | 9 | import static org.junit.Assert.assertTrue; |
10 | 10 | import static org.mockito.ArgumentMatchers.any; |
| 11 | +import static org.mockito.ArgumentMatchers.anyInt; |
11 | 12 | import static org.mockito.ArgumentMatchers.anyString; |
12 | 13 | import static org.mockito.ArgumentMatchers.eq; |
13 | 14 | import static org.mockito.Mockito.*; |
14 | 15 |
|
15 | 16 | import java.io.ByteArrayOutputStream; |
16 | 17 | import java.io.IOError; |
| 18 | +import java.io.IOException; |
17 | 19 | import java.util.ArrayList; |
18 | 20 | import java.util.HashMap; |
19 | 21 | import java.util.HashSet; |
@@ -242,7 +244,7 @@ void testConcurrentRunWithPlatformThreads() throws Throwable { |
242 | 244 | AWSLambda.startRuntimeLoops(lambdaRequestHandler, lambdaLogger, concurrencyConfig, runtimeClient); |
243 | 245 |
|
244 | 246 | // Success Reports Must Equal number of tasks that ran successfully. |
245 | | - verify(runtimeClient, times(7)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), any()); |
| 247 | + verify(runtimeClient, times(7)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), anyInt(), any()); |
246 | 248 | // Hashmap keys should equal the number of threads (runtime loops). |
247 | 249 | assertEquals(4, SampleHandler.hashMap.size()); |
248 | 250 | // Hashmap total count should equal all tasks that ran * number of iterations per task |
@@ -284,7 +286,7 @@ void testConcurrentRunWithPlatformThreadsWithFailures() throws Throwable { |
284 | 286 | verify(runtimeClient).reportInvocationError(eq(UserFaultID), any(), any()); |
285 | 287 |
|
286 | 288 | // Success Reports Must Equal number of tasks that ran successfully. |
287 | | - verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), any()); |
| 289 | + verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), anyInt(), any()); |
288 | 290 |
|
289 | 291 | // Hashmap keys should equal the minumum between(number of threads (runtime loops) AND number of tasks that ran successfully). |
290 | 292 | assertEquals(2, SampleHandler.hashMap.size()); |
@@ -331,7 +333,7 @@ void testConcurrentModeLoopDoesNotExitExceptForLambdaRuntimeClientMaxRetriesExce |
331 | 333 | verify(runtimeClient).reportInvocationError(eq(IOErrorID), any(), any()); |
332 | 334 |
|
333 | 335 | // Success Reports Must Equal number of tasks that ran successfully. |
334 | | - verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), any()); |
| 336 | + verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), anyInt(), any()); |
335 | 337 |
|
336 | 338 | // Hashmap keys should equal the minumum between(number of threads (runtime loops) AND number of tasks that ran successfully). |
337 | 339 | assertEquals(1, SampleHandler.hashMap.size()); |
@@ -520,7 +522,7 @@ void testSequentialWithFatalUserFaultErrorStopsLoop() throws Throwable { |
520 | 522 | verify(runtimeClient).reportInvocationError(eq(UserFaultID), any(), any()); |
521 | 523 |
|
522 | 524 | // Success Reports Must Equal number of tasks that ran successfully. And only 2 Error reports for failImmediatelyRequest and userFaultRequest. |
523 | | - verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), any()); |
| 525 | + verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), anyInt(), any()); |
524 | 526 | verify(runtimeClient, times(2)).reportInvocationError(any(), any(), any()); |
525 | 527 |
|
526 | 528 | // Hashmap keys should equal one as it is not multithreaded. |
@@ -566,7 +568,7 @@ void testSequentialWithVirtualMachineErrorStopsLoop() throws Throwable { |
566 | 568 | verify(runtimeClient).reportInvocationError(eq(IOErrorID), any(), any()); |
567 | 569 |
|
568 | 570 | // Success Reports Must Equal number of tasks that ran successfully. And only 2 Error reports for failImmediatelyRequest and virtualMachineErrorRequest. |
569 | | - verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), any()); |
| 571 | + verify(runtimeClient, times(2)).reportInvocationSuccess(eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), anyInt(), any()); |
570 | 572 | verify(runtimeClient, times(2)).reportInvocationError(any(), any(), any()); |
571 | 573 |
|
572 | 574 | // Hashmap keys should equal one as it is not multithreaded. |
@@ -671,7 +673,68 @@ void testInvocationIdIsPassedToReportSuccess() throws Throwable { |
671 | 673 | AWSLambda.startRuntimeLoops(lambdaRequestHandler, lambdaLogger, concurrencyConfig, runtimeClient); |
672 | 674 |
|
673 | 675 | verify(runtimeClient).reportInvocationSuccess( |
674 | | - eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), eq("test-inv-uuid-1234")); |
| 676 | + eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), any(), anyInt(), eq("test-inv-uuid-1234")); |
| 677 | + } |
| 678 | + |
| 679 | + /** Exposes the backing array so tests can check that it is posted as is. */ |
| 680 | + private static final class InspectableByteArrayOutputStream extends ByteArrayOutputStream { |
| 681 | + byte[] backingArray() { |
| 682 | + return buf; |
| 683 | + } |
| 684 | + } |
| 685 | + |
| 686 | + /** Overrides writeTo the way a subclass could, one byte at a time, so the backing array cannot be captured. */ |
| 687 | + private static final class BytewiseWriteToByteArrayOutputStream extends ByteArrayOutputStream { |
| 688 | + @Override |
| 689 | + public synchronized void writeTo(java.io.OutputStream out) throws IOException { |
| 690 | + for (byte b : toByteArray()) { |
| 691 | + out.write(b); |
| 692 | + } |
| 693 | + } |
| 694 | + } |
| 695 | + |
| 696 | + private void runOneInvocation(LambdaRequestHandler handler) throws Throwable { |
| 697 | + when(concurrencyConfig.isMultiConcurrent()).thenReturn(false); |
| 698 | + |
| 699 | + InvocationRequest request = getFakeInvocationRequest(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE); |
| 700 | + request.setInvocationId("test-inv-uuid-1234"); |
| 701 | + |
| 702 | + // Fatal error to stop the loop after one successful invocation |
| 703 | + InvocationRequest fatalRequest = mock(InvocationRequest.class); |
| 704 | + when(fatalRequest.getId()).thenThrow(UserFault.makeUserFault(new IOError(new Throwable()), true)).thenReturn("fatal"); |
| 705 | + |
| 706 | + when(runtimeClient.nextInvocation()) |
| 707 | + .thenReturn(request) |
| 708 | + .thenReturn(fatalRequest); |
| 709 | + |
| 710 | + AWSLambda.startRuntimeLoops(handler, lambdaLogger, concurrencyConfig, runtimeClient); |
| 711 | + } |
| 712 | + |
| 713 | + @Test |
| 714 | + @Timeout(value = 1, unit = TimeUnit.MINUTES) |
| 715 | + void testResponseBackingArrayIsPostedWithoutCopy() throws Throwable { |
| 716 | + InspectableByteArrayOutputStream output = new InspectableByteArrayOutputStream(); |
| 717 | + output.write("\"success\"".getBytes()); |
| 718 | + |
| 719 | + runOneInvocation(request -> output); |
| 720 | + |
| 721 | + // The backing array itself is passed, with the content length, instead of a toByteArray() copy. |
| 722 | + verify(runtimeClient).reportInvocationSuccess( |
| 723 | + eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), same(output.backingArray()), eq(9), eq("test-inv-uuid-1234")); |
| 724 | + verify(runtimeClient, never()).reportInvocationSuccess(anyString(), any(), any()); |
| 725 | + } |
| 726 | + |
| 727 | + @Test |
| 728 | + @Timeout(value = 1, unit = TimeUnit.MINUTES) |
| 729 | + void testResponseIsCopiedWhenWriteToDoesNotPassTheBackingArray() throws Throwable { |
| 730 | + ByteArrayOutputStream output = new BytewiseWriteToByteArrayOutputStream(); |
| 731 | + output.write("\"success\"".getBytes()); |
| 732 | + |
| 733 | + runOneInvocation(request -> output); |
| 734 | + |
| 735 | + verify(runtimeClient).reportInvocationSuccess( |
| 736 | + eq(SampleHandler.ADD_ENTRY_TO_MAP_ID_OP_MODE), eq("\"success\"".getBytes()), eq("test-inv-uuid-1234")); |
| 737 | + verify(runtimeClient, never()).reportInvocationSuccess(anyString(), any(), anyInt(), any()); |
675 | 738 | } |
676 | 739 |
|
677 | 740 | @Test |
|
0 commit comments