14

Sto costruendo un'applicazione utilizzando i microservizi con lo stack netflix e l'avvio a molla. Una cosa che mi infastidisce è che non ho ancora test di integrazione, in cui posso prendere in giro i servizi circostanti.Servizio di test che utilizza eureka e ribbon

Quindi, ho il servizio A che è un client eureka con nastro per risolvere il nome eureka per l'URL di un servizio registrato B durante una chiamata.

Quindi, idealmente, voglio avviare l'applicazione con le annotazioni integrationtest di spring boot, utilizzare wiremock per simulare il servizio B e quindi chiamare il metodo di servizio A, questo dovrebbe chiamare il mio servizio beffeggiato B usando il nome simbolico del servizio .

Qualcuno lo ha già risolto? Ho cercato i post di blog ecc. Di persone che stanno già facendo questo, ma non ho trovato ...

Conosco l'articolo SO Mock an Eureka Feign Client for Unittesting ma, per quanto posso vedere, questo impedisce solo al client di scoperta di lamentarsi.

+0

Questo post discute alcuni approcci differenti: https://opencredo.com/working-locally-with-microservices/ – MarkOfHall

+0

Sembra che l'articolo parla solo le nozioni di base ed è scritto in un livello elevato. Gli approcci sono abbastanza ovvi, sono più interessato se qualcuno ha trovato un modo carino per farlo davvero. L'approccio ninja code monkey menzionato è un modo, ma questo richiede ancora di decodificare e mantenere la "falsa eureka" ... –

risposta

5

Il seguente codice (tratto da https://github.com/Netflix/eureka/blob/a7a8d278e6399bbff5faa49b9fcbcd7ea9e854f4/eureka-core/src/test/java/com/netflix/eureka/mock/MockRemoteEurekaServer.java) può essere utile;

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); 
} 

} 
+1

In futuro, non copiare il contenuto da altrove senza una chiara attribuzione. È visto come un plagio. Vedi http://stackoverflow.com/help/referencing – Matt

5

Un'opzione potrebbe essere utilizzare Camel per simulare/sostituire gli endpoint Eureka. Ci dovrebbe essere config che dice alla tua app dove cercare Eureka, quindi scavalca quello nella tua configurazione di test per puntare a un nuovo endpoint.

Quindi creare un percorso Camel in test/src utilizzando il jetty o http per rappresentare questo nuovo endpoint, che restituirebbe una risposta prevista dal LoadBalancerClient. Quella risposta avrebbe l'URI sotto test (vale a dire la tua applicazione).