-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enhance ShadowingInterceptor (#1260)
* Enhance ShadowingInterceptor by adding exchange construction method Refactor cloneRequestAndSend to accept an Exchange parameter and use a new buildExchange method for creating requests. Update tests to validate the new functionality in ShadowingInterceptor. * Enhance HeaderField and ShadowingInterceptor to use new HeaderName constructor. Update tests to validate header behavior. * Refactor imports in ShadowingInterceptorTest to streamline code structure * Refactor ShadowingInterceptorTest to use Mockito for ReturnInterceptor Update the test class by removing unnecessary imports and extending the base class. Implement Mockito to create a spy for ReturnInterceptor to verify its behavior during the interceptor test. Ensure proper setup and teardown of routers and interceptors for better isolation in tests. * Refactor ShadowingInterceptor tests for clarity and consistency - Rename router variables to improve clarity: `router` to `interceptorRouter`, `router2` to `shadowingRouter`. - Update corresponding rule variable names to match new router names: `shadowingRule` to `interceptorRule`. - Enhance test method name to `testIfShadowTargetIsCalled()` for better description. - Clean up initialization and shutdown logic in test setup and teardown. * Refactor ShadowingInterceptorTest to use RestAssured for HTTP calls Replace custom assertion method getAndAssert200 with a RestAssured equivalent for improved readability and consistency in test case. * Refactor HeaderField and HeaderName constructors for efficiency Remove unnecessary object creation in HeaderField copy constructor. Simplify HeaderName by removing redundant copy constructor. * Enhance ShadowingInterceptor to include header in request cloning - Add header parameter to cloneRequestAndSend and buildExchange methods - Capture request headers for shadowing functionality - Update tests to verify header handling during shadow requests * Enhance ShadowingInterceptor to copy request headers for cloned requests. Update method parameters for clarity and consistency. Improve error logging to reflect shadow target details.
- Loading branch information
1 parent
46d078d
commit db40fd1
Showing
3 changed files
with
159 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
143 changes: 125 additions & 18 deletions
143
...c/test/java/com/predic8/membrane/core/interceptor/shadowing/ShadowingInterceptorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,144 @@ | ||
package com.predic8.membrane.core.interceptor.shadowing; | ||
|
||
import com.predic8.membrane.core.Router; | ||
import com.predic8.membrane.core.exchange.Exchange; | ||
import com.predic8.membrane.core.exchangestore.ForgetfulExchangeStore; | ||
import com.predic8.membrane.core.http.Body; | ||
import com.predic8.membrane.core.http.Header; | ||
import com.predic8.membrane.core.http.Request; | ||
import com.predic8.membrane.core.interceptor.misc.ReturnInterceptor; | ||
import com.predic8.membrane.core.interceptor.misc.SetHeaderInterceptor; | ||
import com.predic8.membrane.core.rules.AbstractServiceProxy.Target; | ||
import com.predic8.membrane.core.rules.Rule; | ||
import com.predic8.membrane.core.rules.ServiceProxy; | ||
import com.predic8.membrane.core.rules.ServiceProxyKey; | ||
import com.predic8.membrane.core.transport.http.HttpTransport; | ||
import org.junit.jupiter.api.AfterAll; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.mockito.Mock; | ||
import org.mockito.MockitoAnnotations; | ||
import org.mockito.ArgumentCaptor; | ||
import org.mockito.Mockito; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.mockito.Mockito.when; | ||
import java.util.List; | ||
|
||
import static com.predic8.membrane.core.http.MimeType.APPLICATION_JSON; | ||
import static io.restassured.RestAssured.given; | ||
import static org.junit.jupiter.api.Assertions.*; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.*; | ||
|
||
class ShadowingInterceptorTest { | ||
|
||
@Mock | ||
private Target mockTarget; | ||
Exchange exc; | ||
Header header; | ||
|
||
static Router interceptorRouter; | ||
static Router shadowingRouter; | ||
|
||
static Rule interceptorRule; | ||
static ShadowingInterceptor shadowingInterceptor; | ||
|
||
static ReturnInterceptor returnInterceptorMock; | ||
|
||
static Rule shadowingRule; | ||
|
||
@BeforeEach | ||
void setUp() { | ||
MockitoAnnotations.openMocks(this); | ||
void setUp() throws Exception { | ||
header = new Header(){{ | ||
add(CONTENT_TYPE, APPLICATION_JSON); | ||
}}; | ||
exc = ShadowingInterceptor.buildExchange( | ||
new Body("foo".getBytes()), | ||
new Request.Builder() | ||
.post("https://www.google.com") | ||
.header(header) | ||
.buildExchange(), | ||
new Target() {{ | ||
setUrl("https://www.predic8.com:9000/foo"); | ||
}}, | ||
header | ||
); | ||
} | ||
|
||
@BeforeAll | ||
static void startup() throws Exception { | ||
interceptorRouter = new Router(); | ||
interceptorRouter.setHotDeploy(false); | ||
interceptorRouter.setExchangeStore(new ForgetfulExchangeStore()); | ||
interceptorRouter.setTransport(new HttpTransport()); | ||
|
||
interceptorRule = new ServiceProxy(new ServiceProxyKey("localhost", "*", ".*", 2000), null, 0); | ||
shadowingInterceptor = new ShadowingInterceptor(); | ||
shadowingInterceptor.setTargets(List.of(new Target() {{ | ||
setHost("localhost"); | ||
setPort(3000); | ||
}})); | ||
interceptorRule.setInterceptors(List.of( | ||
shadowingInterceptor, | ||
new SetHeaderInterceptor() {{ | ||
setName("foo"); | ||
setValue("bar"); | ||
}}, | ||
new ReturnInterceptor() | ||
)); | ||
|
||
interceptorRouter.getRuleManager().addProxyAndOpenPortIfNew(interceptorRule); | ||
interceptorRouter.init(); | ||
interceptorRouter.start(); | ||
|
||
shadowingRouter = new Router(); | ||
shadowingRouter.setHotDeploy(false); | ||
shadowingRouter.setExchangeStore(new ForgetfulExchangeStore()); | ||
shadowingRouter.setTransport(new HttpTransport()); | ||
|
||
shadowingRule = new ServiceProxy(new ServiceProxyKey("localhost", "*", ".*", 3000), null, 0); | ||
returnInterceptorMock = Mockito.spy(new ReturnInterceptor()); | ||
returnInterceptorMock.setStatusCode(200); | ||
shadowingRule.setInterceptors(List.of(returnInterceptorMock)); | ||
|
||
shadowingRouter.getRuleManager().addProxyAndOpenPortIfNew(shadowingRule); | ||
shadowingRouter.init(); | ||
shadowingRouter.start(); | ||
} | ||
|
||
@AfterAll | ||
static void shutdown() { | ||
shadowingRouter.stop(); | ||
interceptorRouter.stop(); | ||
} | ||
|
||
/** | ||
* Verifies that the shadow target is called by sending a request through the router | ||
* and ensures that the ReturnInterceptor's handleRequest() is invoked once. | ||
*/ | ||
@Test | ||
void testGetDestFromTarget_WithUrl() { | ||
when(mockTarget.getUrl()).thenReturn("http://example.com"); | ||
String result = ShadowingInterceptor.getDestFromTarget(mockTarget, "/path"); | ||
assertEquals("http://example.com", result); | ||
void testIfShadowTargetIsCalled() throws Exception { | ||
given().when().get("http://localhost:2000").then().statusCode(200); | ||
verify(returnInterceptorMock, times(1)).handleRequest(any(Exchange.class)); | ||
} | ||
|
||
/** | ||
* Verifies that the shadow target is called and the ReturnInterceptor's | ||
* handleRequest() is invoked with an Exchange object not containing the "foo" header. | ||
*/ | ||
@Test | ||
void testGetDestFromTarget_WithoutUrl() { | ||
when(mockTarget.getHost()).thenReturn("localhost"); | ||
when(mockTarget.getPort()).thenReturn(8080); | ||
String result = ShadowingInterceptor.getDestFromTarget(mockTarget, "/path"); | ||
assertEquals("http://localhost:8080/path", result); | ||
void testIfShadowTargetHasFooHeader() throws Exception { | ||
given().when().get("http://localhost:2000").then().statusCode(200); | ||
|
||
ArgumentCaptor<Exchange> exchangeCaptor = ArgumentCaptor.forClass(Exchange.class); | ||
verify(returnInterceptorMock, atLeastOnce()).handleRequest(exchangeCaptor.capture()); | ||
|
||
assertNull(exchangeCaptor.getValue().getRequest().getHeader().getFirstValue("foo")); | ||
} | ||
|
||
} | ||
|
||
@Test | ||
void buildExchangeTest() { | ||
assertNotNull(exc); | ||
assertEquals("POST", exc.getRequest().getMethod()); | ||
assertEquals("/foo", exc.getRequest().getUri()); | ||
assertEquals("https://www.predic8.com:9000/foo", exc.getDestinations().get(0)); | ||
assertEquals(APPLICATION_JSON, exc.getRequest().getHeader().getContentType()); | ||
} | ||
} |