Problem:
During the migration from Camel 2 to 3, my error routing tests broke.
The pattern that I follow is to force an exception and assert that the onException()
block sends to my metrics route with the appropriate tags.
I'm using uri pattern matching to individually test that each tag is emitted...this strongly influences the test pattern
Note: In both examples below the createRouteBuilder()
method is identical
Passing Camel 2 Example
import org.apache.camel.RoutesBuilder
import org.apache.camel.builder.RouteBuilder
import org.apache.camel.test.junit4.CamelTestSupport
import org.junit.Test
import java.util.concurrent.TimeUnit
class Camel2Test : CamelTestSupport() {
val startUri = "direct:start"
val baseMetricsUri = "micrometer:counter:errors"
// Want to use pattern to test each individual tag here
val fullMetricsUri = "$baseMetricsUri?tags=a=1,b=2"
override fun isUseAdviceWith(): Boolean {
return true
}
override fun createRouteBuilder(): RoutesBuilder {
return object : RouteBuilder() {
override fun configure() {
onException(Exception::class.java)
.to(fullMetricsUri)
from(startUri)
.routeId(startUri)
.throwException(Exception())
}
}
}
@Test
fun `metric with tag B is emitted`() {
val exchange = createExchangeWithBody("")
val mockEndpoint = getMockEndpoint("mock:test")
context.getRouteDefinition(startUri)
.adviceWith(context, object : RouteBuilder() {
override fun configure() {
interceptSendToEndpoint("$baseMetricsUri.*b.*2.*") // <-- PATTERN
.skipSendToOriginalEndpoint()
.to(mockEndpoint)
}
})
context.start()
mockEndpoint.expectedMessageCount(1)
template.send(startUri, exchange)
assertMockEndpointsSatisfied(2, TimeUnit.SECONDS)
}
}
Failing Camel 3 Example
import org.apache.camel.RoutesBuilder
import org.apache.camel.builder.AdviceWithRouteBuilder
import org.apache.camel.builder.RouteBuilder
import org.apache.camel.test.junit4.CamelTestSupport
import org.junit.Test
import java.util.concurrent.TimeUnit
class Camel3Test : CamelTestSupport() {
val startUri = "direct:start"
val baseMetricsUri = "micrometer:counter:errors"
// Want to use pattern to test each individual tag here
val fullMetricsUri = "$baseMetricsUri?tags=a=1,b=2"
override fun isUseAdviceWith(): Boolean {
return true
}
override fun createRouteBuilder(): RoutesBuilder {
return object : RouteBuilder() {
override fun configure() {
onException(Exception::class.java)
.to(fullMetricsUri)
from(startUri)
.routeId(startUri)
.throwException(Exception())
}
}
}
@Test
fun `metric with tag B is emitted`() {
val exchange = createExchangeWithBody("")
val mockEndpoint = getMockEndpoint("mock:test")
AdviceWithRouteBuilder.adviceWith(context, startUri) { routeBuilder ->
routeBuilder.interceptSendToEndpoint("$baseMetricsUri.*b.*2.*") // <-- PATTERN
.skipSendToOriginalEndpoint()
.to(mockEndpoint)
}
context.start()
mockEndpoint.expectedMessageCount(1)
template.send(startUri, exchange)
assertMockEndpointsSatisfied(2, TimeUnit.SECONDS)
}
}
The mockEndpoint
isn't receiving the exchange and it is instead still going to the metrics endpoint.
Question:
In Camel 3 how can I intercept a route like I was in Camel 2 using patterns? Manual testing shows that the error routing is behaving as expected in prod, so this seems to be a test configuration issue.
Other details:
- This unit test from the camel repo demonstrates what I'm trying to do, but by manually intercepting the route rather than using
mock:
directly in the route. When I don't need pattern matching then this alternate approach works
override fun isMockEndpointsAndSkip() = myUri // ... in test getMockEndpoint("mock:$myUri").expectedMessageCount(1)