Camel routeBuilder.weaveById在使用作为模板化路径参数的ID时失败

r7knjye2  于 2022-11-07  发布在  Apache
关注(0)|答案(1)|浏览(142)

摘要:

我在尝试测试模板化路由时,从我的junit中得到一个IllegalArgumentException,该模板化路由是根据我在第二个RouteBuilder类中创建的模板构建的。
你可以在CreateTemplate类中看到,我尝试使用第三个模板参数来设置TO文件生成器的.id()字符串。这样做是为了我可以在junit中找到(通过weaveById)并模拟这个生成器。但是,似乎id设置不正确,weaveById失败了。
如果我直接创建路由,我的意思是,不通过模板,这工作得很好,我可以用weaveById()方法模拟生产者。
使用Spring保护套2.7.0、Camel 3.16.0和openjdk-11。
我错过了什么?谢谢你的帮助。
注意:我确实找到了一个变通方法,那就是使用weaveByType()。这在junit中被注解掉了,但是工作正常。但是我仍然想知道为什么weaveById()在这里不工作。

问题详细信息与代码:

junit测试类:

package com.jvh.routes;

import org.apache.camel.CamelContext;
import org.apache.camel.EndpointInject;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.AdviceWith;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
import org.apache.camel.test.spring.junit5.UseAdviceWith;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;

@SpringBootTest
@CamelSpringBootTest
@UseAdviceWith
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class RouteTest {

   @Autowired
   private CamelContext camelContext;

   @Autowired
   private ProducerTemplate producerTemplate;

   @EndpointInject("mock:endpointMock")
   private MockEndpoint mockEndpoint;

   @BeforeEach
   public void setup() throws Exception {

      mockEndpoint.reset();

      AdviceWith.adviceWith(camelContext, "my-test-file-route", routeBuilder -> {
         routeBuilder.replaceFromWith("direct:start");
         routeBuilder.weaveById("my-internal-route-id").replace().to(mockEndpoint);  // fails
         //routeBuilder.weaveByType(ToDefinition.class).replace().to(mockEndpoint);  // works
         routeBuilder.setLogRouteAsXml(false);
      });

      camelContext.start();
   }

   @AfterEach
   public void tearDown() {
      camelContext.stop();
   }

   @Test
   void test_processMessageToRestApi_Ok() throws Exception {

      final String testMsg = "{ test msg }";

      // Expect output file endpoint mock to receive 1 message
      mockEndpoint.expectedMessageCount(1);
      mockEndpoint.expectedBodiesReceived(testMsg);

      // Message body
      producerTemplate.sendBody("direct:start", testMsg);
      mockEndpoint.assertIsSatisfied();
   }
}

模板创建类:

package com.jvh.routes;

import org.apache.camel.LoggingLevel;
import org.apache.camel.Ordered;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class CreateTemplate extends RouteBuilder {

   @Override
   public int getOrder() {
      return Ordered.HIGHEST;  // required to ensure the template is created first
   }

   @Override
   public void configure() {

      routeTemplate("myTemplateId")
      .templateParameter("input-directory-param-id")
      .templateParameter("output-directory-param-id")
      .templateParameter("route-id-param-id")

      .from("file:{{input-directory-param-id}}")
      .log(LoggingLevel.INFO, log, "--> got file ${header.CamelFileName}")
      .to("file:{{output-directory-param-id}}")
      .id("{{route-id-param-id}}")              // set id here to be able to mock this producer
      .log(LoggingLevel.INFO, log, "--> done");
   }
}

模板化路由创建类:

package com.jvh.routes;

import org.apache.camel.CamelContext;
import org.apache.camel.Ordered;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.builder.TemplatedRouteBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CreateRoute extends RouteBuilder {

   @Autowired
   private CamelContext camelContext;

   @Override
   public int getOrder() {
      return Ordered.LOWEST;  // route created after the template
   }

   @Override
   public void configure() throws Exception {

      final String routeId = TemplatedRouteBuilder.builder(camelContext, "myTemplateId")
            .routeId("my-test-file-route")
            .parameter("input-directory-param-id", "input-directory")
            .parameter("output-directory-param-id", "output-directory")
            .parameter("route-id-param-id", "my-internal-route-id")     // parameter to set the producer id
            .add();
      log.info("Route {} created from template", routeId);
   }
}

运行junit测试时抛出的异常:

java.lang.IllegalArgumentException: There are no outputs which matches: my-internal-route-id in the route: Route(my-test-file-route)[From[direct:start] -> [Log[--> got file ${header.CamelFileName}], To[file:{{output-directory-param-id}}], Log[--> done]]]
    at org.apache.camel.builder.AdviceWithTasks$1.task(AdviceWithTasks.java:226)
    at org.apache.camel.builder.AdviceWith.doAdviceWith(AdviceWith.java:222)
    at org.apache.camel.builder.AdviceWith.adviceWith(AdviceWith.java:75)
    at com.jvh.routes.RouteTest.setup(RouteTest.java:38)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    <snip...>

junit运行的一些相关调试日志:

<snip...>
2022-05-23 16:36:58.535 DEBUG 10916 --- [           main] o.a.camel.spring.SpringCamelContext      : onApplicationEvent: org.springframework.test.context.event.AfterTestMethodEvent[source=[DefaultTestContext@50fe837a testClass = RouteTest, testInstance = com.jvh.routes.RouteTest@510da778, testMethod = test_processMessageToRestApi_Ok@RouteTest, testException = java.lang.IllegalArgumentException: There are no outputs which matches: my-internal-route-id in the route: Route(my-test-file-route)[From[direct:start] -> [Log[--> got file ${header.CamelFileName}], To[file:{{output-directory-param-id}}], Log[--> done]]], mergedContextConfiguration = [WebMergedContextConfiguration@3a62c01e testClass = RouteTest, locations = '{}', classes = '{class com.jvh.TestApp}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1187c9e8, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@16aa8654, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@61eaec38, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@31920ade, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@16b2bb0c, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@5ae50ce6], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]]
2022-05-23 16:36:58.535 DEBUG 10916 --- [           main] tractDirtiesContextTestExecutionListener : After test method: context [DefaultTestContext@50fe837a testClass = RouteTest, testInstance = com.jvh.routes.RouteTest@510da778, testMethod = test_processMessageToRestApi_Ok@RouteTest, testException = java.lang.IllegalArgumentException: There are no outputs which matches: my-internal-route-id in the route: Route(my-test-file-route)[From[direct:start] -> [Log[--> got file ${header.CamelFileName}], To[file:{{output-directory-param-id}}], Log[--> done]]], mergedContextConfiguration = [WebMergedContextConfiguration@3a62c01e testClass = RouteTest, locations = '{}', classes = '{class com.jvh.TestApp}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1187c9e8, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@16aa8654, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@61eaec38, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@31920ade, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@16b2bb0c, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@5ae50ce6], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]], class annotated with @DirtiesContext [true] with mode [AFTER_EACH_TEST_METHOD], method annotated with @DirtiesContext [false] with mode [null].
2022-05-23 16:36:58.535 DEBUG 10916 --- [           main] o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework.web.context.support.GenericWebApplicationContext@15515c51, started on Mon May 23 16:36:49 EDT 2022
2022-05-23 16:36:58.535 DEBUG 10916 --- [           main] o.a.camel.spring.SpringCamelContext      : onApplicationEvent: org.springframework.context.event.ContextClosedEvent[source=org.springframework.web.context.support.GenericWebApplicationContext@15515c51, started on Mon May 23 16:36:49 EDT 2022]
2022-05-23 16:36:58.543 DEBUG 10916 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 2147483647
2022-05-23 16:36:58.543 DEBUG 10916 --- [           main] o.a.c.main.SimpleMainShutdownStrategy    : Shutdown called
2022-05-23 16:36:58.545 DEBUG 10916 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2022-05-23 16:36:58.545 DEBUG 10916 --- [           main] o.s.t.c.w.ServletTestExecutionListener   : Resetting RequestContextHolder for test context [DefaultTestContext@50fe837a testClass = RouteTest, testInstance = com.jvh.routes.RouteTest@510da778, testMethod = test_processMessageToRestApi_Ok@RouteTest, testException = java.lang.IllegalArgumentException: There are no outputs which matches: my-internal-route-id in the route: Route(my-test-file-route)[From[direct:start] -> [Log[--> got file ${header.CamelFileName}], To[file:{{output-directory-param-id}}], Log[--> done]]], mergedContextConfiguration = [WebMergedContextConfiguration@3a62c01e testClass = RouteTest, locations = '{}', classes = '{class com.jvh.TestApp}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1187c9e8, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@16aa8654, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@61eaec38, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@31920ade, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@16b2bb0c, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@5ae50ce6], resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.activateListener' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.populatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true, 'org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false, 'org.springframework.test.context.support.DependencyInjectionTestExecutionListener.reinjectDependencies' -> true]].
<snip...>
9gm1akwq

9gm1akwq1#

WeaveByID正在特定路由的上下文中编织节点(即终结点)。
给定路线:

from("direct:start")
        .id("my-route")
        .to("mock:bar").id("bar")

您可以执行:

AdviceWith.adviceWith(camelContext, "my-route", ...
           ...
                weaveById("bar").replace().to("log:demo");

在您的示例中,您正在编织“my-internal-route-id”,这是一个路由,而不是端点

相关问题