forked from apache/camel-karaf
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to write integration tests with TestContainer
- Loading branch information
Showing
14 changed files
with
477 additions
and
222 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
.../camel-integration-test/src/main/java/org/apache/karaf/camel/itests/ExternalResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package org.apache.karaf.camel.itests; | ||
|
||
import java.util.Map; | ||
|
||
/** | ||
* An interface representing an external resource to set up before a test and guarantee to tear it down afterward. | ||
* Compared to an {@link org.junit.rules.ExternalResource}, the methods {@link #before()} and {@link #after()} are | ||
* executed outside Karaf container, so it can be used to set up external resources like a database, a message broker, | ||
* etc. | ||
* @see TemporaryFile | ||
* @see GenericContainerResource | ||
*/ | ||
public interface ExternalResource { | ||
|
||
/** | ||
* Sets up the external resource. | ||
*/ | ||
void before(); | ||
|
||
/** | ||
* Tears down the external resource. | ||
*/ | ||
void after(); | ||
|
||
/** | ||
* Gives access to the properties of the external resource like a username, a password or a path, that will be | ||
* provided to the Karaf instance as System properties. | ||
*/ | ||
Map<String, String> properties(); | ||
} |
97 changes: 97 additions & 0 deletions
97
...ntegration-test/src/main/java/org/apache/karaf/camel/itests/GenericContainerResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/** | ||
* 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.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.function.Consumer; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.testcontainers.containers.GenericContainer; | ||
|
||
/** | ||
* A JUnit ExternalResource that starts and stops a TestContainer. | ||
* | ||
* @param <T> the type of the TestContainer | ||
*/ | ||
public class GenericContainerResource<T extends GenericContainer<T>> implements ExternalResource { | ||
|
||
private static final Logger LOG = LoggerFactory.getLogger(GenericContainerResource.class); | ||
private final T container; | ||
private final Map<String, String> properties = new HashMap<>(); | ||
private final List<ExternalResource> dependencies = new ArrayList<>(); | ||
private final Consumer<GenericContainerResource<T>> onStarted; | ||
|
||
public GenericContainerResource(T container) { | ||
this(container, t -> {}); | ||
} | ||
|
||
/** | ||
* Create a GenericContainerResource with the given TestContainer and a callback to be called when the container is | ||
* started. | ||
* @param container the TestContainer | ||
* @param onStarted the callback to be called when the container is started | ||
*/ | ||
public GenericContainerResource(T container, Consumer<GenericContainerResource<T>> onStarted) { | ||
this.container = container; | ||
this.onStarted = onStarted; | ||
} | ||
|
||
@Override | ||
public void before() { | ||
container.start(); | ||
onStarted.accept(this); | ||
for (ExternalResource dependency : dependencies) { | ||
dependency.properties().forEach(this::setProperty); | ||
} | ||
LOG.info("Container {} started", container.getDockerImageName()); | ||
} | ||
|
||
@Override | ||
public void after() { | ||
container.stop(); | ||
for (ExternalResource dependency : dependencies) { | ||
try { | ||
dependency.after(); | ||
} catch (Exception e) { | ||
LOG.warn("Error cleaning dependency: {}", dependency.getClass().getName(), e); | ||
} | ||
} | ||
LOG.info("Container {} stopped", container.getDockerImageName()); | ||
} | ||
|
||
@Override | ||
public Map<String, String> properties() { | ||
return properties; | ||
} | ||
|
||
public T getContainer() { | ||
return container; | ||
} | ||
|
||
public void setProperty(String key, String value) { | ||
properties.put(key, value); | ||
} | ||
|
||
public void addDependency(ExternalResource dependency) { | ||
dependencies.add(dependency); | ||
} | ||
} |
131 changes: 131 additions & 0 deletions
131
...gration-test/src/main/java/org/apache/karaf/camel/itests/PaxExamWithExternalResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
/** | ||
* 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.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.lang.reflect.Modifier; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import org.junit.runner.Description; | ||
import org.junit.runner.Runner; | ||
import org.junit.runner.manipulation.Filter; | ||
import org.junit.runner.manipulation.Filterable; | ||
import org.junit.runner.manipulation.NoTestsRemainException; | ||
import org.junit.runner.manipulation.Sortable; | ||
import org.junit.runner.manipulation.Sorter; | ||
import org.junit.runner.notification.RunNotifier; | ||
import org.junit.runners.ParentRunner; | ||
import org.junit.runners.model.InitializationError; | ||
import org.ops4j.pax.exam.junit.PaxExam; | ||
import org.ops4j.pax.exam.junit.impl.ProbeRunner; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** | ||
* A fork of {@link PaxExam} that supports external resources which can be created and destroyed outside Karaf. | ||
*/ | ||
public class PaxExamWithExternalResource extends Runner implements Filterable, Sortable { | ||
private static final Logger LOG = LoggerFactory.getLogger(PaxExamWithExternalResource.class); | ||
private static final ThreadLocal<PaxExamWithExternalResource> current = new ThreadLocal<>(); | ||
private final ParentRunner<?> delegate; | ||
private final List<ExternalResource> externalResources; | ||
|
||
public PaxExamWithExternalResource(Class<?> testClass) throws InitializationError, InvocationTargetException, | ||
IllegalAccessException { | ||
this.externalResources = beforeAll(testClass); | ||
try { | ||
current.set(this); | ||
this.delegate = new ProbeRunner(testClass); | ||
} finally { | ||
current.remove(); | ||
} | ||
} | ||
|
||
private List<ExternalResource> beforeAll(Class<?> testClass) throws InvocationTargetException, IllegalAccessException { | ||
UseExternalResourceProvider annotation = testClass.getAnnotation(UseExternalResourceProvider.class); | ||
if (annotation != null) { | ||
List<ExternalResource> result = new ArrayList<>(); | ||
for (Method m : annotation.value().getMethods()) { | ||
if (isExternalResourceSupplier(m)) { | ||
ExternalResource externalResource = (ExternalResource) m.invoke(null); | ||
externalResource.before(); | ||
result.add(externalResource); | ||
} | ||
} | ||
return result; | ||
} | ||
LOG.warn("Class {} is not annotated with @UseExternalResourceProvider", testClass.getName()); | ||
return List.of(); | ||
} | ||
|
||
private boolean isExternalResourceSupplier(Method m) { | ||
return ExternalResource.class.isAssignableFrom(m.getReturnType()) && m.getParameterTypes().length == 0 | ||
&& Modifier.isStatic(m.getModifiers()); | ||
} | ||
|
||
@Override | ||
public Description getDescription() { | ||
return delegate.getDescription(); | ||
} | ||
|
||
@Override | ||
public void run(RunNotifier notifier) { | ||
try { | ||
delegate.run(notifier); | ||
} finally { | ||
afterAll(); | ||
} | ||
} | ||
|
||
private void afterAll() { | ||
for (int i = externalResources.size() - 1; i >= 0; i--) { | ||
try { | ||
externalResources.get(i).after(); | ||
} catch (Exception e) { | ||
LOG.warn("Error while cleaning up external resource", e); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void filter(Filter filter) throws NoTestsRemainException { | ||
delegate.filter(filter); | ||
} | ||
|
||
@Override | ||
public void sort(Sorter sorter) { | ||
delegate.sort(sorter); | ||
} | ||
|
||
static Map<String, String> systemProperties() { | ||
PaxExamWithExternalResource value = current.get(); | ||
if (value == null) { | ||
return Map.of(); | ||
} | ||
return value.externalResources.stream() | ||
.map(ExternalResource::properties) | ||
.map(Map::entrySet) | ||
.flatMap(Set::stream) | ||
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue)); | ||
} | ||
} |
Oops, something went wrong.