Skip to content

Commit a515cc6

Browse files
committed
Add named container lookup to support multiple containers of the same type
Adds a name attribute to @TestContainer so that containers can be registered and looked up by name, allowing multiple containers of the same type to coexist in a single test class. Part of #117 Signed-off-by: Radoslav Husar <rhusar@redhat.com> Signed-off-by: Radoslav Husar <radosoft@gmail.com>
1 parent 75f03a2 commit a515cc6

5 files changed

Lines changed: 117 additions & 4 deletions

File tree

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@
5757
<organization>Red Hat, Inc.</organization>
5858
<organizationUrl>https://redhat.com</organizationUrl>
5959
</developer>
60+
<developer>
61+
<id>rhusar</id>
62+
<name>Radoslav Husar</name>
63+
<email>rhusar@redhat.com</email>
64+
<organization>Red Hat, Inc.</organization>
65+
<organizationUrl>https://redhat.com</organizationUrl>
66+
</developer>
6067
</developers>
6168

6269
<scm>

src/main/java/org/arquillian/testcontainers/TestcontainerDescription.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ class TestcontainerDescription {
1919
* The annotation that was on the field
2020
*/
2121
final Testcontainer testcontainer;
22+
23+
/**
24+
* The name of the container, or an empty string for unnamed containers
25+
*/
26+
final String name;
27+
2228
/**
2329
* The instance of the container created
2430
*/
2531
final GenericContainer<?> instance;
2632

2733
TestcontainerDescription(final Testcontainer testcontainer, final GenericContainer<?> instance) {
2834
this.testcontainer = testcontainer;
35+
this.name = testcontainer.name();
2936
this.instance = instance;
3037
}
3138
}

src/main/java/org/arquillian/testcontainers/TestcontainerRegistry.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,45 @@ class TestcontainerRegistry implements Iterable<TestcontainerDescription> {
3737
*/
3838
GenericContainer<?> lookupOrCreate(final Class<GenericContainer<?>> type, final Testcontainer testcontainer,
3939
final List<Annotation> qualifiers) {
40-
GenericContainer<?> result = lookup(type, qualifiers);
40+
final String name = testcontainer.name();
41+
GenericContainer<?> result = name.isEmpty() ? lookup(type, qualifiers) : lookup(name);
4142
if (result == null) {
4243
try {
4344
final Constructor<? extends GenericContainer<?>> constructor = getConstructor(type, testcontainer);
4445
result = constructor.newInstance();
45-
this.containers.add(new TestcontainerDescription(testcontainer, result));
46+
final TestcontainerDescription description = new TestcontainerDescription(testcontainer, result);
47+
if (!name.isEmpty()) {
48+
for (TestcontainerDescription containerDesc : this.containers) {
49+
if (name.equals(containerDesc.name)) {
50+
throw new IllegalArgumentException(
51+
String.format("A container with name \"%s\" is already registered", name));
52+
}
53+
}
54+
}
55+
this.containers.add(description);
4656
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
4757
throw new IllegalArgumentException(String.format("Could create container %s", type.getName()), e);
4858
}
4959
}
5060
return result;
5161
}
5262

63+
/**
64+
* Lookup a container by name.
65+
*
66+
* @param name the container name
67+
*
68+
* @return the container instance or {@code null} if not found
69+
*/
70+
GenericContainer<?> lookup(final String name) {
71+
for (TestcontainerDescription containerDesc : this.containers) {
72+
if (name.equals(containerDesc.name)) {
73+
return containerDesc.instance;
74+
}
75+
}
76+
return null;
77+
}
78+
5379
/**
5480
* Lookup the container in the test container instances. If more than one container is found for the type or
5581
* qualifier, an {@link IllegalArgumentException} is thrown.
@@ -63,14 +89,14 @@ GenericContainer<?> lookup(final Class<?> type, final List<Annotation> qualifier
6389
final List<TestcontainerDescription> foundContainers = new ArrayList<>();
6490
if (qualifiers.isEmpty()) {
6591
for (TestcontainerDescription containerDesc : this.containers) {
66-
if (type.isAssignableFrom(containerDesc.instance.getClass())) {
92+
if (containerDesc.name.isEmpty() && type.isAssignableFrom(containerDesc.instance.getClass())) {
6793
foundContainers.add(containerDesc);
6894
}
6995
}
7096
} else {
7197
for (TestcontainerDescription containerDesc : this.containers) {
7298
for (Annotation qualifier : qualifiers) {
73-
if (type.isAssignableFrom(containerDesc.instance.getClass())
99+
if (containerDesc.name.isEmpty() && type.isAssignableFrom(containerDesc.instance.getClass())
74100
&& type.isAnnotationPresent(qualifier.annotationType())) {
75101
foundContainers.add(containerDesc);
76102
}

src/main/java/org/arquillian/testcontainers/api/Testcontainer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@
5555
*/
5656
boolean value() default true;
5757

58+
/**
59+
* An optional name for the container. When set, the container is registered and looked up by this name, allowing
60+
* multiple containers of the same type to coexist in a single test class.
61+
* <p>
62+
* If left as the default empty string, the container is looked up by type and qualifiers as usual.
63+
* </p>
64+
*
65+
* @return the name of the container, or an empty string for unnamed containers
66+
*/
67+
String name() default "";
68+
5869
/**
5970
* The type used to create the value for the field. The type must have a no-arg constructor.
6071
* <p>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright The Arquillian Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.arquillian.testcontainers;
7+
8+
import org.arquillian.testcontainers.api.Testcontainer;
9+
import org.arquillian.testcontainers.api.TestcontainersRequired;
10+
import org.arquillian.testcontainers.common.SimpleTestContainer;
11+
import org.jboss.arquillian.container.test.api.Deployment;
12+
import org.jboss.arquillian.container.test.api.RunAsClient;
13+
import org.jboss.arquillian.junit5.ArquillianExtension;
14+
import org.jboss.shrinkwrap.api.ShrinkWrap;
15+
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
16+
import org.jboss.shrinkwrap.api.spec.JavaArchive;
17+
import org.junit.jupiter.api.Assertions;
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.extension.ExtendWith;
20+
import org.opentest4j.TestAbortedException;
21+
22+
@ExtendWith(ArquillianExtension.class)
23+
@TestcontainersRequired(TestAbortedException.class)
24+
@RunAsClient
25+
public class NamedContainerTest {
26+
27+
@Deployment
28+
public static JavaArchive createDeployment() {
29+
return ShrinkWrap.create(JavaArchive.class)
30+
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
31+
}
32+
33+
@Testcontainer(name = "first")
34+
private SimpleTestContainer first;
35+
36+
@Testcontainer(name = "second")
37+
private SimpleTestContainer second;
38+
39+
@Testcontainer
40+
private SimpleTestContainer unnamed;
41+
42+
@Test
43+
public void checkAllInjected() {
44+
Assertions.assertNotNull(first, "Expected the first container to be injected.");
45+
Assertions.assertNotNull(second, "Expected the second container to be injected.");
46+
Assertions.assertNotNull(unnamed, "Expected the unnamed container to be injected.");
47+
}
48+
49+
@Test
50+
public void checkAllRunning() {
51+
Assertions.assertTrue(first.isRunning(), "Expected the first container to be running.");
52+
Assertions.assertTrue(second.isRunning(), "Expected the second container to be running.");
53+
Assertions.assertTrue(unnamed.isRunning(), "Expected the unnamed container to be running.");
54+
}
55+
56+
@Test
57+
public void checkAllDifferentInstances() {
58+
Assertions.assertNotSame(first, second, "Expected named containers to be different instances.");
59+
Assertions.assertNotSame(first, unnamed, "Expected named and unnamed containers to be different instances.");
60+
Assertions.assertNotSame(second, unnamed, "Expected named and unnamed containers to be different instances.");
61+
}
62+
}

0 commit comments

Comments
 (0)