Kamelroutentest mit adviceWith mit OnException-Definitionen

Ich habe eine sehr einfache Camel-Routendefinition, die nur einige OnException-Prädikate zur Behandlung der jeweiligen Ausnahmen und einige Protokollanweisungen enthält.

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

Die Bean selbst ist ebenfalls einfach. Sie überprüft lediglich einen Header-Parameter und löst eine entsprechende Ausnahme aus

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

Da dieses Test-Setup nur ein kleiner Teil eines größeren Projekts ist, mag es albern klingen, es wie hier dargestellt zu machen, aber der Kern besteht darin, das redeliveryDelay zum Testzeitpunkt zu ändern, da eine "erzwungene" IOException nicht 3 Minuten warten muss Um die Einheitentests ein wenig zu beschleunigen, kann die Verzögerung für die erneute Zustellung auf etwa 10 ms reduziert werden.

Um dies zu erreichen, macht meine Testmethode folgendes:

@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();
        ...
    }
}

Hier ersetzt der Test nur das Segment onException der IOException, um zunächst die Verzögerung für die erneute Zustellung von 3 Minuten auf 10 ms zu verringern und fügt am Ende einen Scheinendpunkt hinzu. Wenn ich jedoch versuche, den Komponententest durchzuführen, erhalte ich die folgende Ausnahme:

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.

Die Beispiele in deroffizielle DokumentationSoweit ich sie richtig verstanden habe, sind sie sehr ähnlich. Ich habe auch versucht, die Ausnahmedefinition über ein definiertes ID-Prädikat und die entsprechende Methode nachzuschlagenweaveById() oder über dieweaveByToString() Methode, aber ohne anderes Ergebnis. Ich habe auch versucht, die Ausnahmedefinition über zu entfernenweaveByType(OnExceptionDefinition.class).selectIndex(1).remove(); und fügen Sie den OnException-Teil über hinzuweaveAddFirst().onException(...).async...; aber mit dem gleichen Ergebnis.

Das Anhängen eines verspotteten Fehlerendpunkts ist jedoch über z.weaveByToString("Log[io exception noticed]").after().to("mock:ioError");

Tipps zum Ändern von onException-Blöcken oder des redeliveryDelay für Komponententests sind daher sehr willkommen.

@Edit: Ich habe jetzt auch versucht, die onException-Deklarationen über die Routendefinition zu verschieben (from(...)), wie in der Ausnahmemeldung vorgeschlagen, und dies war auch der bevorzugte Fall bei Camel'sAusnahmebeispiele. Dabei schlagen jedoch alle Tests (auch die funktionierenden) ab a fehlNullPointerException aufcontext.getRouteDefinition("someQueueID").adviceWith(context, new AdviceWithRouteBuilder() {... }); Die Route selbst ist offensichtlich nicht mehr zu finden. Ich bezweifle, dass dies ein IntelliJ-Problem ist, da sich beide Klassen im selben Projekt befinden und daher eine Änderung der Route für die Testklasse sichtbar sein sollte.

Verwendete Kamelversion: 2.13.0, IntelliJ IDEA 13.1.2

@ Edit2: Aus irgendeinem Grundcontext.getRouteDefinitions("someQueueID") Gibt null zurück, wenn die OnException-Elemente außerhalb von definiert sindfrom Block, während die allgemeine Route erhalten werden kann übercontext.getRouteDefinitions().get(0) - Die Ausnahme, dass der OnException-Teil als Element der obersten Ebene hinzugefügt werden muss, bleibt jedoch bestehen.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage