|
9 | 9 | import org.junit.jupiter.api.Test; |
10 | 10 | import org.junit.jupiter.api.condition.DisabledOnOs; |
11 | 11 | import org.junit.jupiter.api.condition.OS; |
| 12 | +import org.junit.jupiter.api.parallel.ResourceLock; |
| 13 | +import org.junit.jupiter.api.parallel.Resources; |
12 | 14 |
|
13 | 15 | import static org.junit.jupiter.api.Assertions.assertTrue; |
14 | 16 | import static org.junit.jupiter.api.Assertions.assertNull; |
|
22 | 24 | import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayErrorCause; |
23 | 25 | import com.amazonaws.services.lambda.runtime.api.client.runtimeapi.dto.XRayException; |
24 | 26 |
|
| 27 | +import java.net.Inet4Address; |
| 28 | +import java.net.InetAddress; |
| 29 | +import java.net.NetworkInterface; |
25 | 30 | import java.util.ArrayList; |
| 31 | +import java.util.Enumeration; |
26 | 32 | import java.util.List; |
27 | 33 | import java.util.function.Function; |
28 | 34 | import java.util.function.Supplier; |
29 | 35 |
|
30 | 36 | import static org.junit.jupiter.api.Assertions.fail; |
| 37 | +import static org.junit.jupiter.api.Assumptions.assumeTrue; |
31 | 38 | import static org.mockito.ArgumentMatchers.any; |
32 | 39 | import static org.mockito.ArgumentMatchers.anyString; |
33 | 40 | import static org.mockito.ArgumentMatchers.eq; |
@@ -533,6 +540,75 @@ public void reportInvocationErrorWithInvocationIdTest() { |
533 | 540 | } |
534 | 541 | } |
535 | 542 |
|
| 543 | + @Test |
| 544 | + @ResourceLock(Resources.SYSTEM_PROPERTIES) |
| 545 | + public void connectionBypassesConfiguredProxy() throws Exception { |
| 546 | + // Bind RAPID mock to a non-loopback IPv4 so Java's ProxySelector doesn't |
| 547 | + // auto-exempt it. On loopback (127.0.0.1), the JVM skips proxy regardless. |
| 548 | + InetAddress nonLoopback = findNonLoopbackIPv4(); |
| 549 | + assumeTrue(nonLoopback != null, "No non-loopback IPv4 address available for proxy-bypass test"); |
| 550 | + |
| 551 | + MockWebServer nonLoopbackServer = new MockWebServer(); |
| 552 | + nonLoopbackServer.start(nonLoopback, 0); |
| 553 | + |
| 554 | + MockWebServer fakeProxy = new MockWebServer(); |
| 555 | + fakeProxy.start(); |
| 556 | + // Enqueue a response so if proxy is used, the test fails fast instead of hanging indefinitely. |
| 557 | + fakeProxy.enqueue(new MockResponse().setResponseCode(HTTP_ACCEPTED)); |
| 558 | + |
| 559 | + String previousProxyHost = System.getProperty("http.proxyHost"); |
| 560 | + String previousProxyPort = System.getProperty("http.proxyPort"); |
| 561 | + |
| 562 | + System.setProperty("http.proxyHost", fakeProxy.getHostName()); |
| 563 | + System.setProperty("http.proxyPort", String.valueOf(fakeProxy.getPort())); |
| 564 | + |
| 565 | + try { |
| 566 | + MockResponse mockResponse = new MockResponse(); |
| 567 | + mockResponse.setResponseCode(HTTP_ACCEPTED); |
| 568 | + nonLoopbackServer.enqueue(mockResponse); |
| 569 | + |
| 570 | + String endpoint = "http://" + nonLoopback.getHostAddress() + ":" + nonLoopbackServer.getPort(); |
| 571 | + LambdaError lambdaError = new LambdaError(errorRequest, RapidErrorType.AfterRestoreError); |
| 572 | + lambdaRuntimeApiClientImpl.reportLambdaError(endpoint, lambdaError, 1024 * 1024, null); |
| 573 | + |
| 574 | + // Request arrived at RAPID mock directly |
| 575 | + assertEquals(1, nonLoopbackServer.getRequestCount()); |
| 576 | + // Nothing went to the fake proxy |
| 577 | + assertEquals(0, fakeProxy.getRequestCount()); |
| 578 | + } finally { |
| 579 | + if (previousProxyHost != null) { |
| 580 | + System.setProperty("http.proxyHost", previousProxyHost); |
| 581 | + } else { |
| 582 | + System.clearProperty("http.proxyHost"); |
| 583 | + } |
| 584 | + if (previousProxyPort != null) { |
| 585 | + System.setProperty("http.proxyPort", previousProxyPort); |
| 586 | + } else { |
| 587 | + System.clearProperty("http.proxyPort"); |
| 588 | + } |
| 589 | + nonLoopbackServer.shutdown(); |
| 590 | + fakeProxy.shutdown(); |
| 591 | + } |
| 592 | + } |
| 593 | + |
| 594 | + private InetAddress findNonLoopbackIPv4() throws Exception { |
| 595 | + Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces(); |
| 596 | + while (ifaces.hasMoreElements()) { |
| 597 | + NetworkInterface iface = ifaces.nextElement(); |
| 598 | + if (!iface.isUp() || iface.isLoopback() || iface.isVirtual()) { |
| 599 | + continue; |
| 600 | + } |
| 601 | + Enumeration<InetAddress> addrs = iface.getInetAddresses(); |
| 602 | + while (addrs.hasMoreElements()) { |
| 603 | + InetAddress addr = addrs.nextElement(); |
| 604 | + if (addr instanceof Inet4Address && !addr.isLoopbackAddress() && !addr.isLinkLocalAddress()) { |
| 605 | + return addr; |
| 606 | + } |
| 607 | + } |
| 608 | + } |
| 609 | + return null; |
| 610 | + } |
| 611 | + |
536 | 612 | private String getHostnamePort() { |
537 | 613 | return mockWebServer.getHostName() + ":" + mockWebServer.getPort(); |
538 | 614 | } |
|
0 commit comments