This is an automated email from the ASF dual-hosted git repository.
nfilotto pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karaf.git
The following commit(s) were added to refs/heads/main by this push:
new 12d17faa5 Integration Test Framework: Improve failure management (#529)
12d17faa5 is described below
commit 12d17faa5ff4ca01e67b65a1bfc764be203725c1
Author: Nicolas Filotto <[email protected]>
AuthorDate: Thu Oct 17 12:46:37 2024 +0200
Integration Test Framework: Improve failure management (#529)
Ref #526: Integration Test Framework: Allow to set a timeout
Ref #527: Integration Test Framework: Avoid retry by default
Ref #528: Integration Test Framework: Dump log file on failure
## Modifications:
* Added an element named `timeout` to be able to set the timeout of the
integration test knowing that the default value is 5 minutes instead of the
legacy value which was 1 hour
* Added an element named `retryOnFailure` to enable the auto-retry
mechanism like before, knowing that the default value is now `false`. It should
only be enabled for known flaky tests.
* Added a system property `camel.karaf.itest.dump.logs` to indicate whether
the Karaf log file should be dumped on failure. By default, it is disabled
locally and can be enabled by overriding the Maven property
`dump.logs.on.failure`.
---
.github/workflows/main.yml | 2 +-
.../camel/itests/AbstractCamelRouteITest.java | 124 ++++++++++++++++---
.../karaf/camel/itests/CamelKarafTestHint.java | 15 +++
.../apache/karaf/camel/itests/DumpFileOnError.java | 55 +++++++++
.../itests/TestContainerFactoryFailureAware.java | 132 +++++++++++++++++++++
.../java/org/apache/karaf/camel/itests/Utils.java | 24 ++++
tests/features/pom.xml | 2 +
7 files changed, 335 insertions(+), 19 deletions(-)
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index b924127f1..f6da17ca9 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -38,4 +38,4 @@ jobs:
with:
java-version: 17
distribution: zulu
- - run: ./mvnw -V --no-transfer-progress clean install
+ - run: ./mvnw -V --no-transfer-progress clean install
-Ddump.logs.on.failure=true
diff --git
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/AbstractCamelRouteITest.java
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/AbstractCamelRouteITest.java
index 72a6c69c3..bd3cd8380 100644
---
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/AbstractCamelRouteITest.java
+++
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/AbstractCamelRouteITest.java
@@ -20,7 +20,9 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
@@ -31,9 +33,12 @@ import org.jetbrains.annotations.NotNull;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.ExamFactory;
import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.container.remote.RBCRemoteTargetOptions;
import
org.ops4j.pax.exam.karaf.options.KarafDistributionConfigurationFilePutOption;
import org.ops4j.pax.exam.karaf.options.KarafDistributionOption;
import org.osgi.framework.Bundle;
@@ -44,8 +49,10 @@ import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.karaf.camel.itests.CamelKarafTestHint.DEFAULT_TIMEOUT;
import static org.ops4j.pax.exam.OptionUtils.combine;
+@ExamFactory(TestContainerFactoryFailureAware.class)
public abstract class AbstractCamelRouteITest extends KarafTestSupport
implements CamelContextProvider {
public static final int CAMEL_KARAF_INTEGRATION_TEST_DEBUG_DEFAULT_PORT =
8889;
@@ -56,12 +63,22 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
static final String
CAMEL_KARAF_INTEGRATION_TEST_CONTEXT_FINDER_RETRY_INTERVAL_PROPERTY =
"camel.karaf.itest.context.finder.retry.interval";
static final String CAMEL_KARAF_INTEGRATION_TEST_ROUTE_SUPPLIERS_PROPERTY
= "camel.karaf.itest.route.suppliers";
static final String
CAMEL_KARAF_INTEGRATION_TEST_IGNORE_ROUTE_SUPPLIERS_PROPERTY =
"camel.karaf.itest.ignore.route.suppliers";
+ static final String CAMEL_KARAF_INTEGRATION_TEST_DUMP_LOGS_PROPERTY =
"camel.karaf.itest.dump.logs";
private static final Logger LOG =
LoggerFactory.getLogger(AbstractCamelRouteITest.class);
private final Map<CamelContextKey, CamelContext> contexts = new
ConcurrentHashMap<>();
private final Map<CamelContextKey, ProducerTemplate> templates = new
ConcurrentHashMap<>();
+ @Rule
+ public final DumpFileOnError dumpFileOnError;
private List<String> requiredBundles;
+ protected AbstractCamelRouteITest() {
+ this.retry = new Retry(retryOnFailure());
+ this.dumpFileOnError = new DumpFileOnError(
+ getKarafLogFile(), System.err,
Boolean.getBoolean(CAMEL_KARAF_INTEGRATION_TEST_DUMP_LOGS_PROPERTY)
+ );
+ }
+
public String getCamelKarafVersion() {
String version = System.getProperty("camel.karaf.version");
if (version == null) {
@@ -105,6 +122,9 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
"getCamelKarafVersion must be overridden to provide the
version of Camel Karaf to use");
}
Option[] options = new Option[]{
+ CoreOptions.systemTimeout(timeoutInMillis()),
+ RBCRemoteTargetOptions.waitForRBCFor((int) timeoutInMillis()),
+
CoreOptions.systemProperty(CAMEL_KARAF_INTEGRATION_TEST_DUMP_LOGS_PROPERTY).value(System.getProperty(CAMEL_KARAF_INTEGRATION_TEST_DUMP_LOGS_PROPERTY,
"false")),
CoreOptions.systemProperty("project.target").value(getBaseDir()),
KarafDistributionOption.features("mvn:org.apache.camel.karaf/apache-camel/%s/xml/features".formatted(camelKarafVersion),
"scr", getMode().getFeatureName()),
CoreOptions.mavenBundle().groupId("org.apache.camel.karaf").artifactId("camel-integration-test").version(camelKarafVersion)
@@ -124,6 +144,13 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
return combine(combine, getAdditionalOptions());
}
+ /**
+ * @return the location of the Karaf log file.
+ */
+ private static @NotNull File getKarafLogFile() {
+ return new File(System.getProperty("karaf.log"), "karaf.log");
+ }
+
/**
* Indicates whether the debug mode is enabled or not. The debug mode is
enabled when the system property
* {@link #CAMEL_KARAF_INTEGRATION_TEST_DEBUG_PROPERTY} is set.
@@ -159,7 +186,7 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
* Returns the interval in seconds between each retry when trying to find
a Camel context, corresponding to the value of the
* system property {@link
#CAMEL_KARAF_INTEGRATION_TEST_CONTEXT_FINDER_RETRY_INTERVAL_PROPERTY}. The
default value is
* {@link
#CAMEL_KARAF_INTEGRATION_TEST_CONTEXT_FINDER_RETRY_INTERVAL_DEFAULT}.
- * @return
+ * @return the interval in seconds between each retry when trying to find
a Camel context
*/
private static int getContextFinderRetryInterval() {
return Integer.getInteger(
@@ -197,6 +224,9 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
return options;
}
+ /**
+ * @return the options provided by the external resources.
+ */
@NotNull
private static Option[] getExternalResourceOptions() {
return
PaxExamWithExternalResource.systemProperties().entrySet().stream()
@@ -204,33 +234,85 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
.toArray(Option[]::new);
}
+ /**
+ * Returns the timeout in milliseconds for the test, corresponding to the
value of the
+ * {@link CamelKarafTestHint#timeout()} annotation multiplied by one
thousand.
+ * @return the timeout in milliseconds for the test
+ */
+ private long timeoutInMillis() {
+ return
TimeUnit.SECONDS.toMillis(getCamelKarafTestHint().map(CamelKarafTestHint::timeout).orElse(DEFAULT_TIMEOUT));
+ }
+
+ /**
+ * Indicates whether the test should be retried on failure. By default, no
retry is performed.
+ * @return {@code true} if the test should be retried on failure, {@code
false} otherwise
+ */
+ private boolean retryOnFailure() {
+ return
getCamelKarafTestHint().filter(CamelKarafTestHint::retryOnFailure).isPresent();
+ }
+
+ /**
+ * Indicates whether the test requires external resources or not. By
default, no external resources are required.
+ * @return {@code true} if the test requires external resources, {@code
false} otherwise
+ */
private boolean hasExternalResources() {
- CamelKarafTestHint hint =
getClass().getAnnotation(CamelKarafTestHint.class);
- return hint != null && hint.externalResourceProvider() != Object.class;
+ return getCamelKarafTestHint().filter(hint ->
hint.externalResourceProvider() != Object.class).isPresent();
}
+ /**
+ * @return the {@link CamelKarafTestHint} annotation of the test class
+ */
+ private Optional<CamelKarafTestHint> getCamelKarafTestHint() {
+ return getCamelKarafTestHint(getClass());
+ }
+ /**
+ * @return the {@link CamelKarafTestHint} annotation of the given test
class
+ */
+ private static Optional<CamelKarafTestHint> getCamelKarafTestHint(Class<?>
clazz) {
+ return
Optional.ofNullable(clazz.getAnnotation(CamelKarafTestHint.class));
+ }
+
+ /**
+ * @return the option to enable only the Camel route suppliers provided in
the {@link CamelKarafTestHint} annotation.
+ */
private Option getCamelRouteSupplierFilter() {
return
CoreOptions.systemProperty(CAMEL_KARAF_INTEGRATION_TEST_ROUTE_SUPPLIERS_PROPERTY)
- .value(String.join(",",
getClass().getAnnotation(CamelKarafTestHint.class).camelRouteSuppliers()));
+ .value(String.join(",",
getCamelKarafTestHint().orElseThrow().camelRouteSuppliers()));
}
+ /**
+ * Indicates whether specific Camel route suppliers have been provided in
the {@link CamelKarafTestHint} annotation.
+ * @return {@code true} if specific Camel route suppliers have been
provided, {@code false} otherwise
+ */
private boolean hasCamelRouteSupplierFilter() {
- CamelKarafTestHint hint =
getClass().getAnnotation(CamelKarafTestHint.class);
- return hint != null && hint.camelRouteSuppliers().length > 0;
+ return getCamelKarafTestHint().filter(hint ->
hint.camelRouteSuppliers().length > 0).isPresent();
}
+ /**
+ * Indicates whether all Camel route suppliers should be ignored or not.
By default, all Camel route suppliers are used.
+ * @return {@code true} if all Camel route suppliers should be ignored,
{@code false} otherwise
+ */
private boolean ignoreCamelRouteSuppliers() {
- CamelKarafTestHint hint =
getClass().getAnnotation(CamelKarafTestHint.class);
- return hint != null && hint.ignoreRouteSuppliers();
+ return
getCamelKarafTestHint().filter(CamelKarafTestHint::ignoreRouteSuppliers).isPresent();
}
+ /**
+ * Indicates whether additional required features have been provided in
the {@link CamelKarafTestHint} annotation.
+ * @return {@code true} if additional required features have been
provided, {@code false} otherwise
+ */
+ private boolean hasAdditionalRequiredFeatures() {
+ return getCamelKarafTestHint().filter(hint ->
hint.additionalRequiredFeatures().length > 0).isPresent();
+ }
+
+ /**
+ * @return the option to ignore all Camel route suppliers.
+ */
private Option getIgnoreCamelRouteSupplier() {
return
CoreOptions.systemProperty(CAMEL_KARAF_INTEGRATION_TEST_IGNORE_ROUTE_SUPPLIERS_PROPERTY)
.value(Boolean.toString(Boolean.TRUE));
}
-
/**
* Returns the list of additional options to add to the configuration.
*/
@@ -252,6 +334,10 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
return List.of();
}
+ /**
+ * Install all the required features repositories.
+ * @throws Exception if an error occurs while installing a features
repository
+ */
private void installRequiredFeaturesRepositories() throws Exception {
for (String featuresRepository : getRequiredFeaturesRepositories()) {
addFeaturesRepository(featuresRepository);
@@ -268,15 +354,18 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
* the {@link CamelKarafTestHint#additionalRequiredFeatures()}.
*/
private List<String> getAllRequiredFeatures() {
- CamelKarafTestHint hint =
getClass().getAnnotation(CamelKarafTestHint.class);
- if (hint == null || hint.additionalRequiredFeatures().length == 0) {
- return getRequiredFeatures();
+ if (hasAdditionalRequiredFeatures()) {
+ List<String> requiredFeatures = new
ArrayList<>(getRequiredFeatures());
+
requiredFeatures.addAll(List.of(getCamelKarafTestHint().orElseThrow().additionalRequiredFeatures()));
+ return requiredFeatures;
}
- List<String> requiredFeatures = new ArrayList<>(getRequiredFeatures());
- requiredFeatures.addAll(List.of(hint.additionalRequiredFeatures()));
- return requiredFeatures;
+ return getRequiredFeatures();
}
+ /**
+ * Installs the required features for the test.
+ * @throws Exception if an error occurs while installing a feature
+ */
private void installRequiredFeatures() throws Exception {
for (String featureName : getAllRequiredFeatures()) {
if (featureService.getFeature(featureName) == null) {
@@ -301,8 +390,7 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
* @return {@code true} if the test is a blueprint test, {@code false}
otherwise
*/
private static boolean isBlueprintTest(Class<?> clazz) {
- CamelKarafTestHint hint =
clazz.getAnnotation(CamelKarafTestHint.class);
- return hint != null && hint.isBlueprintTest();
+ return
getCamelKarafTestHint(clazz).filter(CamelKarafTestHint::isBlueprintTest).isPresent();
}
private static Mode getMode(Class<?> clazz) {
@@ -381,7 +469,7 @@ public abstract class AbstractCamelRouteITest extends
KarafTestSupport implement
Assert.assertEquals(Bundle.ACTIVE, bundle.getState());
//need to check with the command because the status may be Active
while it's displayed as Waiting in the console
//because of an exception for instance
- String bundles = executeCommand("bundle:list -s -t 0 | grep
%s".formatted(name));
+ String bundles = executeCommand("bundle:list -s -t 0 | grep
%s".formatted(name), timeoutInMillis(), false);
Assert.assertTrue("bundle %s is in state %d
/%s".formatted(bundle.getSymbolicName(), bundle.getState(), bundles),
bundles.contains("Active"));
}
diff --git
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/CamelKarafTestHint.java
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/CamelKarafTestHint.java
index b7c79a595..858146974 100644
---
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/CamelKarafTestHint.java
+++
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/CamelKarafTestHint.java
@@ -15,6 +15,11 @@ import java.util.List;
@Inherited
public @interface CamelKarafTestHint {
+ /**
+ * The default timeout in seconds for the test.
+ */
+ int DEFAULT_TIMEOUT = 300;
+
/**
* Specify the class that provides the methods to create all the external
resources required by the test.
* In the provider class, each public static method that returns an
instance of a subtype of {@link ExternalResource}
@@ -52,4 +57,14 @@ public @interface CamelKarafTestHint {
* Forces to ignore all Camel route suppliers within the context of the
tests. False by default.
*/
boolean ignoreRouteSuppliers() default false;
+
+ /**
+ * Specify whether the test should be retried on failure. By default, no
retry is performed.
+ */
+ boolean retryOnFailure() default false;
+
+ /**
+ * Specify the timeout in seconds for the test. By default, the timeout is
300 seconds.
+ */
+ int timeout() default DEFAULT_TIMEOUT;
}
diff --git
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/DumpFileOnError.java
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/DumpFileOnError.java
new file mode 100644
index 000000000..fde04c61d
--- /dev/null
+++
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/DumpFileOnError.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.karaf.camel.itests;
+
+import java.io.File;
+import java.io.PrintStream;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class DumpFileOnError implements TestRule {
+
+ private final PrintStream out;
+ private final File file;
+ private final boolean enabled;
+
+ public DumpFileOnError(File file, PrintStream out, boolean enabled) {
+ this.file = file;
+ this.out = out;
+ this.enabled = enabled;
+ }
+
+ @Override
+ public Statement apply(Statement statement, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ statement.evaluate();
+ } catch (Throwable t) {
+ if (enabled) {
+ Utils.dumpFile(file, out);
+ }
+ throw t;
+ }
+ }
+ };
+ }
+}
diff --git
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/TestContainerFactoryFailureAware.java
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/TestContainerFactoryFailureAware.java
new file mode 100644
index 000000000..c926fb47b
--- /dev/null
+++
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/TestContainerFactoryFailureAware.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.karaf.camel.itests;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Queue;
+
+import org.ops4j.pax.exam.ExamSystem;
+import org.ops4j.pax.exam.TestAddress;
+import org.ops4j.pax.exam.TestContainer;
+import org.ops4j.pax.exam.TestContainerFactory;
+import org.ops4j.pax.exam.spi.PaxExamRuntime;
+import org.ops4j.pax.exam.util.PathUtils;
+
+import static
org.apache.karaf.camel.itests.AbstractCamelRouteITest.CAMEL_KARAF_INTEGRATION_TEST_DUMP_LOGS_PROPERTY;
+
+public class TestContainerFactoryFailureAware implements TestContainerFactory {
+
+ private final boolean enabled;
+ private final TestContainerFactory delegate;
+
+ public TestContainerFactoryFailureAware() {
+ this.enabled =
Boolean.getBoolean(CAMEL_KARAF_INTEGRATION_TEST_DUMP_LOGS_PROPERTY);
+ this.delegate = PaxExamRuntime.getTestContainerFactory();
+ }
+
+ @Override
+ public TestContainer[] create(ExamSystem system) {
+ TestContainer[] containers = delegate.create(system);
+ if (enabled) {
+ for (int i = 0; i < containers.length; i++) {
+ containers[i] = new TestContainerFailureAware(containers[i]);
+ }
+ }
+ return containers;
+ }
+
+ private static class TestContainerFailureAware implements TestContainer {
+
+ private final TestContainer delegate;
+
+ private TestContainerFailureAware(TestContainer delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public TestContainer start() {
+ try {
+ return delegate.start();
+ } catch (RuntimeException e) {
+ Utils.dumpFile(getKarafLogFile(), System.err);
+ throw e;
+ }
+ }
+
+ @Override
+ public long install(InputStream stream) {
+ return delegate.install(stream);
+ }
+
+ @Override
+ public long install(String location, InputStream stream) {
+ return delegate.install(location, stream);
+ }
+
+ @Override
+ public long installProbe(InputStream stream) {
+ return delegate.installProbe(stream);
+ }
+
+ @Override
+ public void uninstallProbe() {
+ delegate.uninstallProbe();
+ }
+
+ @Override
+ public void call(TestAddress address) {
+ delegate.call(address);
+ }
+
+ @Override
+ public TestContainer stop() {
+ return delegate.stop();
+ }
+
+ private static File getKarafUnpackDirectory() {
+ return new File(PathUtils.getBaseDir(), "target/exam");
+ }
+
+ private static File getKarafLogFile() {
+ return new File(searchKarafBase(getKarafUnpackDirectory()),
"data/log/karaf.log");
+ }
+
+ /**
+ * Since we might get quite deep use a simple breath first search
algorithm
+ */
+ private static File searchKarafBase(File root) {
+ Queue<File> searchNext = new LinkedList<>();
+ searchNext.add(root);
+ while (!searchNext.isEmpty()) {
+ File head = searchNext.poll();
+ if (!head.isDirectory()) {
+ continue;
+ }
+ if (new File(head, "system").isDirectory() && new File(head,
"etc").isDirectory()) {
+ return head;
+ }
+
searchNext.addAll(List.of(Objects.requireNonNull(head.listFiles())));
+ }
+ return null;
+ }
+ }
+}
diff --git
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/Utils.java
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/Utils.java
index 9d06ffe51..0c3594b22 100644
---
a/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/Utils.java
+++
b/tests/camel-integration-test/src/main/java/org/apache/karaf/camel/itests/Utils.java
@@ -16,8 +16,12 @@
*/
package org.apache.karaf.camel.itests;
+import java.io.File;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
@@ -25,6 +29,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.IntPredicate;
+import java.util.stream.Stream;
import org.jetbrains.annotations.NotNull;
import org.ops4j.pax.exam.MavenUtils;
@@ -119,4 +124,23 @@ public final class Utils {
throw new IllegalStateException("Can't find the users.properties file,
please provide it using the system " +
"property users.file.location");
}
+
+ /**
+ * Dump the given file into the stream.
+ */
+ static void dumpFile(File file, PrintStream out) {
+ if (file.exists()) {
+ out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ out.printf(">>>>> START Dumping file %s%n", file.getName());
+ out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
+ try (Stream<String> lines = Files.lines(file.toPath())) {
+ lines.forEach(out::println);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
+ out.printf("<<<<< END Dumping file %s%n", file.getName());
+ out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
+ }
+ }
}
diff --git a/tests/features/pom.xml b/tests/features/pom.xml
index 307832aee..f00f671a5 100644
--- a/tests/features/pom.xml
+++ b/tests/features/pom.xml
@@ -33,6 +33,7 @@
<name>Apache Camel :: Karaf :: Tests :: Features</name>
<properties>
+ <dump.logs.on.failure>false</dump.logs.on.failure>
<users.file.location>${project.basedir}/../../camel-integration-test/src/main/resources/etc/users.properties</users.file.location>
</properties>
@@ -296,6 +297,7 @@
<include>**/*Test.java</include>
</includes>
<systemPropertyVariables>
+
<camel.karaf.itest.dump.logs>${dump.logs.on.failure}</camel.karaf.itest.dump.logs>
<camel.karaf.version>${project.version}</camel.karaf.version>
<project.version>${project.version}</project.version>
<project.target>${project.build.directory}</project.target>