Refactor testcontainers service connections
Update restcontainers service connections support so that technology specific `@ServiceConnector` annotations are not longer required. A single `@ServiceConnector` annotation can now be used to create all `ConnectionDetail` beans. Closes gh-35017
This commit is contained in:
@@ -16,9 +16,9 @@
|
||||
|
||||
package org.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Container;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
@@ -26,13 +26,13 @@ import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.boot.origin.OriginProvider;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Base class for {@link ConnectionDetailsFactory} implementations that provide
|
||||
* {@link ConnectionDetails} from a {@link ContainerConnectionSource}.
|
||||
*
|
||||
* @param <A> the source annotation type. The annotation will be mergable to a
|
||||
* {@link ServiceConnection @ServiceConnection}.
|
||||
* @param <D> the connection details type
|
||||
* @param <C> the generic container type
|
||||
* @author Moritz Halbritter
|
||||
@@ -40,17 +40,58 @@ import org.springframework.util.Assert;
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public abstract class ContainerConnectionDetailsFactory<A extends Annotation, D extends ConnectionDetails, C extends GenericContainer<?>>
|
||||
implements ConnectionDetailsFactory<ContainerConnectionSource<A, D, C>, D> {
|
||||
public abstract class ContainerConnectionDetailsFactory<D extends ConnectionDetails, C extends Container<?>>
|
||||
implements ConnectionDetailsFactory<ContainerConnectionSource<D, C>, D> {
|
||||
|
||||
/**
|
||||
* Constant passed to the constructor when any connection name is accepted.
|
||||
*/
|
||||
protected static final String ANY_CONNECTION_NAME = null;
|
||||
|
||||
private final String connectionName;
|
||||
|
||||
private final String[] requiredClassNames;
|
||||
|
||||
/**
|
||||
* Create a new {@link ContainerConnectionDetailsFactory} instance that accepts
|
||||
* {@link #ANY_CONNECTION_NAME any connection name}.
|
||||
*/
|
||||
protected ContainerConnectionDetailsFactory() {
|
||||
this(ANY_CONNECTION_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ContainerConnectionDetailsFactory} instance with the given
|
||||
* connection name restriction.
|
||||
* @param connectionName the required connection name or {@link #ANY_CONNECTION_NAME}
|
||||
* @param requiredClassNames the names of classes that must be present
|
||||
*/
|
||||
protected ContainerConnectionDetailsFactory(String connectionName, String... requiredClassNames) {
|
||||
this.connectionName = connectionName;
|
||||
this.requiredClassNames = requiredClassNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final D getConnectionDetails(ContainerConnectionSource<A, D, C> source) {
|
||||
Class<?>[] generics = resolveGenerics();
|
||||
Class<?> annotationType = generics[0];
|
||||
Class<?> connectionDetailsType = generics[1];
|
||||
Class<?> containerType = generics[2];
|
||||
return (!source.accepts(annotationType, connectionDetailsType, containerType)) ? null
|
||||
: getContainerConnectionDetails(source);
|
||||
public final D getConnectionDetails(ContainerConnectionSource<D, C> source) {
|
||||
if (!hasRequiredClasses()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Class<?>[] generics = resolveGenerics();
|
||||
Class<?> connectionDetailsType = generics[0];
|
||||
Class<?> containerType = generics[1];
|
||||
if (source.accepts(this.connectionName, connectionDetailsType, containerType)) {
|
||||
return getContainerConnectionDetails(source);
|
||||
}
|
||||
}
|
||||
catch (NoClassDefFoundError ex) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasRequiredClasses() {
|
||||
return ObjectUtils.isEmpty(this.requiredClassNames) || Arrays.stream(this.requiredClassNames)
|
||||
.allMatch((requiredClassName) -> ClassUtils.isPresent(requiredClassName, null));
|
||||
}
|
||||
|
||||
private Class<?>[] resolveGenerics() {
|
||||
@@ -64,7 +105,7 @@ public abstract class ContainerConnectionDetailsFactory<A extends Annotation, D
|
||||
* @param source the source
|
||||
* @return the service connection or {@code null}.
|
||||
*/
|
||||
protected abstract D getContainerConnectionDetails(ContainerConnectionSource<A, D, C> source);
|
||||
protected abstract D getContainerConnectionDetails(ContainerConnectionSource<D, C> source);
|
||||
|
||||
/**
|
||||
* Convenient base class for {@link ConnectionDetails} results that are backed by a
|
||||
@@ -78,7 +119,7 @@ public abstract class ContainerConnectionDetailsFactory<A extends Annotation, D
|
||||
* Create a new {@link ContainerConnectionDetails} instance.
|
||||
* @param source the source {@link ContainerConnectionSource}
|
||||
*/
|
||||
protected ContainerConnectionDetails(ContainerConnectionSource<?, ?, ?> source) {
|
||||
protected ContainerConnectionDetails(ContainerConnectionSource<?, ?> source) {
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
this.origin = source.getOrigin();
|
||||
}
|
||||
|
||||
@@ -16,23 +16,25 @@
|
||||
|
||||
package org.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Set;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.testcontainers.containers.Container;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.boot.origin.OriginProvider;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Passed to {@link ContainerConnectionDetailsFactory} to provide details of the
|
||||
* {@link ServiceConnection @ServiceConnection} annotation {@link GenericContainer} field
|
||||
* that provides the service.
|
||||
* {@link ServiceConnection @ServiceConnection} annotated {@link Container} that provides
|
||||
* the service.
|
||||
*
|
||||
* @param <A> the source annotation type. The annotation will mergable to a
|
||||
* {@link ServiceConnection @ServiceConnection}
|
||||
* @param <D> the connection details type
|
||||
* @param <C> the generic container type
|
||||
* @author Moritz Halbritter
|
||||
@@ -41,58 +43,77 @@ import org.springframework.core.annotation.MergedAnnotation;
|
||||
* @since 3.1.0
|
||||
* @see ContainerConnectionDetailsFactory
|
||||
*/
|
||||
public final class ContainerConnectionSource<A extends Annotation, D extends ConnectionDetails, C extends GenericContainer<?>>
|
||||
public final class ContainerConnectionSource<D extends ConnectionDetails, C extends Container<?>>
|
||||
implements OriginProvider {
|
||||
|
||||
private final Class<D> connectionDetailsType;
|
||||
private static final Log logger = LogFactory.getLog(ContainerConnectionSource.class);
|
||||
|
||||
private final Field field;
|
||||
private final String beanNameSuffix;
|
||||
|
||||
private final A annotation;
|
||||
private final Origin origin;
|
||||
|
||||
private final C container;
|
||||
|
||||
private final AnnotatedFieldOrigin origin;
|
||||
private String acceptedConnectionName;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ContainerConnectionSource(Class<D> connectionDetailsType, Field field,
|
||||
MergedAnnotation<ServiceConnection> annotation, C container) {
|
||||
this(connectionDetailsType, field, (A) annotation.getRoot().synthesize(), container);
|
||||
}
|
||||
private Set<Class<?>> acceptedConnectionDetailsTypes;
|
||||
|
||||
ContainerConnectionSource(Class<D> connectionDetailsType, Field field, A annotation, C container) {
|
||||
this.connectionDetailsType = connectionDetailsType;
|
||||
this.field = field;
|
||||
this.annotation = annotation;
|
||||
ContainerConnectionSource(String beanNameSuffix, Origin origin, C container,
|
||||
MergedAnnotation<ServiceConnection> annotation) {
|
||||
this.beanNameSuffix = beanNameSuffix;
|
||||
this.origin = origin;
|
||||
this.container = container;
|
||||
this.origin = new AnnotatedFieldOrigin(field, annotation);
|
||||
this.acceptedConnectionName = getConnectionName(container, annotation.getString("name"));
|
||||
this.acceptedConnectionDetailsTypes = Set.of(annotation.getClassArray("type"));
|
||||
}
|
||||
|
||||
boolean accepts(Class<?> annotationType, Class<?> connectionDetailsType, Class<?> containerType) {
|
||||
return annotationType.isInstance(this.annotation)
|
||||
&& connectionDetailsType.isAssignableFrom(this.connectionDetailsType)
|
||||
&& containerType.isInstance(this.container);
|
||||
ContainerConnectionSource(String beanNameSuffix, Origin origin, C container, ServiceConnection annotation) {
|
||||
this.beanNameSuffix = beanNameSuffix;
|
||||
this.origin = origin;
|
||||
this.container = container;
|
||||
this.acceptedConnectionName = getConnectionName(container, annotation.name());
|
||||
this.acceptedConnectionDetailsTypes = Set.of(annotation.type());
|
||||
}
|
||||
|
||||
String getBeanName() {
|
||||
return this.field.getName() + this.connectionDetailsType.getSimpleName() + "ConnectedContainer";
|
||||
private static String getConnectionName(Container<?> container, String connectionName) {
|
||||
if (StringUtils.hasLength(connectionName)) {
|
||||
return connectionName;
|
||||
}
|
||||
try {
|
||||
DockerImageName imageName = DockerImageName.parse(container.getDockerImageName());
|
||||
imageName.assertValid();
|
||||
return imageName.getRepository();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
return container.getDockerImageName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the source annotation that provided the connection to the container. This
|
||||
* annotation will be mergable to {@link ServiceConnection @ServiceConnection}.
|
||||
* @return the source annotation
|
||||
*/
|
||||
public A getAnnotation() {
|
||||
return this.annotation;
|
||||
boolean accepts(String connectionName, Class<?> connectionDetailsType, Class<?> containerType) {
|
||||
if (!containerType.isInstance(this.container)) {
|
||||
logger.trace(LogMessage.of(() -> "%s not accepted as %s is not an instance of %s".formatted(this,
|
||||
this.container.getClass().getName(), containerType.getName())));
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.hasLength(connectionName) && !connectionName.equalsIgnoreCase(this.acceptedConnectionName)) {
|
||||
logger.trace(LogMessage.of(() -> "%s not accepted as connection names '%s' and '%s' do not match"
|
||||
.formatted(this, connectionName, this.acceptedConnectionName)));
|
||||
return false;
|
||||
}
|
||||
if (!this.acceptedConnectionDetailsTypes.isEmpty() && !this.acceptedConnectionDetailsTypes.stream()
|
||||
.anyMatch((candidate) -> candidate.isAssignableFrom(connectionDetailsType))) {
|
||||
logger.trace(LogMessage.of(() -> "%s not accepted as connection details type %s not in %s".formatted(this,
|
||||
connectionDetailsType, this.acceptedConnectionDetailsTypes)));
|
||||
return false;
|
||||
}
|
||||
logger.trace(LogMessage
|
||||
.of(() -> "%s accepted for connection name '%s', connection details type %s, container type %s"
|
||||
.formatted(this, connectionName, connectionDetailsType.getName(), containerType.getName())));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link GenericContainer} that implements the service being connected to.
|
||||
* @return the {@link GenericContainer} providing the service
|
||||
*/
|
||||
public C getContainer() {
|
||||
return this.container;
|
||||
String getBeanNameSuffix() {
|
||||
return this.beanNameSuffix;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,9 +121,17 @@ public final class ContainerConnectionSource<A extends Annotation, D extends Con
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link Container} that implements the service being connected to.
|
||||
* @return the {@link Container} providing the service
|
||||
*/
|
||||
public C getContainer() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ServiceConnectedContainer for %s".formatted(this.origin);
|
||||
return "@ServiceConnection source for %s".formatted(this.origin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Class used to register bean definitions from a list of
|
||||
* {@link ContainerConnectionSource} instances.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ContainerConnectionSourcesRegistrar {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ContainerConnectionSourcesRegistrar.class);
|
||||
|
||||
private final ListableBeanFactory beanFactory;
|
||||
|
||||
private final ConnectionDetailsFactories connectionDetailsFactories;
|
||||
|
||||
private final List<ContainerConnectionSource<?, ?>> sources;
|
||||
|
||||
ContainerConnectionSourcesRegistrar(ListableBeanFactory beanFactory,
|
||||
ConnectionDetailsFactories connectionDetailsFactories, List<ContainerConnectionSource<?, ?>> sources) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.connectionDetailsFactories = connectionDetailsFactories;
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
void registerBeanDefinitions(BeanDefinitionRegistry registry) {
|
||||
this.sources.forEach((source) -> registerBeanDefinition(registry, source));
|
||||
}
|
||||
|
||||
private void registerBeanDefinition(BeanDefinitionRegistry registry, ContainerConnectionSource<?, ?> source) {
|
||||
getConnectionDetails(source)
|
||||
.forEach((connectionDetailsType, connectionDetails) -> registerBeanDefinition(registry, source,
|
||||
connectionDetailsType, connectionDetails));
|
||||
}
|
||||
|
||||
private <S> Map<Class<?>, ConnectionDetails> getConnectionDetails(S source) {
|
||||
Map<Class<?>, ConnectionDetails> connectionDetails = this.connectionDetailsFactories
|
||||
.getConnectionDetails(source);
|
||||
Assert.state(!connectionDetails.isEmpty(), () -> "No connection details created for %s".formatted(source));
|
||||
return connectionDetails;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void registerBeanDefinition(BeanDefinitionRegistry registry, ContainerConnectionSource<?, ?> source,
|
||||
Class<?> connectionDetailsType, ConnectionDetails connectionDetails) {
|
||||
String[] existingBeans = this.beanFactory.getBeanNamesForType(connectionDetailsType);
|
||||
if (!ObjectUtils.isEmpty(existingBeans)) {
|
||||
logger.debug(LogMessage.of(() -> "Skipping registration of %s due to existing beans %s".formatted(source,
|
||||
Arrays.asList(existingBeans))));
|
||||
return;
|
||||
}
|
||||
String beanName = getBeanName(source, connectionDetails);
|
||||
Class<T> beanType = (Class<T>) connectionDetails.getClass();
|
||||
Supplier<T> beanSupplier = () -> (T) connectionDetails;
|
||||
logger.debug(LogMessage.of(() -> "Registering '%s' for %s".formatted(beanName, source)));
|
||||
registry.registerBeanDefinition(beanName, new RootBeanDefinition(beanType, beanSupplier));
|
||||
}
|
||||
|
||||
private String getBeanName(ContainerConnectionSource<?, ?> source, ConnectionDetails connectionDetails) {
|
||||
List<String> parts = new ArrayList<>();
|
||||
parts.add(ClassUtils.getShortNameAsProperty(connectionDetails.getClass()));
|
||||
parts.add("for");
|
||||
parts.add(source.getBeanNameSuffix());
|
||||
return StringUtils.uncapitalize(parts.stream().map(StringUtils::capitalize).collect(Collectors.joining()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,31 +16,26 @@
|
||||
|
||||
package org.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link Origin} backed by a {@link Field} and an {@link Annotation}.
|
||||
* {@link Origin} backed by a {@link Field}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class AnnotatedFieldOrigin implements Origin {
|
||||
class FieldOrigin implements Origin {
|
||||
|
||||
private final Field field;
|
||||
|
||||
private final Annotation annotation;
|
||||
|
||||
AnnotatedFieldOrigin(Field field, Annotation annotation) {
|
||||
FieldOrigin(Field field) {
|
||||
Assert.notNull(field, "Field must not be null");
|
||||
Assert.notNull(annotation, "Annotation must not be null");
|
||||
this.field = field;
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,18 +46,18 @@ class AnnotatedFieldOrigin implements Origin {
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
AnnotatedFieldOrigin other = (AnnotatedFieldOrigin) obj;
|
||||
return this.field.equals(other.field) && this.annotation.equals(other.annotation);
|
||||
FieldOrigin other = (FieldOrigin) obj;
|
||||
return this.field.equals(other.field);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.field, this.annotation);
|
||||
return this.field.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.annotation + " " + this.field;
|
||||
return ClassUtils.getShortName(this.field.getDeclaringClass()) + "." + this.field.getName();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,15 +21,14 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.testcontainers.containers.Container;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Annotation used to indicate that a field provides a service that can be connected to.
|
||||
* Typically used to meta-annotate a higher-level annotation.
|
||||
* <p>
|
||||
* When used, a {@link ConnectionDetailsFactory} must be registered in
|
||||
* {@code spring.factories} to provide {@link ConnectionDetails} for the field value.
|
||||
* Annotation used to indicate that a field or method is a
|
||||
* {@link ContainerConnectionSource} which provides a service that can be connected to.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
@@ -37,14 +36,35 @@ import org.springframework.boot.autoconfigure.service.connection.ConnectionDetai
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
public @interface ServiceConnection {
|
||||
|
||||
/**
|
||||
* The type of {@link ConnectionDetails} that can describe how to connect to the
|
||||
* service.
|
||||
* @return the connection type
|
||||
* The name of the service being connected to. If not specified, the image name will
|
||||
* be used. Container names are used to determine the connection details that should
|
||||
* be created when a technology-specific {@link Container} subclass is not available.
|
||||
* This attribute is an alias for {@link #name()}.
|
||||
* @return the name of the service
|
||||
* @see #name()
|
||||
*/
|
||||
Class<? extends ConnectionDetails> value();
|
||||
@AliasFor("name")
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* The name of the service being connected to. If not specified, the image name will
|
||||
* be used. Container names are used to determine the connection details that should
|
||||
* be created when a technology-specific {@link Container} subclass is not available.
|
||||
* @return the name of the service
|
||||
* @see #value()
|
||||
*/
|
||||
@AliasFor("value")
|
||||
String name() default "";
|
||||
|
||||
/**
|
||||
* A restriction to types of {@link ConnectionDetails} that can be created from this
|
||||
* connection. The default value does not restrict the types that can be created.
|
||||
* @return the connection detail types that can be created to establish the connection
|
||||
*/
|
||||
Class<? extends ConnectionDetails>[] type() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,21 +17,17 @@
|
||||
package org.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.ContextCustomizer;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link ContextCustomizer} to support registering {@link ConnectionDetails}.
|
||||
* Spring Test {@link ContextCustomizer} to support registering {@link ConnectionDetails}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
@@ -39,46 +35,30 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
class ServiceConnectionContextCustomizer implements ContextCustomizer {
|
||||
|
||||
private final ConnectionDetailsFactories factories = new ConnectionDetailsFactories();
|
||||
private final List<ContainerConnectionSource<?, ?>> sources;
|
||||
|
||||
private final List<ContainerConnectionSource<?, ?, ?>> sources;
|
||||
private final ConnectionDetailsFactories connectionDetailsFactories;
|
||||
|
||||
ServiceConnectionContextCustomizer(List<ContainerConnectionSource<?, ?, ?>> sources) {
|
||||
ServiceConnectionContextCustomizer(List<ContainerConnectionSource<?, ?>> sources) {
|
||||
this(sources, new ConnectionDetailsFactories());
|
||||
}
|
||||
|
||||
ServiceConnectionContextCustomizer(List<ContainerConnectionSource<?, ?>> sources,
|
||||
ConnectionDetailsFactories connectionDetailsFactories) {
|
||||
this.sources = sources;
|
||||
this.connectionDetailsFactories = connectionDetailsFactories;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
|
||||
if (beanFactory instanceof BeanDefinitionRegistry registry) {
|
||||
registerServiceConnections(registry);
|
||||
new ContainerConnectionSourcesRegistrar(beanFactory, this.connectionDetailsFactories, this.sources)
|
||||
.registerBeanDefinitions(registry);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerServiceConnections(BeanDefinitionRegistry registry) {
|
||||
this.sources.forEach((source) -> registerServiceConnection(registry, source));
|
||||
}
|
||||
|
||||
private void registerServiceConnection(BeanDefinitionRegistry registry, ContainerConnectionSource<?, ?, ?> source) {
|
||||
ConnectionDetails connectionDetails = getConnectionDetails(source);
|
||||
register(connectionDetails, registry, source.getBeanName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void register(ConnectionDetails connectionDetails, BeanDefinitionRegistry registry, String beanName) {
|
||||
Class<T> beanType = (Class<T>) connectionDetails.getClass();
|
||||
Supplier<T> beanSupplier = () -> (T) connectionDetails;
|
||||
BeanDefinition beanDefinition = new RootBeanDefinition(beanType, beanSupplier);
|
||||
registry.registerBeanDefinition(beanName, beanDefinition);
|
||||
}
|
||||
|
||||
private <S> ConnectionDetails getConnectionDetails(S source) {
|
||||
ConnectionDetails connectionDetails = this.factories.getConnectionDetails(source);
|
||||
Assert.state(connectionDetails != null, () -> "No connection details created for %s".formatted(source));
|
||||
return connectionDetails;
|
||||
}
|
||||
|
||||
List<ContainerConnectionSource<?, ?, ?>> getSources() {
|
||||
List<ContainerConnectionSource<?, ?>> getSources() {
|
||||
return this.sources;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.Container;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
@@ -31,10 +31,14 @@ import org.springframework.test.context.ContextCustomizer;
|
||||
import org.springframework.test.context.ContextCustomizerFactory;
|
||||
import org.springframework.test.context.TestContextAnnotationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link ContextCustomizerFactory} to support service connections in tests.
|
||||
* Spring Test {@link ContextCustomizerFactory} to support
|
||||
* {@link ServiceConnection @ServiceConnection} annotated {@link Container} fields in
|
||||
* tests.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
@@ -45,12 +49,12 @@ class ServiceConnectionContextCustomizerFactory implements ContextCustomizerFact
|
||||
@Override
|
||||
public ContextCustomizer createContextCustomizer(Class<?> testClass,
|
||||
List<ContextConfigurationAttributes> configAttributes) {
|
||||
List<ContainerConnectionSource<?, ?, ?>> sources = new ArrayList<>();
|
||||
List<ContainerConnectionSource<?, ?>> sources = new ArrayList<>();
|
||||
findSources(testClass, sources);
|
||||
return (sources.isEmpty()) ? null : new ServiceConnectionContextCustomizer(sources);
|
||||
}
|
||||
|
||||
private void findSources(Class<?> clazz, List<ContainerConnectionSource<?, ?, ?>> sources) {
|
||||
private void findSources(Class<?> clazz, List<ContainerConnectionSource<?, ?>> sources) {
|
||||
ReflectionUtils.doWithFields(clazz, (field) -> {
|
||||
MergedAnnotations annotations = MergedAnnotations.from(field);
|
||||
annotations.stream(ServiceConnection.class)
|
||||
@@ -61,23 +65,17 @@ class ServiceConnectionContextCustomizerFactory implements ContextCustomizerFact
|
||||
}
|
||||
}
|
||||
|
||||
private ContainerConnectionSource<?, ?, ?> createSource(Field field,
|
||||
MergedAnnotation<ServiceConnection> annotation) {
|
||||
if (!Modifier.isStatic(field.getModifiers())) {
|
||||
throw new IllegalStateException("@ServiceConnection field '%s' must be static".formatted(field.getName()));
|
||||
}
|
||||
Class<? extends ConnectionDetails> connectionDetailsType = getConnectionDetailsType(annotation);
|
||||
private ContainerConnectionSource<?, ?> createSource(Field field, MergedAnnotation<ServiceConnection> annotation) {
|
||||
Assert.state(Modifier.isStatic(field.getModifiers()),
|
||||
() -> "@ServiceConnection field '%s' must be static".formatted(field.getName()));
|
||||
String beanNameSuffix = StringUtils.capitalize(ClassUtils.getShortNameAsProperty(field.getDeclaringClass()))
|
||||
+ StringUtils.capitalize(field.getName());
|
||||
Origin origin = new FieldOrigin(field);
|
||||
Object fieldValue = getFieldValue(field);
|
||||
Assert.isInstanceOf(GenericContainer.class, fieldValue,
|
||||
"Field %s must be a %s".formatted(field.getName(), GenericContainer.class.getName()));
|
||||
GenericContainer<?> container = (GenericContainer<?>) fieldValue;
|
||||
return new ContainerConnectionSource<>(connectionDetailsType, field, annotation, container);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Class<? extends ConnectionDetails> getConnectionDetailsType(
|
||||
MergedAnnotation<ServiceConnection> annotation) {
|
||||
return (Class<? extends ConnectionDetails>) annotation.getClass(MergedAnnotation.VALUE);
|
||||
Assert.state(Container.class.isInstance(fieldValue), () -> "Field '%s' in %s must be a %s"
|
||||
.formatted(field.getName(), field.getDeclaringClass().getName(), Container.class.getName()));
|
||||
Container<?> container = (Container<?>) fieldValue;
|
||||
return new ContainerConnectionSource<>(beanNameSuffix, origin, container, annotation);
|
||||
}
|
||||
|
||||
private Object getFieldValue(Field field) {
|
||||
|
||||
@@ -24,22 +24,23 @@ import org.testcontainers.containers.RabbitMQContainer;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link RabbitServiceConnection @RabbitServiceConnection}-annotated
|
||||
* {@link RabbitMQContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link RabbitConnectionDetails}
|
||||
* from a {@link ServiceConnection @ServiceConnection}-annotated
|
||||
* {@link RabbitMQContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class RabbitContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<RabbitServiceConnection, RabbitConnectionDetails, RabbitMQContainer> {
|
||||
extends ContainerConnectionDetailsFactory<RabbitConnectionDetails, RabbitMQContainer> {
|
||||
|
||||
@Override
|
||||
protected RabbitConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<RabbitServiceConnection, RabbitConnectionDetails, RabbitMQContainer> source) {
|
||||
ContainerConnectionSource<RabbitConnectionDetails, RabbitMQContainer> source) {
|
||||
return new RabbitMqContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ class RabbitContainerConnectionDetailsFactory
|
||||
private final RabbitMQContainer container;
|
||||
|
||||
private RabbitMqContainerConnectionDetails(
|
||||
ContainerConnectionSource<RabbitServiceConnection, RabbitConnectionDetails, RabbitMQContainer> source) {
|
||||
ContainerConnectionSource<RabbitConnectionDetails, RabbitMQContainer> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.amqp;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a RabbitMQ service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
* @see RabbitConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(RabbitConnectionDetails.class)
|
||||
public @interface RabbitServiceConnection {
|
||||
|
||||
}
|
||||
@@ -23,22 +23,23 @@ import org.testcontainers.containers.CassandraContainer;
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link CassandraServiceConnection @CassandraServiceConnection}-annotated
|
||||
* {@link CassandraContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link CassandraConnectionDetails}
|
||||
* from a {@link ServiceConnection @ServiceConnection}-annotated
|
||||
* {@link CassandraContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class CassandraContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<CassandraServiceConnection, CassandraConnectionDetails, CassandraContainer<?>> {
|
||||
class CassandraContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<CassandraConnectionDetails, CassandraContainer<?>> {
|
||||
|
||||
@Override
|
||||
protected CassandraConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<CassandraServiceConnection, CassandraConnectionDetails, CassandraContainer<?>> source) {
|
||||
ContainerConnectionSource<CassandraConnectionDetails, CassandraContainer<?>> source) {
|
||||
return new CassandraContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ class CassandraContainerConnectionDetailsFactory extends
|
||||
private final CassandraContainer<?> container;
|
||||
|
||||
private CassandraContainerConnectionDetails(
|
||||
ContainerConnectionSource<CassandraServiceConnection, CassandraConnectionDetails, CassandraContainer<?>> source) {
|
||||
ContainerConnectionSource<CassandraConnectionDetails, CassandraContainer<?>> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.cassandra;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.cassandra.CassandraConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a Cassandra service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
* @see CassandraConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(CassandraConnectionDetails.class)
|
||||
public @interface CassandraServiceConnection {
|
||||
|
||||
}
|
||||
@@ -21,22 +21,23 @@ import org.testcontainers.couchbase.CouchbaseContainer;
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link CouchbaseServiceConnection @CouchbaseServiceConnection}-annotated
|
||||
* {@link CouchbaseContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link CouchbaseConnectionDetails}
|
||||
* from a {@link ServiceConnection @ServiceConnection}-annotated
|
||||
* {@link CouchbaseContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class CouchbaseContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<CouchbaseServiceConnection, CouchbaseConnectionDetails, CouchbaseContainer> {
|
||||
class CouchbaseContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<CouchbaseConnectionDetails, CouchbaseContainer> {
|
||||
|
||||
@Override
|
||||
protected CouchbaseConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<CouchbaseServiceConnection, CouchbaseConnectionDetails, CouchbaseContainer> source) {
|
||||
ContainerConnectionSource<CouchbaseConnectionDetails, CouchbaseContainer> source) {
|
||||
return new CouchbaseContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ class CouchbaseContainerConnectionDetailsFactory extends
|
||||
private final CouchbaseContainer container;
|
||||
|
||||
private CouchbaseContainerConnectionDetails(
|
||||
ContainerConnectionSource<CouchbaseServiceConnection, CouchbaseConnectionDetails, CouchbaseContainer> source) {
|
||||
ContainerConnectionSource<CouchbaseConnectionDetails, CouchbaseContainer> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.couchbase;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.couchbase.CouchbaseConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a Couchbase service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
* @see CouchbaseConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(CouchbaseConnectionDetails.class)
|
||||
public @interface CouchbaseServiceConnection {
|
||||
|
||||
}
|
||||
@@ -18,30 +18,31 @@ package org.springframework.boot.testcontainers.service.connection.elasticsearch
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails.Node.Protocol;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link ElasticsearchServiceConnection @ElasticsearchServiceConnection}-annotated
|
||||
* {@link GenericContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create
|
||||
* {@link ElasticsearchConnectionDetails} from a
|
||||
* {@link ServiceConnection @ServiceConnection}-annotated {@link ElasticsearchContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ElasticsearchContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<ElasticsearchServiceConnection, ElasticsearchConnectionDetails, GenericContainer<?>> {
|
||||
class ElasticsearchContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<ElasticsearchConnectionDetails, ElasticsearchContainer> {
|
||||
|
||||
private static final int DEFAULT_PORT = 9200;
|
||||
|
||||
@Override
|
||||
protected ElasticsearchConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<ElasticsearchServiceConnection, ElasticsearchConnectionDetails, GenericContainer<?>> source) {
|
||||
ContainerConnectionSource<ElasticsearchConnectionDetails, ElasticsearchContainer> source) {
|
||||
return new ElasticsearchContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -55,7 +56,7 @@ class ElasticsearchContainerConnectionDetailsFactory extends
|
||||
private final List<Node> nodes;
|
||||
|
||||
private ElasticsearchContainerConnectionDetails(
|
||||
ContainerConnectionSource<ElasticsearchServiceConnection, ElasticsearchConnectionDetails, GenericContainer<?>> source) {
|
||||
ContainerConnectionSource<ElasticsearchConnectionDetails, ElasticsearchContainer> source) {
|
||||
super(source);
|
||||
this.nodes = List.of(new Node(source.getContainer().getHost(),
|
||||
source.getContainer().getMappedPort(DEFAULT_PORT), Protocol.HTTP, null, null));
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.elasticsearch;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a Elasticsearch service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
* @see ElasticsearchConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(ElasticsearchConnectionDetails.class)
|
||||
public @interface ElasticsearchServiceConnection {
|
||||
|
||||
}
|
||||
@@ -24,18 +24,18 @@ import org.springframework.boot.testcontainers.service.connection.ContainerConne
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link ServiceConnection @ServiceConnection}-annotated {@link JdbcDatabaseContainer}
|
||||
* fields that should produce {@link FlywayConnectionDetails}.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link FlywayConnectionDetails}
|
||||
* from a {@link ServiceConnection @ServiceConnection}-annotated
|
||||
* {@link JdbcDatabaseContainer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class FlywayContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<ServiceConnection, FlywayConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
class FlywayContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<FlywayConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
|
||||
@Override
|
||||
protected FlywayConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<ServiceConnection, FlywayConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
ContainerConnectionSource<FlywayConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
return new FlywayContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class FlywayContainerConnectionDetailsFactory extends
|
||||
private final JdbcDatabaseContainer<?> container;
|
||||
|
||||
private FlywayContainerConnectionDetails(
|
||||
ContainerConnectionSource<ServiceConnection, FlywayConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
ContainerConnectionSource<FlywayConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -23,22 +23,23 @@ import org.testcontainers.containers.InfluxDBContainer;
|
||||
import org.springframework.boot.autoconfigure.influx.InfluxDbConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link InfluxDbServiceConnection @InfluxDbServiceConnection}-annotated
|
||||
* {@link InfluxDBContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link InfluxDbConnectionDetails}
|
||||
* from a {@link ServiceConnection @ServiceConnection}-annotated
|
||||
* {@link InfluxDBContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class InfluxDbContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<InfluxDbServiceConnection, InfluxDbConnectionDetails, InfluxDBContainer<?>> {
|
||||
class InfluxDbContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<InfluxDbConnectionDetails, InfluxDBContainer<?>> {
|
||||
|
||||
@Override
|
||||
protected InfluxDbConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<InfluxDbServiceConnection, InfluxDbConnectionDetails, InfluxDBContainer<?>> source) {
|
||||
ContainerConnectionSource<InfluxDbConnectionDetails, InfluxDBContainer<?>> source) {
|
||||
return new InfluxDbContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -51,7 +52,7 @@ class InfluxDbContainerConnectionDetailsFactory extends
|
||||
private final InfluxDBContainer<?> container;
|
||||
|
||||
private InfluxDbContainerConnectionDetails(
|
||||
ContainerConnectionSource<InfluxDbServiceConnection, InfluxDbConnectionDetails, InfluxDBContainer<?>> source) {
|
||||
ContainerConnectionSource<InfluxDbConnectionDetails, InfluxDBContainer<?>> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.influx;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.influx.InfluxDbConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides an InfluxDB service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
* @see InfluxDbConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(InfluxDbConnectionDetails.class)
|
||||
public @interface InfluxDbServiceConnection {
|
||||
|
||||
}
|
||||
@@ -21,22 +21,22 @@ import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link JdbcServiceConnection @JdbcServiceConnection}-annotated
|
||||
* {@link JdbcDatabaseContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link JdbcConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link JdbcDatabaseContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class JdbcContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<JdbcServiceConnection, JdbcConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
class JdbcContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<JdbcConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
|
||||
@Override
|
||||
protected JdbcConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<JdbcServiceConnection, JdbcConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
ContainerConnectionSource<JdbcConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
return new JdbcContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class JdbcContainerConnectionDetailsFactory extends
|
||||
private final JdbcDatabaseContainer<?> container;
|
||||
|
||||
private JdbcContainerConnectionDetails(
|
||||
ContainerConnectionSource<JdbcServiceConnection, JdbcConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
ContainerConnectionSource<JdbcConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.jdbc;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a JDBC database service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.1.0
|
||||
* @see JdbcConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(JdbcConnectionDetails.class)
|
||||
public @interface JdbcServiceConnection {
|
||||
|
||||
}
|
||||
@@ -24,22 +24,22 @@ import org.testcontainers.containers.KafkaContainer;
|
||||
import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link KafkaServiceConnection @KafkaServiceConnection}-annotated {@link KafkaContainer}
|
||||
* fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link KafkaConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link KafkaContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class KafkaContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<KafkaServiceConnection, KafkaConnectionDetails, KafkaContainer> {
|
||||
extends ContainerConnectionDetailsFactory<KafkaConnectionDetails, KafkaContainer> {
|
||||
|
||||
@Override
|
||||
protected KafkaConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<KafkaServiceConnection, KafkaConnectionDetails, KafkaContainer> source) {
|
||||
ContainerConnectionSource<KafkaConnectionDetails, KafkaContainer> source) {
|
||||
return new KafkaContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class KafkaContainerConnectionDetailsFactory
|
||||
private final KafkaContainer container;
|
||||
|
||||
private KafkaContainerConnectionDetails(
|
||||
ContainerConnectionSource<KafkaServiceConnection, KafkaConnectionDetails, KafkaContainer> source) {
|
||||
ContainerConnectionSource<KafkaConnectionDetails, KafkaContainer> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.kafka;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a Kafka service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.1.0
|
||||
* @see KafkaConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(KafkaConnectionDetails.class)
|
||||
public @interface KafkaServiceConnection {
|
||||
|
||||
}
|
||||
@@ -24,18 +24,18 @@ import org.springframework.boot.testcontainers.service.connection.ContainerConne
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link ServiceConnection @ServiceConnection}-annotated {@link JdbcDatabaseContainer}
|
||||
* fields that should produce {@link LiquibaseConnectionDetails}.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link LiquibaseConnectionDetails}
|
||||
* from a {@link ServiceConnection @ServiceConnection}-annotated
|
||||
* {@link JdbcDatabaseContainer}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class LiquibaseContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<ServiceConnection, LiquibaseConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
class LiquibaseContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<LiquibaseConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
|
||||
@Override
|
||||
protected LiquibaseConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<ServiceConnection, LiquibaseConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
ContainerConnectionSource<LiquibaseConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
return new LiquibaseContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class LiquibaseContainerConnectionDetailsFactory extends
|
||||
private final JdbcDatabaseContainer<?> container;
|
||||
|
||||
private LiquibaseContainerConnectionDetails(
|
||||
ContainerConnectionSource<ServiceConnection, LiquibaseConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
ContainerConnectionSource<LiquibaseConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -22,22 +22,26 @@ import org.testcontainers.containers.MongoDBContainer;
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link MongoServiceConnection @MongoServiceConnection}-annotated
|
||||
* {@link MongoDBContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link MongoDBContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MongoContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<MongoServiceConnection, MongoConnectionDetails, MongoDBContainer> {
|
||||
extends ContainerConnectionDetailsFactory<MongoConnectionDetails, MongoDBContainer> {
|
||||
|
||||
MongoContainerConnectionDetailsFactory() {
|
||||
super(ANY_CONNECTION_NAME, "com.mongodb.ConnectionString");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MongoConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<MongoServiceConnection, MongoConnectionDetails, MongoDBContainer> source) {
|
||||
ContainerConnectionSource<MongoConnectionDetails, MongoDBContainer> source) {
|
||||
return new MongoContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -50,7 +54,7 @@ class MongoContainerConnectionDetailsFactory
|
||||
private final ConnectionString connectionString;
|
||||
|
||||
private MongoContainerConnectionDetails(
|
||||
ContainerConnectionSource<MongoServiceConnection, MongoConnectionDetails, MongoDBContainer> source) {
|
||||
ContainerConnectionSource<MongoConnectionDetails, MongoDBContainer> source) {
|
||||
super(source);
|
||||
this.connectionString = new ConnectionString(source.getContainer().getReplicaSetUrl());
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.mongo;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a Mongo service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.1.0
|
||||
* @see MongoConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(MongoConnectionDetails.class)
|
||||
public @interface MongoServiceConnection {
|
||||
|
||||
}
|
||||
@@ -25,22 +25,26 @@ import org.testcontainers.containers.Neo4jContainer;
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link Neo4jServiceConnection @Neo4jServiceConnection}-annotated {@link Neo4jContainer}
|
||||
* fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link Neo4jConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link Neo4jContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class Neo4jContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<Neo4jServiceConnection, Neo4jConnectionDetails, Neo4jContainer<?>> {
|
||||
extends ContainerConnectionDetailsFactory<Neo4jConnectionDetails, Neo4jContainer<?>> {
|
||||
|
||||
Neo4jContainerConnectionDetailsFactory() {
|
||||
super(ANY_CONNECTION_NAME, "org.neo4j.driver.AuthToken");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Neo4jConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<Neo4jServiceConnection, Neo4jConnectionDetails, Neo4jContainer<?>> source) {
|
||||
ContainerConnectionSource<Neo4jConnectionDetails, Neo4jContainer<?>> source) {
|
||||
return new Neo4jContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -53,7 +57,7 @@ class Neo4jContainerConnectionDetailsFactory
|
||||
private final Neo4jContainer<?> container;
|
||||
|
||||
private Neo4jContainerConnectionDetails(
|
||||
ContainerConnectionSource<Neo4jServiceConnection, Neo4jConnectionDetails, Neo4jContainer<?>> source) {
|
||||
ContainerConnectionSource<Neo4jConnectionDetails, Neo4jContainer<?>> source) {
|
||||
super(source);
|
||||
this.container = source.getContainer();
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.neo4j;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.neo4j.Neo4jConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates a field provides a Neo4j service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.1.0
|
||||
* @see Neo4jConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(Neo4jConnectionDetails.class)
|
||||
public @interface Neo4jServiceConnection {
|
||||
|
||||
}
|
||||
@@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* General support for auto-configuration of service connections in tests.
|
||||
* General support for service connections in tests.
|
||||
*/
|
||||
package org.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
@@ -21,25 +21,28 @@ import org.testcontainers.containers.MariaDBContainer;
|
||||
import org.testcontainers.containers.MariaDBR2DBCDatabaseContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ConnectionDetailsFactory} for
|
||||
* {@link R2dbcServiceConnection @R2dbcServiceConnection}- annotated
|
||||
* {@link MariaDBContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link MariaDBContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MariaDbR2dbcContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<R2dbcServiceConnection, R2dbcConnectionDetails, MariaDBContainer<?>> {
|
||||
extends ContainerConnectionDetailsFactory<R2dbcConnectionDetails, MariaDBContainer<?>> {
|
||||
|
||||
MariaDbR2dbcContainerConnectionDetailsFactory() {
|
||||
super(ANY_CONNECTION_NAME, "io.r2dbc.spi.ConnectionFactoryOptions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<R2dbcServiceConnection, R2dbcConnectionDetails, MariaDBContainer<?>> source) {
|
||||
ContainerConnectionSource<R2dbcConnectionDetails, MariaDBContainer<?>> source) {
|
||||
return new R2dbcDatabaseContainerConnectionDetails(source.getContainer());
|
||||
}
|
||||
|
||||
|
||||
@@ -21,25 +21,28 @@ import org.testcontainers.containers.MSSQLR2DBCDatabaseContainer;
|
||||
import org.testcontainers.containers.MSSQLServerContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ConnectionDetailsFactory} for
|
||||
* {@link R2dbcServiceConnection @R2dbcServiceConnection}- annotated
|
||||
* {@link MSSQLServerContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link MSSQLServerContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class SqlServerR2dbcContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<R2dbcServiceConnection, R2dbcConnectionDetails, MSSQLServerContainer<?>> {
|
||||
class MsSqlServerR2dbcContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<R2dbcConnectionDetails, MSSQLServerContainer<?>> {
|
||||
|
||||
MsSqlServerR2dbcContainerConnectionDetailsFactory() {
|
||||
super(ANY_CONNECTION_NAME, "io.r2dbc.spi.ConnectionFactoryOptions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<R2dbcServiceConnection, R2dbcConnectionDetails, MSSQLServerContainer<?>> source) {
|
||||
ContainerConnectionSource<R2dbcConnectionDetails, MSSQLServerContainer<?>> source) {
|
||||
return new R2dbcDatabaseContainerConnectionDetails(source.getContainer());
|
||||
}
|
||||
|
||||
@@ -21,25 +21,28 @@ import org.testcontainers.containers.MySQLContainer;
|
||||
import org.testcontainers.containers.MySQLR2DBCDatabaseContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ConnectionDetailsFactory} for
|
||||
* {@link R2dbcServiceConnection @R2dbcServiceConnection}- annotated
|
||||
* {@link MySQLContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link MySQLContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class MySqlR2dbcContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<R2dbcServiceConnection, R2dbcConnectionDetails, MySQLContainer<?>> {
|
||||
extends ContainerConnectionDetailsFactory<R2dbcConnectionDetails, MySQLContainer<?>> {
|
||||
|
||||
MySqlR2dbcContainerConnectionDetailsFactory() {
|
||||
super(ANY_CONNECTION_NAME, "io.r2dbc.spi.ConnectionFactoryOptions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<R2dbcServiceConnection, R2dbcConnectionDetails, MySQLContainer<?>> source) {
|
||||
ContainerConnectionSource<R2dbcConnectionDetails, MySQLContainer<?>> source) {
|
||||
return new R2dbcDatabaseContainerConnectionDetails(source.getContainer());
|
||||
}
|
||||
|
||||
|
||||
@@ -21,24 +21,28 @@ import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.containers.PostgreSQLR2DBCDatabaseContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ConnectionDetailsFactory} for {@link R2dbcServiceConnection @R2dbcConnection}
|
||||
* annotated {@link PostgreSQLContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link R2dbcConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link PostgreSQLContainer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class PostgresR2dbcContainerConnectionDetailsFactory extends
|
||||
ContainerConnectionDetailsFactory<R2dbcServiceConnection, R2dbcConnectionDetails, PostgreSQLContainer<?>> {
|
||||
class PostgresR2dbcContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<R2dbcConnectionDetails, PostgreSQLContainer<?>> {
|
||||
|
||||
PostgresR2dbcContainerConnectionDetailsFactory() {
|
||||
super(ANY_CONNECTION_NAME, "io.r2dbc.spi.ConnectionFactoryOptions");
|
||||
}
|
||||
|
||||
@Override
|
||||
public R2dbcConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<R2dbcServiceConnection, R2dbcConnectionDetails, PostgreSQLContainer<?>> source) {
|
||||
ContainerConnectionSource<R2dbcConnectionDetails, PostgreSQLContainer<?>> source) {
|
||||
return new R2dbcDatabaseContainerConnectionDetails(source.getContainer());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.r2dbc;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates a field provides a R2DBC database service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.1.0
|
||||
* @see ServiceConnection
|
||||
* @see R2dbcConnectionDetails
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(R2dbcConnectionDetails.class)
|
||||
public @interface R2dbcServiceConnection {
|
||||
|
||||
}
|
||||
@@ -16,27 +16,33 @@
|
||||
|
||||
package org.springframework.boot.testcontainers.service.connection.redis;
|
||||
|
||||
import org.testcontainers.containers.Container;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
|
||||
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* {@link ContainerConnectionDetailsFactory} for
|
||||
* {@link RedisServiceConnection @RedisServiceConnection}-annotated
|
||||
* {@link GenericContainer} fields.
|
||||
* {@link ContainerConnectionDetailsFactory} to create {@link RedisConnectionDetails} from
|
||||
* a {@link ServiceConnection @ServiceConnection}-annotated {@link GenericContainer} using
|
||||
* the {@code "redis"} image.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class RedisContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<RedisServiceConnection, RedisConnectionDetails, GenericContainer<?>> {
|
||||
extends ContainerConnectionDetailsFactory<RedisConnectionDetails, Container<?>> {
|
||||
|
||||
RedisContainerConnectionDetailsFactory() {
|
||||
super("redis");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedisConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<RedisServiceConnection, RedisConnectionDetails, GenericContainer<?>> source) {
|
||||
ContainerConnectionSource<RedisConnectionDetails, Container<?>> source) {
|
||||
return new RedisContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
@@ -49,7 +55,7 @@ class RedisContainerConnectionDetailsFactory
|
||||
private final Standalone standalone;
|
||||
|
||||
private RedisContainerConnectionDetails(
|
||||
ContainerConnectionSource<RedisServiceConnection, RedisConnectionDetails, GenericContainer<?>> source) {
|
||||
ContainerConnectionSource<RedisConnectionDetails, Container<?>> source) {
|
||||
super(source);
|
||||
this.standalone = Standalone.of(source.getContainer().getHost(),
|
||||
source.getContainer().getFirstMappedPort());
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection.redis;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
|
||||
/**
|
||||
* Annotation that indicates that a field provides a Redis service connection.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @since 3.1.0
|
||||
* @see RedisConnectionDetails
|
||||
* @see ServiceConnection
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.TYPE })
|
||||
@ServiceConnection(RedisConnectionDetails.class)
|
||||
public @interface RedisServiceConnection {
|
||||
|
||||
}
|
||||
@@ -8,7 +8,6 @@ org.springframework.boot.testcontainers.service.connection.amqp.RabbitContainerC
|
||||
org.springframework.boot.testcontainers.service.connection.cassandra.CassandraContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.couchbase.CouchbaseContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.flyway.FlywayContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.redis.RedisContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.elasticsearch.ElasticsearchContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.influx.InfluxDbContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.jdbc.JdbcContainerConnectionDetailsFactory,\
|
||||
@@ -17,6 +16,7 @@ org.springframework.boot.testcontainers.service.connection.liquibase.LiquibaseCo
|
||||
org.springframework.boot.testcontainers.service.connection.mongo.MongoContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.neo4j.Neo4jContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.r2dbc.MariaDbR2dbcContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.r2dbc.MsSqlServerR2dbcContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.r2dbc.MySqlR2dbcContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.r2dbc.PostgresR2dbcContainerConnectionDetailsFactory,\
|
||||
org.springframework.boot.testcontainers.service.connection.r2dbc.SqlServerR2dbcContainerConnectionDetailsFactory
|
||||
org.springframework.boot.testcontainers.service.connection.redis.RedisContainerConnectionDetailsFactory
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory;
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ContainerConnectionDetailsFactory}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ContainerConnectionDetailsFactoryTests {
|
||||
|
||||
private String beanNameSuffix;
|
||||
|
||||
private Origin origin;
|
||||
|
||||
private JdbcDatabaseContainer<?> container;
|
||||
|
||||
private MergedAnnotation<ServiceConnection> annotation;
|
||||
|
||||
private ContainerConnectionSource<?, ?> source;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.beanNameSuffix = "MyBean";
|
||||
this.origin = mock(Origin.class);
|
||||
this.container = mock(PostgreSQLContainer.class);
|
||||
this.annotation = MergedAnnotation.of(ServiceConnection.class,
|
||||
Map.of("name", "myname", "type", new Class<?>[0]));
|
||||
this.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, this.container,
|
||||
this.annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getConnectionDetailsWhenTypesMatchAndNoNameRestrictionReturnsDetails() {
|
||||
TestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();
|
||||
ConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);
|
||||
assertThat(connectionDetails).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getConnectionDetailsWhenTypesMatchAndNameRestrictionMatchesReturnsDetails() {
|
||||
TestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory("myname");
|
||||
ConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);
|
||||
assertThat(connectionDetails).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getConnectionDetailsWhenTypesMatchAndNameRestrictionDoesNotMatchReturnsNull() {
|
||||
TestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory("notmyname");
|
||||
ConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);
|
||||
assertThat(connectionDetails).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getConnectionDetailsWhenContainerTypeDoesNotMatchReturnsNull() {
|
||||
ElasticsearchContainer container = mock(ElasticsearchContainer.class);
|
||||
ContainerConnectionSource<?, ?> source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin,
|
||||
container, this.annotation);
|
||||
TestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();
|
||||
ConnectionDetails connectionDetails = getConnectionDetails(factory, source);
|
||||
assertThat(connectionDetails).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getConnectionDetailsHasOrigin() {
|
||||
TestContainerConnectionDetailsFactory factory = new TestContainerConnectionDetailsFactory();
|
||||
ConnectionDetails connectionDetails = getConnectionDetails(factory, this.source);
|
||||
assertThat(Origin.from(connectionDetails)).isSameAs(this.origin);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private ConnectionDetails getConnectionDetails(ConnectionDetailsFactory<?, ?> factory,
|
||||
ContainerConnectionSource<?, ?> source) {
|
||||
return ((ConnectionDetailsFactory) factory).getConnectionDetails(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link ContainerConnectionDetailsFactory}.
|
||||
*/
|
||||
static class TestContainerConnectionDetailsFactory
|
||||
extends ContainerConnectionDetailsFactory<JdbcConnectionDetails, JdbcDatabaseContainer<?>> {
|
||||
|
||||
TestContainerConnectionDetailsFactory() {
|
||||
this(ANY_CONNECTION_NAME);
|
||||
}
|
||||
|
||||
TestContainerConnectionDetailsFactory(String connectionName) {
|
||||
super(connectionName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JdbcConnectionDetails getContainerConnectionDetails(
|
||||
ContainerConnectionSource<JdbcConnectionDetails, JdbcDatabaseContainer<?>> source) {
|
||||
return new TestContainerConnectionDetails(source);
|
||||
}
|
||||
|
||||
static class TestContainerConnectionDetails extends ContainerConnectionDetails
|
||||
implements JdbcConnectionDetails {
|
||||
|
||||
TestContainerConnectionDetails(ContainerConnectionSource<?, ?> source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return "user";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return "secret";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJdbcUrl() {
|
||||
return "jdbc:example";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link ContainerConnectionSource}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ContainerConnectionSourceTests {
|
||||
|
||||
private String beanNameSuffix;
|
||||
|
||||
private Origin origin;
|
||||
|
||||
private JdbcDatabaseContainer<?> container;
|
||||
|
||||
private MergedAnnotation<ServiceConnection> annotation;
|
||||
|
||||
private ContainerConnectionSource<?, ?> source;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.beanNameSuffix = "MyBean";
|
||||
this.origin = mock(Origin.class);
|
||||
this.container = mock(PostgreSQLContainer.class);
|
||||
given(this.container.getDockerImageName()).willReturn("postgres");
|
||||
this.annotation = MergedAnnotation.of(ServiceConnection.class, Map.of("name", "", "type", new Class<?>[0]));
|
||||
this.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, this.container,
|
||||
this.annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenContainerIsNotInstanceOfContainerTypeReturnsFalse() {
|
||||
String connectionName = null;
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = ElasticsearchContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenContainerIsInstanceOfContainerTypeReturnsTrue() {
|
||||
String connectionName = null;
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionNameDoesNotMatchNameTakenFromAnnotationReturnsFalse() {
|
||||
setupSourceAnnotatedWithName("myname");
|
||||
String connectionName = "othername";
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionNameDoesNotMatchNameTakenFromContainerReturnsFalse() {
|
||||
String connectionName = "othername";
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionNameIsUnrestrictedReturnsTrue() {
|
||||
String connectionName = null;
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionNameMatchesNameTakenFromAnnotationReturnsTrue() {
|
||||
setupSourceAnnotatedWithName("myname");
|
||||
String connectionName = "myname";
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionNameMatchesNameTakenFromContainerReturnsTrue() {
|
||||
String connectionName = "postgres";
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionDetailsTypeNotInAnnotationRestrictionReturnsFalse() {
|
||||
setupSourceAnnotatedWithType(ElasticsearchConnectionDetails.class);
|
||||
String connectionName = null;
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionDetailsTypeInAnnotationRestrictionReturnsTrue() {
|
||||
setupSourceAnnotatedWithType(JdbcConnectionDetails.class);
|
||||
String connectionName = null;
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsWhenConnectionDetailsTypeIsNotRestrictedReturnsTrue() {
|
||||
String connectionName = null;
|
||||
Class<?> connectionDetailsType = JdbcConnectionDetails.class;
|
||||
Class<?> containerType = JdbcDatabaseContainer.class;
|
||||
assertThat(this.source.accepts(connectionName, connectionDetailsType, containerType)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBeanNameSuffixReturnsBeanNameSuffix() {
|
||||
assertThat(this.source.getBeanNameSuffix()).isEqualTo(this.beanNameSuffix);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getOriginReturnsOrigin() {
|
||||
assertThat(this.source.getOrigin()).isEqualTo(this.origin);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getContainerReturnsContainer() {
|
||||
assertThat(this.source.getContainer()).isSameAs(this.container);
|
||||
}
|
||||
|
||||
@Test
|
||||
void toStringReturnsSensibleString() {
|
||||
assertThat(this.source.toString()).startsWith("@ServiceConnection source for Mock for Origin");
|
||||
}
|
||||
|
||||
private void setupSourceAnnotatedWithName(String name) {
|
||||
this.annotation = MergedAnnotation.of(ServiceConnection.class, Map.of("name", name, "type", new Class<?>[0]));
|
||||
this.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, this.container,
|
||||
this.annotation);
|
||||
}
|
||||
|
||||
private void setupSourceAnnotatedWithType(Class<?> type) {
|
||||
this.annotation = MergedAnnotation.of(ServiceConnection.class,
|
||||
Map.of("name", "", "type", new Class<?>[] { type }));
|
||||
this.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, this.container,
|
||||
this.annotation);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link FieldOrigin}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class FieldOriginTests {
|
||||
|
||||
@Test
|
||||
void createWhenFieldIsNullThrowsException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new FieldOrigin(null))
|
||||
.withMessage("Field must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void equalsAndHashCode() {
|
||||
Origin o1 = new FieldOrigin(ReflectionUtils.findField(Fields.class, "one"));
|
||||
Origin o2 = new FieldOrigin(ReflectionUtils.findField(Fields.class, "one"));
|
||||
Origin o3 = new FieldOrigin(ReflectionUtils.findField(Fields.class, "two"));
|
||||
assertThat(o1).isEqualTo(o1).isEqualTo(o2).isNotEqualTo(o3);
|
||||
assertThat(o1.hashCode()).isEqualTo(o2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
void toStringReturnsSensibleString() {
|
||||
Origin origin = new FieldOrigin(ReflectionUtils.findField(Fields.class, "one"));
|
||||
assertThat(origin).hasToString("FieldOriginTests.Fields.one");
|
||||
}
|
||||
|
||||
static class Fields {
|
||||
|
||||
String one;
|
||||
|
||||
String two;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,32 +16,35 @@
|
||||
|
||||
package org.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.Container;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactoryTests.ServiceConnections.NestedClass;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServiceConnectionContextCustomizerFactory}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class ServiceConnectionContextCustomizerFactoryTests {
|
||||
class ServiceConnectionContextCustomizerFactoryTests {
|
||||
|
||||
private final ServiceConnectionContextCustomizerFactory factory = new ServiceConnectionContextCustomizerFactory();
|
||||
|
||||
@Test
|
||||
void whenClassHasNoServiceConnectionsThenCreateReturnsNull() {
|
||||
void createContextCustomizerWhenNoServiceConnectionsReturnsNull() {
|
||||
assertThat(this.factory.createContextCustomizer(NoServiceConnections.class, null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenClassHasServiceConnectionsThenCreateReturnsCustomizer() {
|
||||
void createContextCustomizerWhenClassHasServiceConnectionsReturnsCustomizer() {
|
||||
ServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory
|
||||
.createContextCustomizer(ServiceConnections.class, null);
|
||||
assertThat(customizer).isNotNull();
|
||||
@@ -49,37 +52,79 @@ public class ServiceConnectionContextCustomizerFactoryTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenEnclosingClassHasServiceConnectionsThenCreateReturnsCustomizer() {
|
||||
void createContextCustomizerWhenEnclosingClassHasServiceConnectionsReturnsCustomizer() {
|
||||
ServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory
|
||||
.createContextCustomizer(NestedClass.class, null);
|
||||
.createContextCustomizer(ServiceConnections.NestedClass.class, null);
|
||||
assertThat(customizer).isNotNull();
|
||||
assertThat(customizer.getSources()).hasSize(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenClassHasNonStaticServiceConnectionThenCreateShouldFailWithHelpfulIllegalStateException() {
|
||||
void createContextCustomizerWhenClassHasNonStaticServiceConnectionFailsWithHepfulException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.factory.createContextCustomizer(NonStaticServiceConnection.class, null))
|
||||
.withMessage("@ServiceConnection field 'service' must be static");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void createContextCustomizerWhenClassHasAnnotationOnNonConnectionFieldFailsWithHepfulException() {
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.factory.createContextCustomizer(ServiceConnectionOnWrongFieldType.class, null))
|
||||
.withMessage("Field 'service2' in " + ServiceConnectionOnWrongFieldType.class.getName()
|
||||
+ " must be a org.testcontainers.containers.Container");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createContextCustomizerCreatesCustomizerSourceWithSensibleBeanNameSuffix() {
|
||||
ServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory
|
||||
.createContextCustomizer(SingleServiceConnection.class, null);
|
||||
ContainerConnectionSource<?, ?> source = customizer.getSources().get(0);
|
||||
assertThat(source.getBeanNameSuffix()).isEqualTo("SingleServiceConnectionService1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createContextCustomizerCreatesCustomizerSourceWithSensibleOrigin() {
|
||||
ServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory
|
||||
.createContextCustomizer(SingleServiceConnection.class, null);
|
||||
ContainerConnectionSource<?, ?> source = customizer.getSources().get(0);
|
||||
assertThat(source.getOrigin())
|
||||
.hasToString("ServiceConnectionContextCustomizerFactoryTests.SingleServiceConnection.service1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void createContextCustomizerCreatesCustomizerSourceWithSensibleToString() {
|
||||
ServiceConnectionContextCustomizer customizer = (ServiceConnectionContextCustomizer) this.factory
|
||||
.createContextCustomizer(SingleServiceConnection.class, null);
|
||||
ContainerConnectionSource<?, ?> source = customizer.getSources().get(0);
|
||||
assertThat(source).hasToString(
|
||||
"@ServiceConnection source for ServiceConnectionContextCustomizerFactoryTests.SingleServiceConnection.service1");
|
||||
}
|
||||
|
||||
static class NoServiceConnections {
|
||||
|
||||
}
|
||||
|
||||
static class SingleServiceConnection {
|
||||
|
||||
@ServiceConnection
|
||||
private static GenericContainer<?> service1 = new MockContainer();
|
||||
|
||||
}
|
||||
|
||||
static class ServiceConnections {
|
||||
|
||||
@ServiceConnection(TestConnectionDetails.class)
|
||||
private static GenericContainer<?> service1 = new GenericContainer<>("example");
|
||||
@ServiceConnection
|
||||
private static Container<?> service1 = new MockContainer();
|
||||
|
||||
@ServiceConnection(TestConnectionDetails.class)
|
||||
private static GenericContainer<?> service2 = new GenericContainer<>("example");
|
||||
@ServiceConnection
|
||||
private static Container<?> service2 = new MockContainer();
|
||||
|
||||
@Nested
|
||||
class NestedClass {
|
||||
|
||||
@ServiceConnection(TestConnectionDetails.class)
|
||||
private static GenericContainer<?> service3 = new GenericContainer<>("example");
|
||||
@ServiceConnection
|
||||
private static Container<?> service3 = new MockContainer();
|
||||
|
||||
}
|
||||
|
||||
@@ -87,12 +132,35 @@ public class ServiceConnectionContextCustomizerFactoryTests {
|
||||
|
||||
static class NonStaticServiceConnection {
|
||||
|
||||
@ServiceConnection(TestConnectionDetails.class)
|
||||
private GenericContainer<?> service = new GenericContainer<>("example");
|
||||
@ServiceConnection
|
||||
private Container<?> service = new MockContainer("example");
|
||||
|
||||
}
|
||||
|
||||
static class TestConnectionDetails implements ConnectionDetails {
|
||||
static class ServiceConnectionOnWrongFieldType {
|
||||
|
||||
@ServiceConnection
|
||||
private static InputStream service2 = new ByteArrayInputStream(new byte[0]);
|
||||
|
||||
}
|
||||
|
||||
static class MockContainer extends GenericContainer<MockContainer> {
|
||||
|
||||
private final String dockerImageName;
|
||||
|
||||
MockContainer() {
|
||||
this("example");
|
||||
}
|
||||
|
||||
MockContainer(String dockerImageName) {
|
||||
super(dockerImageName);
|
||||
this.dockerImageName = dockerImageName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDockerImageName() {
|
||||
return this.dockerImageName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.springframework.boot.testcontainers.service.connection;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
|
||||
import org.springframework.boot.origin.Origin;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
/**
|
||||
* Tests for {@link ServiceConnectionContextCustomizer}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ServiceConnectionContextCustomizerTests {
|
||||
|
||||
private String beanNameSuffix;
|
||||
|
||||
private Origin origin;
|
||||
|
||||
private JdbcDatabaseContainer<?> container;
|
||||
|
||||
private MergedAnnotation<ServiceConnection> annotation;
|
||||
|
||||
private ContainerConnectionSource<?, ?> source;
|
||||
|
||||
private ConnectionDetailsFactories factories;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.beanNameSuffix = "MyBean";
|
||||
this.origin = mock(Origin.class);
|
||||
this.container = mock(PostgreSQLContainer.class);
|
||||
this.annotation = MergedAnnotation.of(ServiceConnection.class,
|
||||
Map.of("name", "myname", "type", new Class<?>[0]));
|
||||
this.source = new ContainerConnectionSource<>(this.beanNameSuffix, this.origin, this.container,
|
||||
this.annotation);
|
||||
this.factories = mock(ConnectionDetailsFactories.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeContextRegistersServiceConnections() {
|
||||
ServiceConnectionContextCustomizer customizer = new ServiceConnectionContextCustomizer(List.of(this.source),
|
||||
this.factories);
|
||||
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
|
||||
DefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());
|
||||
given(context.getBeanFactory()).willReturn(beanFactory);
|
||||
MergedContextConfiguration mergedConfig = mock(MergedContextConfiguration.class);
|
||||
JdbcConnectionDetails connectionDetails = new TestJdbcConnectionDetails();
|
||||
given(this.factories.getConnectionDetails(this.source))
|
||||
.willReturn(Map.of(JdbcConnectionDetails.class, connectionDetails));
|
||||
customizer.customizeContext(context, mergedConfig);
|
||||
ArgumentCaptor<BeanDefinition> beanDefinitionCaptor = ArgumentCaptor.forClass(BeanDefinition.class);
|
||||
then(beanFactory).should()
|
||||
.registerBeanDefinition(eq("testJdbcConnectionDetailsForMyBean"), beanDefinitionCaptor.capture());
|
||||
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionCaptor.getValue();
|
||||
assertThat(beanDefinition.getInstanceSupplier().get()).isSameAs(connectionDetails);
|
||||
assertThat(beanDefinition.getBeanClass()).isEqualTo(TestJdbcConnectionDetails.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeContextWhenFactoriesHasNoConnectionDetailsThrowsException() {
|
||||
ServiceConnectionContextCustomizer customizer = new ServiceConnectionContextCustomizer(List.of(this.source),
|
||||
this.factories);
|
||||
ConfigurableApplicationContext context = mock(ConfigurableApplicationContext.class);
|
||||
DefaultListableBeanFactory beanFactory = spy(new DefaultListableBeanFactory());
|
||||
given(context.getBeanFactory()).willReturn(beanFactory);
|
||||
MergedContextConfiguration mergedConfig = mock(MergedContextConfiguration.class);
|
||||
assertThatIllegalStateException().isThrownBy(() -> customizer.customizeContext(context, mergedConfig))
|
||||
.withMessageStartingWith("No connection details created for @ServiceConnection source");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test {@link JdbcConnectionDetails}.
|
||||
*/
|
||||
static class TestJdbcConnectionDetails implements JdbcConnectionDetails {
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJdbcUrl() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,6 @@ import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.RabbitMQContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.amqp.rabbit.annotation.Queue;
|
||||
import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
||||
@@ -34,6 +33,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.amqp.RabbitConnectionDetails;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
@@ -41,7 +42,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link RabbitServiceConnection}.
|
||||
* Tests for {@link RabbitContainerConnectionDetailsFactory}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
@@ -49,11 +50,12 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class RabbitServiceConnectionTests {
|
||||
class RabbitContainerConnectionDetailsFactoryIntegrationTests {
|
||||
|
||||
@Container
|
||||
@RabbitServiceConnection
|
||||
static final RabbitMQContainer rabbit = new RabbitMQContainer(DockerImageName.parse("rabbitmq:3.11-alpine"));
|
||||
@ServiceConnection
|
||||
static final RabbitMQContainer rabbit = new RabbitMQContainer(DockerImageNames.rabbit())
|
||||
.withStartupTimeout(Duration.ofMinutes(4));
|
||||
|
||||
@Autowired(required = false)
|
||||
private RabbitConnectionDetails connectionDetails;
|
||||
@@ -21,18 +21,19 @@ import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.InfluxDBContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link InfluxDbServiceConnection}.
|
||||
* Tests for {@link InfluxDbContainerConnectionDetailsFactory}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
@@ -40,21 +41,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
@SpringJUnitConfig
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
class InfluxDbServiceConnectionTests {
|
||||
|
||||
private static final String INFLUXDB_VERSION = "2.6.1";
|
||||
class InfluxDbContainerConnectionDetailsFactoryIntegrationTests {
|
||||
|
||||
@Container
|
||||
@InfluxDbServiceConnection
|
||||
static final InfluxDBContainer<?> influxDbService = new InfluxDBContainer<>(
|
||||
DockerImageName.parse("influxdb").withTag(INFLUXDB_VERSION));
|
||||
@ServiceConnection
|
||||
static final InfluxDBContainer<?> influxDbService = new InfluxDBContainer<>(DockerImageNames.influxDb());
|
||||
|
||||
@Autowired
|
||||
private InfluxDB influxDb;
|
||||
|
||||
@Test
|
||||
void connectionCanBeMadeToInfluxDbContainer() {
|
||||
assertThat(this.influxDb.version()).isEqualTo("v" + INFLUXDB_VERSION);
|
||||
assertThat(this.influxDb.version()).isEqualTo("v" + DockerImageNames.influxDb().getVersionPart());
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -25,11 +25,12 @@ import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.KafkaContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.kafka.annotation.KafkaListener;
|
||||
@@ -40,7 +41,7 @@ import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link KafkaServiceConnection}.
|
||||
* Tests for {@link KafkaContainerConnectionDetailsFactory}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
* @author Andy Wilkinson
|
||||
@@ -50,11 +51,11 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@TestPropertySource(properties = { "spring.kafka.consumer.group-id=test-group",
|
||||
"spring.kafka.consumer.auto-offset-reset=earliest" })
|
||||
class KafkaServiceConnectionTests {
|
||||
class KafkaContainerConnectionDetailsFactoryIntegrationTests {
|
||||
|
||||
@Container
|
||||
@KafkaServiceConnection
|
||||
static final KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:5.4.3"));
|
||||
@ServiceConnection
|
||||
static final KafkaContainer kafka = new KafkaContainer(DockerImageNames.kafka());
|
||||
|
||||
@Autowired
|
||||
private KafkaTemplate<String, String> kafkaTemplate;
|
||||
Reference in New Issue
Block a user