2014-05-19 14 views
5

Ho una definizione di percorso Camel molto semplice che include solo alcuni predicati di OnException per gestire le rispettive eccezioni e alcune istruzioni di registro.Test di percorso cammello utilizzando i consigliCon definizioni OnException

from("hazelcast:seda:someQueue") 
    .id("someQueueID") 
    .onException(CustomException.class) 
     .handled(true) 
     .log(LoggingLevel.WARN, "custom exception noticed") 
    .end() 
    .onException(IOException.class, FileNotFoundException.class) 
     .asyncDelayedRedelivery() 
     .redeliveryDelay(3*1000*60) // 3 Minutes 
     .maximumRedeliveries(3) 
     .log(LoggingLevel.WARN, "io exception noticed") 
    .end() 
    .onException(Exception.class) 
     .log(LoggingLevel.WARN, "general exception noticed") 
    .end() 

    .log("Starting route") 
    .bean(TestBean.class) 
    .log("Finished route"); 

Il fagiolo in se è troppo semplice, semplicemente controlla un parametro di intestazione e genera un'eccezione appropriata

public class TestBean 
{ 
    @Handler 
    public void checkData(@Headers final Map<String, Object> headers) 
      throws CustomException, IOException, Exception 
    { 
     Integer testVal = (Integer)headers.get("TestValue"); 
     if (0 == testVal) 
      throw new CustomException("CustomException"); 
     else if (1 == testVal) 
      throw new IOException("IOException"); 
     else 
      throw new Exception("Exception"); 
    } 
} 

Come questo test-setup è solo una piccola parte di un progetto più ampio che può sembrare sciocco per farlo come presentato qui, ma l'intento principale è quello di modificare il redeliveryDelay al momento del test in quanto una IOException "forzata" non dovrà attendere 3 minuti e quindi, per accelerare un po 'i test unitari, il ritardo di riconsegna potrebbe essere ridotto a come 10 ms.

Al fine di raggiungere questo mio test-metodo esegue le seguenti operazioni:

@ContextConfiguration(classes = OnExceptionRouteTest.ContextConfig.class, loader = AnnotationConfigContextLoader.class) 
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) 
public class OnExceptionRouteTest extends CamelSpringTestSupport 
{ 
    @Override 
    protected AbstractApplicationContext createApplicationContext() 
    { 
     return new AnnotationConfigApplicationContext(ContextConfig.class) 
    } 

    @Configuration 
    public static class ContextConfig extends CamelConfiguration 
    { 
     @Override 
     protected void setupCamelContext(CamelContext camelContext) throws Exception 
     { 
      super.setupCamelContext(camelContext); 
      camelContext.addComponent("hazelcast", new StubComponent()); 
      // some other unnecessary stuff 
     } 

     @Override 
     public List<RouteBuilder> routes() 
     { 
      final List<RouteBuilder> list = new ArrayList<>(); 
      list.add(new OnExceptionRoute()); 
      return list; 
     } 
    } 

    @Override 
    public boolean isUseAdviceWith() 
    { 
     return true; 
    } 

    @Test 
    public void testIOException() 
    { 
     context.getRouteDefinition("someQueueID") 
       .adviceWith(context, new AdviceWithRouteBuilder() 
       { 
        @Override 
        public void configure() throws Exception 
        { 
         this.weaveByType(OnExceptionDefinition.class) 
          .selectIndex(1) 
          .replace() 
           .onException(IOException.class, FileNotFound.class) 
            .asyncDelayedRedelivery() 
            .redeliveryDelay(10) 
            .maximumRedeliveries(3) 
            .log("modified io exception noticed") 
            .to("mock:ioError") 
           .end(); 
          ... 
          mockEndpoints(); 
        } 
       }); 
     context.start(); 
     MockEndpoint ioErrorEndpoint = getMockEndpoint("mock:ioError"); 
     ... 
     ioErrorEndpoint.setExpectedMessageCount(1); 
     ... 

     Map<String, Object> headers = new HashMap<>(); 
     headers.put("TestValue", new Integer(1)); 
     template.sendBodyAndHeaders("hazelcast:seda:someQueue", new Object(), headers); 

     ... 
     ioErrorEndpoint.assertIsSatisfied(); 
     ... 
    } 
} 

Ecco il test appena sostituisce il segmento onException del IOException per ridurre prima il ritardo di riconsegna da 3 minuti a 10 ms e aggiunge un finto endpoint alla fine. Tuttavia quando si tenta di eseguire il test di unità avrò la seguente eccezione:

java.lang.IllegalArgumentException: The output must be added as top-level on the route. Try moving OnException[[class java.io.IOException, class java.io.FileNotFoundException] -> []] to the top of route. 

Tuttavia, gli esempi nel official documentation, per quanto li ho capito bene, sono molto simili. Ho anche provato a cercare la definizione dell'eccezione tramite un predicato ID definito e il suo metodo corrispondente weaveById() o tramite il metodo weaveByToString() ma senza altri risultati. Ho anche provato a rimuovere la definizione dell'eccezione tramite weaveByType(OnExceptionDefinition.class).selectIndex(1).remove(); e aggiungere la parte OnException tramite weaveAddFirst().onException(...).async...; ma con lo stesso risultato.

L'aggiunta di un punto finale di errore fittizio, tuttavia, è possibile tramite f.e. weaveByToString("Log[io exception noticed]").after().to("mock:ioError");

Quindi qualsiasi suggerimento per la modifica dei blocchi di eccezioni o di redeliveryDelay per i test di unità è più che benvenuto.


@EDIT: Ho provato anche ora di passare alle dichiarazioni onException sopra la definizione della rotta (from(...)) come suggerito dal messaggio di eccezione e questo è stato anche il caso preferito in cammello di exception samples. In tal caso, tuttavia, tutti i test (anche quelli funzionanti) non riescono a partire da su context.getRouteDefinition("someQueueID").adviceWith(context, new AdviceWithRouteBuilder() {... }); poiché ovviamente non è più possibile trovare la rotta stessa. Dubito che questo sia un problema di IntelliJ poiché entrambe le classi si trovano all'interno dello stesso progetto e quindi una modifica del percorso dovrebbe essere visibile alla classe di test.

versione cammello in uso: 2.13.0, IntelliJ IDEA 13.1.2


@ Edit2: Per qualche ragione context.getRouteDefinitions("someQueueID") rendimenti nullo se gli elementi onException sono definiti all'esterno del blocco from, mentre il percorso generale può essere ottenuto tramite context.getRouteDefinitions().get(0) - sebbene l'eccezione indichi che la parte OnException deve essere aggiunta come elemento di livello superiore.

+1

Un'altra opzione è quella di rendere il redeliveryDelay (e forse altre impostazioni) una proprietà, e poi hanno un file di proprietà di produzione + un file delle proprietà di prova, con differenti valori in base alle esigenze di ciascun ambiente. –

+0

@SteveHarrington Anche se il tuo suggerimento con l'inserimento di valori di proprietà in questi campi funziona, questo non risolve il problema principale per il consiglioCon un mio parere, insieme ai blocchi onException. Tuttavia, vorrei accettare il tuo suggerimento come risposta se sei disposto a pubblicare una risposta. –

risposta

4

Quando si utilizza il DSL Java, l'ID del percorso viene impostato utilizzando il metodo .routeId(), non .id() come indicato sopra. Questo può aiutare con i tuoi problemi adviceWith.

Invece di codificare a macchina il ritardo dei tentativi, un approccio migliore sarebbe rendere il ritardo configurabile utilizzando le proprietà. Controlla la documentazione relativa al metodo useOverridePropertiesWithPropertiesComponent() sulla tua classe CamelSpringTestSupport.

EDIT

Non è necessario a tessere la clausola onException, è sufficiente indicare uno nuovo. Ecco un esempio completo:

import org.apache.camel.builder.AdviceWithRouteBuilder; 
import org.apache.camel.builder.RouteBuilder; 
import org.apache.camel.test.junit4.CamelTestSupport; 

public class DummyTest extends CamelTestSupport{ 
    @Override 
    protected RouteBuilder createRouteBuilder() throws Exception { 
     return new RouteBuilder(){ 
      @Override 
      public void configure() throws Exception { 

       from("direct://start") 
        .routeId("myroute") 
        .onException(Exception.class) 
         .id("myException") 
         .continued(true) 
        .end() 
        .throwException(new Exception()) 
        .to("mock:end"); 
      } 
     }; 
    } 

    @org.junit.Test 
    public void doTest() throws Exception{ 
     context.getRouteDefinition("myroute").adviceWith(context, new AdviceWithRouteBuilder(){ 
      @Override 
      public void configure() throws Exception { 
       context.getRouteDefinition("myroute") 
        .onException(Exception.class).setBody(constant("adviceWith")).continued(true); 
      }}); 
     context.start(); 
     template.sendBody("direct://start", "original"); 
     String bodyAtEndOfExchange = getMockEndpoint("mock:end") 
       .getExchanges().get(0).getIn().getBody(String.class); 
     assertEquals("adviceWith", bodyAtEndOfExchange);   
     context.stop(); 
    } 

    @Override 
    public boolean isUseAdviceWith() { 
     return true; 
    } 
} 
+0

Ho già capito il problema di '.id (...)' e '.routeId (...)', ma grazie per averlo indicato qui, dato che non ho aggiornato il post da allora. Ho anche configurato il ritardo tramite le proprietà come già suggerito da @SteveHarrington. Mentre questo risolve il problema del delirio specifico del test, rimane comunque l'argomento attuale: come consigliare un blocco onException correttamente? Ovviamente, 'inOnly' e' to' possono essere catturati usando gli interceptor, ma cosa succede se vogliamo aggiungere qualcosa nel mezzo della strada e non usare id. Non sono sicuro che Camel 2.15+ ora abbia un supporto migliore, devi provarlo di nuovo –

Problemi correlati