2014-05-19 66 views
5

我有一個非常簡單的Camel路由定義,它只包含一些用於處理相應異常和一些日誌語句的OnException謂詞。使用adviceWith進行駱駝路由測試以及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"); 

bean本身也很簡單,它只是檢查頭參數,作爲這個測試的設置是一個大項目的一小部分,可能聽起來很傻拋出一個適當的異常

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

像這裏介紹的那樣做,但核心意圖是在測試時間修改redeliveryDelay,因爲「強制」IOException不需要等待3分鐘,因此爲了加快單元測試的速度,重新傳遞延遲可以降低到像10毫秒。

爲了實現這個我的測試方法執行以下操作:

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

這裏的測試只是取代了IOException異常的onException的段首先從3分鐘降低了重新傳遞延遲到10毫秒,並增加了模擬終點。然而,當我嘗試運行單元測試,我會出現以下情況例外:

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. 

然而,在official documentation的例子,據我理解正確的他們,都非常相似。我還嘗試通過已定義的ID謂詞及其相應的方法weaveById()或通過weaveByToString()方法查找異常定義,但沒有其他結果。我還嘗試通過weaveByType(OnExceptionDefinition.class).selectIndex(1).remove();刪除異常定義,並通過weaveAddFirst().onException(...).async...;添加OnException部分,但結果相同。

但是,可以通過f.e添加模擬錯誤端點。 weaveByToString("Log[io exception noticed]").after().to("mock:ioError");

因此,修改onException塊或單元測試的redeliveryDelay的任何提示都值得歡迎。


@Edit:我現在也試圖移動通過異常消息建議同時這也是在駱駝的exception samples優選情況下,路由定義(from(...))上面的onException的聲明。然而,在這樣做的時候,所有的測試(甚至是工作測試)在context.getRouteDefinition("someQueueID").adviceWith(context, new AdviceWithRouteBuilder() {... });上的NullPointerException都失敗了,因爲顯然這條路線本身已經找不到了。我懷疑這是一個IntelliJ問題,因爲這兩個類都在同一個項目中,因此路由的修改應該對測試類可見。

駱駝版本在使用中:2.13.0,IntelliJ IDEA的13.1.2


@ EDIT2:由於某些原因context.getRouteDefinitions("someQueueID")返回NULL,如果onException的元件在from塊之外定義,而一般路線可以通過context.getRouteDefinitions().get(0)獲得 - 但是,該異常聲明OnException部分需要添加爲頂層元素。

+1

另一種選擇是使redeliveryDelay(也許還有其他各種設置)的屬性,然後有一個生產性文件+測試屬性文件,具有不同的值,以滿足您的每一個需求環境。 –

+0

@SteveHarrington雖然與注射的屬性值進入這些領域你的建議的工作,這並沒有解決與在我看來onException的塊一起爲adviceWith的核心問題。不過,如果您願意發佈答案,我願意接受您的建議作爲答案。 –

回答

4

使用Java DSL時,使用.routeId()方法設置路由的ID,而不是像以上編碼的.id()。這可能會有助於您的問題adviceWith

而不是硬編碼的重試延遲,更好的方法是使延時配置使用屬性。查看您的CamelSpringTestSupport課程中方法useOverridePropertiesWithPropertiesComponent()的文檔。

編輯

您不必織onException條款,只是陳述一個新的。這裏有一個完整的例子:

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

我已經想通了,關於這個問題'.ID(...)'和'.routeId(...)'但是謝謝你指出來這裏,因爲我沒有,因爲再更新帖子。我還通過@SteveHarrington建議的屬性配置了延遲。雖然這解決了特定於測試的刪除問題,但實際的主題仍然存在 - 如何正確地建議onException塊?當然,可以使用攔截器捕捉inOnly和to,但如果我們想在道路中間添加某些東西而不使用id,該怎麼辦。不確定駱駝2.15+現在是否有更好的支持,必須再試一次 –