Browse Source

Support Testcontainer Redis with custom image names

Update `RedisContainerConnectionDetailsFactory` so that it can also
support `RedisContainer` with a custom name.

Closes gh-41450
pull/42067/head
Phillip Webb 1 year ago
parent
commit
fa686bb593
  1. 53
      spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/redis/CustomRedisContainerConnectionDetailsFactoryTests.java
  2. 29
      spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java
  3. 12
      spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionSource.java
  4. 10
      spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/redis/RedisContainerConnectionDetailsFactory.java
  5. 43
      spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/TestContainerConnectionSource.java

53
spring-boot-project/spring-boot-testcontainers/src/dockerTest/java/org/springframework/boot/testcontainers/service/connection/redis/CustomRedisContainerConnectionDetailsFactoryTests.java

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
/*
* Copyright 2012-2024 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.util.Map;
import com.redis.testcontainers.RedisContainer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories;
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testcontainers.service.connection.TestContainerConnectionSource;
import org.springframework.core.annotation.MergedAnnotation;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link RedisContainerConnectionDetailsFactory} when using a custom contain
* without "redis" as the name.
*
* @author Phillip Webb
*/
class CustomRedisContainerConnectionDetailsFactoryTests {
@Test
void getConnectionDetailsWhenRedisContainerWithCustomName() {
ConnectionDetailsFactories factories = new ConnectionDetailsFactories();
MergedAnnotation<ServiceConnection> annotation = MergedAnnotation.of(ServiceConnection.class,
Map.of("value", ""));
ContainerConnectionSource<RedisContainer> source = TestContainerConnectionSource.create("test", null,
RedisContainer.class, "mycustomimage", annotation, null);
Map<Class<?>, ConnectionDetails> connectionDetails = factories.getConnectionDetails(source, true);
assertThat(connectionDetails.get(RedisConnectionDetails.class)).isNotNull();
}
}

29
spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionDetailsFactory.java

@ -104,12 +104,10 @@ public abstract class ContainerConnectionDetailsFactory<C extends Container<?>, @@ -104,12 +104,10 @@ public abstract class ContainerConnectionDetailsFactory<C extends Container<?>,
}
try {
Class<?>[] generics = resolveGenerics();
Class<?> containerType = generics[0];
Class<?> connectionDetailsType = generics[1];
for (String connectionName : this.connectionNames) {
if (source.accepts(connectionName, containerType, connectionDetailsType)) {
return getContainerConnectionDetails(source);
}
Class<?> requiredContainerType = generics[0];
Class<?> requiredConnectionDetailsType = generics[1];
if (sourceAccepts(source, requiredContainerType, requiredConnectionDetailsType)) {
return getContainerConnectionDetails(source);
}
}
catch (NoClassDefFoundError ex) {
@ -118,6 +116,25 @@ public abstract class ContainerConnectionDetailsFactory<C extends Container<?>, @@ -118,6 +116,25 @@ public abstract class ContainerConnectionDetailsFactory<C extends Container<?>,
return null;
}
/**
* Return if the give source accepts the connection. By default this method checks
* each connection name.
* @param source the container connection source
* @param requiredContainerType the required container type
* @param requiredConnectionDetailsType the required connection details type
* @return if the source accepts the connection
* @since 3.4.0
*/
protected boolean sourceAccepts(ContainerConnectionSource<C> source, Class<?> requiredContainerType,
Class<?> requiredConnectionDetailsType) {
for (String requiredConnectionName : this.connectionNames) {
if (source.accepts(requiredConnectionName, requiredContainerType, requiredConnectionDetailsType)) {
return true;
}
}
return false;
}
private boolean hasRequiredClasses() {
return ObjectUtils.isEmpty(this.requiredClassNames) || Arrays.stream(this.requiredClassNames)
.allMatch((requiredClassName) -> ClassUtils.isPresent(requiredClassName, null));

12
spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/ContainerConnectionSource.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2024 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.
@ -90,7 +90,15 @@ public final class ContainerConnectionSource<C extends Container<?>> implements @@ -90,7 +90,15 @@ public final class ContainerConnectionSource<C extends Container<?>> implements
return null;
}
boolean accepts(String requiredConnectionName, Class<?> requiredContainerType,
/**
* Return is this source accepts the given connection.
* @param requiredConnectionName the required connection name or {@code null}
* @param requiredContainerType the required container type
* @param requiredConnectionDetailsType the required connection details type
* @return if the connection is accepted by this source
* @since 3.4.0
*/
public boolean accepts(String requiredConnectionName, Class<?> requiredContainerType,
Class<?> requiredConnectionDetailsType) {
if (StringUtils.hasText(requiredConnectionName)
&& !requiredConnectionName.equalsIgnoreCase(this.connectionName)) {

10
spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/redis/RedisContainerConnectionDetailsFactory.java

@ -18,6 +18,7 @@ package org.springframework.boot.testcontainers.service.connection.redis; @@ -18,6 +18,7 @@ package org.springframework.boot.testcontainers.service.connection.redis;
import java.util.List;
import com.redis.testcontainers.RedisContainer;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
@ -49,7 +50,14 @@ class RedisContainerConnectionDetailsFactory @@ -49,7 +50,14 @@ class RedisContainerConnectionDetailsFactory
}
@Override
public RedisConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
protected boolean sourceAccepts(ContainerConnectionSource<Container<?>> source, Class<?> requiredContainerType,
Class<?> requiredConnectionDetailsType) {
return super.sourceAccepts(source, requiredContainerType, requiredConnectionDetailsType)
|| source.accepts(ANY_CONNECTION_NAME, RedisContainer.class, requiredConnectionDetailsType);
}
@Override
protected RedisConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<Container<?>> source) {
return new RedisContainerConnectionDetails(source);
}

43
spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/TestContainerConnectionSource.java

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
/*
* Copyright 2012-2024 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.function.Supplier;
import org.testcontainers.containers.Container;
import org.springframework.boot.origin.Origin;
import org.springframework.core.annotation.MergedAnnotation;
/**
* Factory for tests to create a {@link ContainerConnectionSource}.
*
* @author Phillip Webb
*/
public final class TestContainerConnectionSource {
private TestContainerConnectionSource() {
}
public static <C extends Container<?>> ContainerConnectionSource<C> create(String beanNameSuffix, Origin origin,
Class<C> containerType, String containerImageName, MergedAnnotation<ServiceConnection> annotation,
Supplier<C> containerSupplier) {
return new ContainerConnectionSource<>(beanNameSuffix, origin, containerType, containerImageName, annotation,
containerSupplier);
}
}
Loading…
Cancel
Save