I'm building an application using microservices with the netflix stack and spring boot. One thing that bugs me is that I have no integration tests yet, where I can mock the surrounding services.
So, I have service A which is a eureka client with ribbon to resolve the eureka name to the URL of a registered service B during a call.
So ideally I want to start the application with the integrationtest annotations of spring boot, use wiremock to simulate the service B and then call the method of service A, this should call my mocked service B using the symbolic name of the service.
Did anyone already solve this? I have searched for blog entries etc. of people doing this already, but couldn't find any...
I know of the SO article Mock an Eureka Feign Client for Unittesting but as far as I can see this just prevents the discovery client from complaining.
The following code (taken from https://github.com/Netflix/eureka/blob/a7a8d278e6399bbff5faa49b9fcbcd7ea9e854f4/eureka-core/src/test/java/com/netflix/eureka/mock/MockRemoteEurekaServer.java ) may be helpful to you;
public class MockRemoteEurekaServer extends ExternalResource {
public static final String EUREKA_API_BASE_PATH = "/eureka/v2/";
private final Map<String, Application> applicationMap;
private final Map<String, Application> applicationDeltaMap;
private final Server server;
private boolean sentDelta;
private int port;
private volatile boolean simulateNotReady;
public MockRemoteEurekaServer(int port, Map<String, Application> applicationMap,
Map<String, Application> applicationDeltaMap) {
this.applicationMap = applicationMap;
this.applicationDeltaMap = applicationDeltaMap;
ServletHandler handler = new AppsResourceHandler();
EurekaServerConfig serverConfig = new DefaultEurekaServerConfig();
EurekaServerContext serverContext = mock(EurekaServerContext.class);
when(serverContext.getServerConfig()).thenReturn(serverConfig);
handler.addFilterWithMapping(ServerRequestAuthFilter.class, "/*", 1).setFilter(new ServerRequestAuthFilter(serverContext));
handler.addFilterWithMapping(RateLimitingFilter.class, "/*", 1).setFilter(new RateLimitingFilter(serverContext));
server = new Server(port);
server.addHandler(handler);
System.out.println(String.format(
"Created eureka server mock with applications map %s and applications delta map %s",
stringifyAppMap(applicationMap), stringifyAppMap(applicationDeltaMap)));
}
@Override
protected void before() throws Throwable {
start();
}
@Override
protected void after() {
try {
stop();
} catch (Exception e) {
Assert.fail(e.getMessage());
}
}
public void start() throws Exception {
server.start();
port = server.getConnectors()[0].getLocalPort();
}
public void stop() throws Exception {
server.stop();
}
public boolean isSentDelta() {
return sentDelta;
}
public int getPort() {
return port;
}
public void simulateNotReady(boolean simulateNotReady) {
this.simulateNotReady = simulateNotReady;
}
private static String stringifyAppMap(Map<String, Application> applicationMap) {
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, Application> entry : applicationMap.entrySet()) {
String entryAsString = String.format("{ name : %s , instance count: %d }", entry.getKey(),
entry.getValue().getInstances().size());
builder.append(entryAsString);
}
return builder.toString();
}
private class AppsResourceHandler extends ServletHandler {
@Override
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
throws IOException, ServletException {
if (simulateNotReady) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
return;
}
String authName = request.getHeader(AbstractEurekaIdentity.AUTH_NAME_HEADER_KEY);
String authVersion = request.getHeader(AbstractEurekaIdentity.AUTH_VERSION_HEADER_KEY);
String authId = request.getHeader(AbstractEurekaIdentity.AUTH_ID_HEADER_KEY);
Assert.assertNotNull(authName);
Assert.assertNotNull(authVersion);
Assert.assertNotNull(authId);
Assert.assertTrue(!authName.equals(ServerRequestAuthFilter.UNKNOWN));
Assert.assertTrue(!authVersion.equals(ServerRequestAuthFilter.UNKNOWN));
Assert.assertTrue(!authId.equals(ServerRequestAuthFilter.UNKNOWN));
for (FilterHolder filterHolder : this.getFilters()) {
filterHolder.getFilter().doFilter(request, response, new FilterChain() {
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
// do nothing;
}
});
}
String pathInfo = request.getPathInfo();
System.out.println(
"Eureka resource mock, received request on path: " + pathInfo + ". HTTP method: |" + request
.getMethod() + '|');
boolean handled = false;
if (null != pathInfo && pathInfo.startsWith("")) {
pathInfo = pathInfo.substring(EUREKA_API_BASE_PATH.length());
if (pathInfo.startsWith("apps/delta")) {
Applications apps = new Applications();
for (Application application : applicationDeltaMap.values()) {
apps.addApplication(application);
}
apps.setAppsHashCode(apps.getReconcileHashCode());
sendOkResponseWithContent((Request) request, response, toJson(apps));
handled = true;
sentDelta = true;
} else if (pathInfo.startsWith("apps")) {
Applications apps = new Applications();
for (Application application : applicationMap.values()) {
apps.addApplication(application);
}
apps.setAppsHashCode(apps.getReconcileHashCode());
sendOkResponseWithContent((Request) request, response, toJson(apps));
handled = true;
}
}
if (!handled) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"Request path: " + pathInfo + " not supported by eureka resource mock.");
}
}
private void sendOkResponseWithContent(Request request, HttpServletResponse response, String content)
throws IOException {
response.setContentType("application/json; charset=UTF-8");
response.setStatus(HttpServletResponse.SC_OK);
response.getOutputStream().write(content.getBytes("UTF-8"));
response.getOutputStream().flush();
request.setHandled(true);
System.out.println("Eureka resource mock, sent response for request path: " + request.getPathInfo() +
" with content" + content);
}
}
private String toJson(Applications apps) throws IOException {
return new EurekaJsonJacksonCodec().getObjectMapper(Applications.class).writeValueAsString(apps);
}
}
One option would be to use Camel to mock/replace the Eureka endpoints. There should be config telling your app where to look for Eureka, so override that in your test configuration to point to new endpoint.
Then create a Camel route in test/src using either jetty or http to represent this new endpoint, which would return a response that the LoadBalancerClient expects. That response would have the URI under test (ie your application).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.