Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miscellaneous test framework tidy ups #6223

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ public void checkTests() {
Assertions.assertEquals(0L, ts.getTestsSkipped());

Assertions.assertTrue(TEST.getLogRecords().stream()
.anyMatch(logRecord -> logRecord.getMessage().contains("`RouteBuilder` detected")));
.anyMatch(logRecord -> logRecord.getMessage().contains("RouteBuilder beans are present")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ public void checkTests() {
Assertions.assertEquals(0L, ts.getTestsSkipped());

Assertions.assertFalse(TEST.getLogRecords().stream()
.anyMatch(logRecord -> logRecord.getMessage().contains("`RouteBuilder` detected")));
.anyMatch(logRecord -> logRecord.getMessage().contains("RouteBuilder beans are present")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
import org.junit.platform.engine.support.store.NamespacedHierarchicalStore;

public class CallbackUtil {
private CallbackUtil() {
// Utility class
}

static boolean isPerClass(CamelQuarkusTestSupport testSupport) {
return getLifecycle(testSupport).filter(lc -> lc.equals(TestInstance.Lifecycle.PER_CLASS)).isPresent();
Expand All @@ -47,13 +50,13 @@ static Optional<TestInstance.Lifecycle> getLifecycle(CamelQuarkusTestSupport tes
}

static void resetContext(CamelQuarkusTestSupport testInstance) {

//if routeBuilder (from the test) was used, all routes from that builder has to be stopped and removed
//because routes will be created again (in case of TestInstance.Lifecycle.PER_CLASS, this method is not executed)
if (testInstance.isUseRouteBuilder() && testInstance.createdRoutes != null) {
Set<String> createdRoutes = testInstance.getCreatedRoutes();
if (testInstance.isUseRouteBuilder() && createdRoutes != null) {

try {
for (String r : testInstance.createdRoutes) {
for (String r : createdRoutes) {
testInstance.context().getRouteController().stopRoute(r);
testInstance.context().removeRoute(r);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@

/**
* The {@link CamelTestSupport} class does not work on Quarkus. This class provides a replacement, which can be used in
* JVM mode. There are several differences between {@link CamelTestSupport} and this class.
* JVM mode. Note that {@link CamelQuarkusTestSupport} <b>DOES NOT</b> work for native mode tests.
* <p>
* There are several differences between {@link CamelTestSupport} and this class.
* </p>
* <ul>
* <li>Starting and stopping {@link CamelContext} in Camel Quarkus is generally bound to starting and stopping the
* application
Expand Down Expand Up @@ -80,40 +83,41 @@ public class CamelQuarkusTestSupport extends CamelTestSupport

@Inject
protected CamelContext context;

/*
* Set of routes, which were created by routeBuilder. This set is used by some callbacks.
*/
Set<String> createdRoutes;
private Set<String> createdRoutes;

//------------------------ quarkus callbacks ---------------

/**
* Replacement of {@link #afterAll(ExtensionContext)} called from {@link AfterAllCallback#afterAll(QuarkusTestContext)}
*/
protected void doAfterAll(QuarkusTestContext context) throws Exception {
// Noop
}

/**
* Replacement of {@link #afterEach(ExtensionContext)} called from
* {@link AfterEachCallback#afterEach(QuarkusTestMethodContext)}
*/
protected void doAfterEach(QuarkusTestMethodContext context) throws Exception {
// Noop
}

/**
* Replacement of {@link #beforeAll(ExtensionContext)} called from {@link AfterConstructCallback#afterConstruct(Object)}
* Execution differs in case of <i>@TestInstance(TestInstance.Lifecycle.PER_METHOD)</i> in which case callback is called
* Execution differs in case of <i>@TestInstance(TestInstance.Lifecycle.PER_METHOD)</i>. in which case a callback is
* invoked
* before each test (instead of {@link #beforeAll(ExtensionContext)}).
*/
protected void doAfterConstruct() throws Exception {
// Noop
}

/**
* Replacement of {@link #beforeEach(ExtensionContext)} called from
* {@link BeforeEachCallback#beforeEach(QuarkusTestMethodContext)}
*/
protected void doBeforeEach(QuarkusTestMethodContext context) throws Exception {
// Noop
}

/**
Expand All @@ -134,8 +138,7 @@ protected CamelContext createCamelContext() throws Exception {
*/
@Override
protected void bindToRegistry(Registry registry) throws Exception {
//CamelTestSupport has to use the same context as CamelQuarkusTestSupport
Assertions.assertEquals(context, super.context, "Different context found!");
assertTestClassCamelContextMatchesAppCamelContext();
super.bindToRegistry(registry);
}

Expand All @@ -144,8 +147,7 @@ protected void bindToRegistry(Registry registry) throws Exception {
*/
@Override
protected void postProcessTest() throws Exception {
//CamelTestSupport has to use the same context as CamelQuarkusTestSupport
Assertions.assertEquals(context, super.context, "Different context found!");
assertTestClassCamelContextMatchesAppCamelContext();
super.postProcessTest();
}

Expand All @@ -154,8 +156,7 @@ protected void postProcessTest() throws Exception {
*/
@Override
public CamelContext context() {
//CamelTestSupport has to use the same context as CamelQuarkusTestSupport
Assertions.assertEquals(context, super.context, "Different context found!");
assertTestClassCamelContextMatchesAppCamelContext();
return super.context();
}

Expand All @@ -174,11 +175,14 @@ public CamelContext context() {
* }
* </pre>
*
* @return Never returns any result. UnsupportedOperationException is thrown instead.
* Or you can produce named CDI beans, and they will be resolvable from the Camel registry.
*
* @throws UnsupportedOperationException since on Camel Quarkus the Camel registry is a facade on top of the Quarkus
* CDI bean container.
*/
@Override
protected final Registry createCamelRegistry() {
throw new UnsupportedOperationException("won't be executed.");
throw new UnsupportedOperationException("Creating a registry is not supported for Camel Quarkus tests");
}

/**
Expand All @@ -188,7 +192,7 @@ protected final Registry createCamelRegistry() {
*/
@Override
public final void beforeAll(ExtensionContext context) {
//replaced by quarkus callback (beforeEach)
// In Camel Quarkus, junit5 uses a different classloader. The original CamelTestSupport logic is in org.apache.camel.quarkus.test.BeforeEachCallback
}

/**
Expand All @@ -197,7 +201,7 @@ public final void beforeAll(ExtensionContext context) {
*/
@Override
public final void beforeEach(ExtensionContext context) throws Exception {
//replaced by quarkus callback (beforeEach)
// In Camel Quarkus, junit5 uses a different classloader. The original CamelTestSupport logic is in org.apache.camel.quarkus.test.BeforeEachCallback
}

/**
Expand All @@ -207,7 +211,7 @@ public final void beforeEach(ExtensionContext context) throws Exception {
*/
@Override
public final void afterAll(ExtensionContext context) {
//in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback
// In Camel Quarkus, junit5 uses a different classloader. The original CamelTestSupport logic is in org.apache.camel.quarkus.test.AfterAllCallback
}

/**
Expand All @@ -217,7 +221,7 @@ public final void afterAll(ExtensionContext context) {
*/
@Override
public final void afterEach(ExtensionContext context) throws Exception {
//in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback
// In Camel Quarkus, junit5 uses a different classloader. The original CamelTestSupport logic is in org.apache.camel.quarkus.test.AfterEachCallback
}

/**
Expand All @@ -227,7 +231,7 @@ public final void afterEach(ExtensionContext context) throws Exception {
*/
@Override
public final void afterTestExecution(ExtensionContext context) throws Exception {
//in camel-quarkus, junit5 uses different classloader, necessary code was moved into quarkus's callback
// In Camel Quarkus, junit5 uses a different classloader. The original CamelTestSupport logic is in org.apache.camel.quarkus.test.AfterAllCallback
}

/**
Expand All @@ -252,14 +256,12 @@ public void tearDown() throws Exception {
}

/**
* This method stops the Camel context. Be aware that on of the limitation that Quarkus brings is that context
* can not be started (lifecycle f the context is bound to the application) .
*
* @throws Exception
* The CamelContext lifecycle is managed by Quarkus and FastCamelContext cannot be restarted after stop.
* Therefore, this is a noop operation.
*/
@Override
protected void stopCamelContext() throws Exception {
//context is started and stopped via quarkus lifecycle
protected void stopCamelContext() {
// Noop
}

/**
Expand All @@ -268,16 +270,16 @@ protected void stopCamelContext() throws Exception {
*/
@Override
protected final void doQuarkusCheck() {
//can run on Quarkus

//log warning in case that at least one RouteBuilder in the registry, it might mean, that unintentionally
// RouteBuilders are shared across or that RouteBuilder is created with @Produces
// Log a warning in case that at least one RouteBuilder is present in the Camel registry.
// It might mean, that unintentionally routes are shared across tests, or that a RouteBuilder is
// created with @Produces
if (isUseRouteBuilder() && !context.getRegistry().findByType(RouteBuilder.class).isEmpty()) {
LOG.warn(
"Test with `true` in `isUserRouteBuilder' and `RouteBuilder` detected in the context registry. " +
"All tests will share this routeBuilder from the registry. This is usually not intended. " +
"If `@Produces` is used to create such a RouteBuilder, please refactor the code " +
"by overriding the method `createRouteBuilder()` instead.");
LOG.warn("isUseRouteBuilder = true and RouteBuilder beans are present in the Camel registry.\n" +
"All tests will share their routes. If this is not desired, define your test routes " +
"by overriding CamelQuarkusTestSupport.createRouteBuilder().\nOr use configuration properties " +
"quarkus.camel.routes-discovery.exclude-patterns or quarkus.camel.routes-discovery.include-patterns " +
"to control which routes are started.");
}
}

Expand All @@ -304,10 +306,10 @@ void internalBeforeEach(ExtensionContext context) throws Exception {
}

/**
* Strategy to perform any pre setup, before {@link CamelContext} is created
* Strategy to perform any pre setup, before the {@link CamelContext} is created.
* <p>
* Be aware that difference in lifecycle with Quarkus may require a special behavior.
* If this method is overridden, <i>super.doPreSetup()</i> has to be called.
* Be aware that difference in lifecycle with Quarkus may require special behavior.
* If this method is overridden, <i>super.doPreSetup()</i> must be called.
* </p>
*/
@Override
Expand All @@ -317,18 +319,21 @@ protected void doPreSetup() throws Exception {
}

if (isUseRouteBuilder()) {
//save the routeIds of routes existing before setup
createdRoutes = context.getRoutes().stream().map(r -> r.getRouteId()).collect(Collectors.toSet());
// Save the routeIds of routes existing before setup
createdRoutes = context.getRoutes()
.stream()
.map(Route::getRouteId)
.collect(Collectors.toSet());
}

super.doPreSetup();
}

/**
* Strategy to perform any post setup after {@link CamelContext} is created
* Strategy to perform any post setup after the {@link CamelContext} is created.
* <p>
* Be aware that difference in lifecycle with Quarkus may require a special behavior.
* If this method is overridden, <i>super.doPostSetup()</i> has to be called.
* Be aware that difference in lifecycle with Quarkus may require special behavior.
* If this method is overridden, <i>super.doPostSetup()</i> must be called.
* </p>
*/
@Override
Expand All @@ -338,15 +343,18 @@ protected void doPostSetup() throws Exception {
if (isUseDebugger()) {
ModelCamelContext mcc = (ModelCamelContext) context;
List<RouteDefinition> rdfs = mcc.getRouteDefinitions();
//if context was suspended routes was not added, because it would trigger start of the context
// routes have to be added now
// If the context was suspended, routes were not added because it would trigger start of the context
// therefore, add the routes here
mcc.addRouteDefinitions(rdfs);
}
}

if (isUseRouteBuilder()) {
//remove from the routes all routes which existed before setup
var allRoutes = context.getRoutes().stream().map(r -> r.getRouteId()).collect(Collectors.toSet());
// Remove from the routes all routes which existed before setup
Set<String> allRoutes = context.getRoutes()
.stream()
.map(Route::getRouteId)
.collect(Collectors.toSet());
if (createdRoutes != null) {
allRoutes.removeAll(createdRoutes);
}
Expand All @@ -356,29 +364,30 @@ protected void doPostSetup() throws Exception {
}

/**
* Internal disablement of the context stop functionality.
* The CamelContext lifecycle is managed by Quarkus and FastCamelContext cannot be restarted after stop.
* Therefore, this is a noop operation.
*/
@Override
protected final void doStopCamelContext(CamelContext context, Service camelContextService) {
//don't stop
// noop
}

/**
* This method does nothing. The context starts together with Quarkus engine.
* The CamelContext lifecycle is managed by Quarkus and FastCamelContext is started automatically.
* Therefore, this is a noop operation.
*/
@Override
protected final void startCamelContext() {
//context has already started
// noop
}

/**
* Override when using <a href="http://camel.apache.org/advicewith.html">advice with</a> and return <tt>true</tt>.
* This helps knowing advice with is to be used.
* Override when using <a href="http://camel.apache.org/advicewith.html">advice with</a> and return <code>true</code>.
* <p/>
* <b>Important:</b> Its important to execute method {@link #startRouteDefinitions()}} manually from the unit test
* <b>Important:</b> You must execute method {@link #startRouteDefinitions()}} manually from the unit test
* after you are done doing all the advice with.
*
* @return <tt>true</tt> if you use advice with in your unit tests.
* @return <code>true</code> to apply advice to existing route(s). <code>false</code> to disable advice.
*/
@Override
public boolean isUseAdviceWith() {
Expand All @@ -398,4 +407,13 @@ protected void startRouteDefinitions() throws Exception {
modelCamelContext.startRouteDefinitions(definitions);
}

Set<String> getCreatedRoutes() {
return createdRoutes;
}

private void assertTestClassCamelContextMatchesAppCamelContext() {
// Test classes must use the same CamelContext as the application under test
Assertions.assertEquals(context, super.context,
"CamelQuarkusTestSupport uses a different CamelContext compared to the application under test");
}
}
Loading