I am trying to execute the following containers, but I am finding an error because kafkaConnect is being started befor kafka, when kafka:9092 and when the kafka:9092 url is reached during the kafkaConnect execution no response is obtained since kafka is not running yet.
````
@Container
private final KafkaContainer kafka = new KafkaContainer()
.withNetwork(network)
.withNetworkAliases("kafka");
@Container
private final GenericContainer kafkaConnect = new GenericContainer("confluentinc/cp-kafka-connect:latest")
.withEnv("CONNECT_BOOTSTRAP_SERVERS", "kafka:9092")
.withEnv("CONNECT_REST_PORT", KAFKA_CONNECT_EXPOSED_PORT.toString())
.withEnv("CONNECT_GROUP_ID", "quickstart-avro")
.withEnv("CONNECT_CONFIG_STORAGE_TOPIC", "quickstart-avro-config")
.withEnv("CONNECT_OFFSET_STORAGE_TOPIC", "quickstart-avro-offsets")
.withEnv("CONNECT_STATUS_STORAGE_TOPIC", "quickstart-avro-status")
.withEnv("CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR", "1")
.withEnv("CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR", "1")
.withEnv("CONNECT_STATUS_STORAGE_REPLICATION_FACTOR", "1")
.withEnv("CONNECT_KEY_CONVERTER", "io.confluent.connect.avro.AvroConverter")
.withEnv("CONNECT_VALUE_CONVERTER", "io.confluent.connect.avro.AvroConverter")
.withEnv("CONNECT_KEY_CONVERTER_SCHEMA_REGISTRY_URL", "http://registry:8081/")
.withEnv("CONNECT_VALUE_CONVERTER_SCHEMA_REGISTRY_URL", "http://registry:8081/")
.withEnv("CONNECT_INTERNAL_KEY_CONVERTER", "org.apache.kafka.connect.json.JsonConverter")
.withEnv("CONNECT_INTERNAL_VALUE_CONVERTER", "org.apache.kafka.connect.json.JsonConverter")
.withEnv("CONNECT_LOG4J_ROOT_LOGLEVEL", "INFO")
.withEnv("CONNECT_LOG4J_LOGGERS", "org.reflections=INFO,io.debezium.connector.mysql=INFO,io.debezium.connector.mysql.BinlogReader=INFO,io.debezium.relational.history=INFO")
.withEnv("CONNECT_PLUGIN_PATH", "/usr/share/java,/etc/kafka-connect/jars")
.withClasspathResourceMapping("dbzp/", "/etc/kafka-connect/jars/dbz", BindMode.READ_ONLY)
.withExposedPorts(KAFKA_CONNECT_EXPOSED_PORT)
.withNetwork(network)
// .withStartupTimeout(Duration.of(240, SECONDS))
;
```
I have tried to postponing thekafkaConnectstarting usingstartupTimeout`, but I couldn't because after reading documentation I understood this method just increases the period to check if the container is started.
I have found two temporal workarounds.
@Container of kafkaConect, which allows to @TestContainer annotation to start kafka. Once kafka is running, this forces each test to execute kafkaConect.start(), which is a pain.Question
How can I ensure kafka will be executed before kafkaConnect?
I am using Java 8, JUnit:5.3.2 and Jupiter TestContainer:1.11.1
/cc @kiview @britter
So this is soley an ordering issue? Does Container.start() block until the container is started? In this case we probably only have to fix the ordering inside the extension. /cc @sormuras
@bsideup you might want to introduce a label for JUnit 5 related problems so that they are easier to discover for us.
I don't see this as a specifically JUnit5 related problem. We also don't support this for other test-framework integrations. But I remember a PoC from @bsideup for the general DSL, to support defining a start order.
@kiuby88
For the time being I'd recommend to not use the JUnit5 integration and instead start the containers in your @BeforeEach annotated method in your desired order.
@britter We already have this label, I just used it :wink:
But you are right, in theory we could use an implicit order based on the declaration order. However, I'm not sure if we are guaranteed an ordered result when we access the annotated fields? Probably not.
Hi,
@bsideup , If I understood fine, the problem is related to this line in the extension TestcontainersExtension/65-72 which retrieve the containers to be started by beforeAll. (Similar methods for non static declarations).
@kiview finally, I find a good solution to me. I have declared containers as Spring beans, which allows to manage dependencies between them :-)
I wanted to avoid the before-based hooks because my idea was to decouple the tests configurations in order to create reusable configurations to setup the test environments and put them in a share library. Then, using a spring Configuration I can ensure the order which can be added to any test class.
@kiuby88 if you're okay with hacky-ish solutions, you can override start of KafkaConnect and call kafka.start() in it before calling super.start(), this way Kafka will be started either by JUnit or when KafkaConnect container starts 馃槄
thanks @bsideup
Currently, I am using the following work around.
````
@Configuration
public class MySqlAndKafkaConnectConfig {
@Bean(initMethod = "start", destroyMethod = "stop")
public KafkaContainer kafkaContainer() {
return new KafkaContainer() //some omitted configs
}
@Bean(initMethod = "start", destroyMethod = "stop")
public MySQLContainer mySqlContainer() {
return (MySQLContainer) new MySQLContainer()//...
}
@Bean(initMethod = "start", destroyMethod = "stop")
public GenericContainer kafkaConnectContainer(KafkaContainer kafkaContainer) {
return new GenericContainer("confluentinc/cp-kafka-connect:latest")
.withEnv("CONNECT_BOOTSTRAP_SERVERS", kafkaContainer.getNetworkAliases() + ":9092")//...
}
}
````
This configuration can be imported by any test which requires that stack :-)
I've got some integration test cases that use multiple containers, which are best started in a particular order. Rather than have each container as a separate @Container annotated value I put them in a separate class where I could control the start up order. In effect, a primitive Docker compose.
Like this (heavily edited from the original):
public final class CollaboratingContainers implements AutoCloseable {
private final Network network;
private final ElasticsearchContainer elasticsearchContainer;
...
private final List<GenericContainer<?>> containers = new ArrayList<>(3);
@SuppressWarnings("resource")
public CollaboratingContainers() {
network = Network.newNetwork();
elasticsearchContainer = new ElasticsearchContainer(ELASTICSEARCH_IMAGE).withNetwork(network)
.withNetworkAliases("es");
containers.add(elasticsearchContainer);
...
}
public final void start() {
// Retrieving the network ID creates the network.
network.getId();
for (var container : containers) {
container.start();
}
}
Then my test case uses @BeforeEach to set up the containers:
public class MyIT {
private CollaboratingContainers containers;
@BeforeEach
public void setUpContainers() {
containers = new CollaboratingContainers();
containers.start();
}
@AfterEach
public void tearDownContainers() {
containers.close();
}
It might be better if testcontainers provided a generalized helper class like my CollaboratingContainers, rather than a means for ordering each @Container.
@KantarBenedictAdamson FYI if you implement Startable interface, you can use @Container annotation on it ;)
also, in my junit5 branch, I was experimenting with dependsOn:
https://github.com/testcontainers/testcontainers-java/blob/junit5/modules/junit5/src/test/java/org/testcontainers/junit5/DependenciesTest.java
We may backport it
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you believe this is a mistake, please reply to this comment to keep it open. If there isn't one already, a PR to fix or at least reproduce the problem in a test case will always help us get back on track to tackle this.
This issue has been automatically closed due to inactivity. We apologise if this is still an active problem for you, and would ask you to re-open the issue if this is the case.
implemented in 1.12.0 (see dependsOn)
Most helpful comment
implemented in 1.12.0 (see
dependsOn)