diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc index 99b138f3d9f..21c2c10e97d 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/testing.adoc @@ -971,7 +971,7 @@ The following service connection factories are provided in the `spring-boot-test | Containers of type `Neo4jContainer` | `R2dbcConnectionDetails` -| Containers of type `MariaDBContainer`, `MSSQLServerContainer`, `MySQLContainer` or `PostgreSQLContainer` +| Containers of type `MariaDBContainer`, `MSSQLServerContainer`, `MySQLContainer`, `OracleContainer`, or `PostgreSQLContainer` | `RabbitConnectionDetails` | Containers of type `RabbitMQContainer` diff --git a/spring-boot-project/spring-boot-testcontainers/build.gradle b/spring-boot-project/spring-boot-testcontainers/build.gradle index b8fdd467d70..08b4171666f 100644 --- a/spring-boot-project/spring-boot-testcontainers/build.gradle +++ b/spring-boot-project/spring-boot-testcontainers/build.gradle @@ -25,6 +25,7 @@ dependencies { optional("org.testcontainers:mssqlserver") optional("org.testcontainers:mysql") optional("org.testcontainers:neo4j") + optional("org.testcontainers:oracle-xe") optional("org.testcontainers:postgresql") optional("org.testcontainers:rabbitmq") optional("org.testcontainers:redpanda") @@ -41,8 +42,11 @@ dependencies { testImplementation("org.mockito:mockito-core") testImplementation("org.mockito:mockito-junit-jupiter") testImplementation("org.springframework:spring-core-test") + testImplementation("org.springframework:spring-r2dbc") testImplementation("org.springframework.amqp:spring-rabbit") testImplementation("org.springframework.kafka:spring-kafka") testImplementation("org.testcontainers:junit-jupiter") + + testRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc") } diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactory.java new file mode 100644 index 00000000000..3d11143de1e --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactory.java @@ -0,0 +1,66 @@ +/* + * 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 io.r2dbc.spi.ConnectionFactoryOptions; +import org.testcontainers.containers.OracleContainer; +import org.testcontainers.containers.OracleR2DBCDatabaseContainer; + +import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails; +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} to create {@link R2dbcConnectionDetails} from + * a {@link ServiceConnection @ServiceConnection}-annotated {@link OracleContainer}. + * + * @author EddĂș MelĂ©ndez + */ +class OracleR2dbcContainerConnectionDetailsFactory + extends ContainerConnectionDetailsFactory { + + OracleR2dbcContainerConnectionDetailsFactory() { + super(ANY_CONNECTION_NAME, "io.r2dbc.spi.ConnectionFactoryOptions"); + } + + @Override + public R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource source) { + return new R2dbcDatabaseContainerConnectionDetails(source); + } + + /** + * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}. + */ + private static final class R2dbcDatabaseContainerConnectionDetails extends ContainerConnectionDetails + implements R2dbcConnectionDetails { + + private final OracleContainer container; + + private R2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource source) { + super(source); + this.container = source.getContainer(); + } + + @Override + public ConnectionFactoryOptions getConnectionFactoryOptions() { + return OracleR2DBCDatabaseContainer.getOptions(this.container); + } + + } + +} diff --git a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories index 68f7a176866..aad843c3b40 100644 --- a/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories @@ -22,6 +22,7 @@ org.springframework.boot.testcontainers.service.connection.neo4j.Neo4jContainerC 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.OracleR2dbcContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.r2dbc.PostgresR2dbcContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.redis.RedisContainerConnectionDetailsFactory,\ org.springframework.boot.testcontainers.service.connection.redpanda.RedpandaContainerConnectionDetailsFactory diff --git a/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactoryTests.java b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactoryTests.java new file mode 100644 index 00000000000..a9fce38f3e0 --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactoryTests.java @@ -0,0 +1,69 @@ +/* + * 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 io.r2dbc.spi.ConnectionFactory; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.OracleContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration; +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.testsupport.testcontainers.DockerImageNames; +import org.springframework.context.annotation.Configuration; +import org.springframework.r2dbc.core.DatabaseClient; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link OracleR2dbcContainerConnectionDetailsFactory}. + * + * @author Andy Wilkinson + */ +@SpringJUnitConfig +@Testcontainers(disabledWithoutDocker = true) +class OracleR2dbcContainerConnectionDetailsFactoryTests { + + @Container + @ServiceConnection + static final OracleContainer oracle = new OracleContainer(DockerImageNames.oracleXe()); + + @Autowired + ConnectionFactory connectionFactory; + + @Test + void connectionCanBeMadeToOracleContainer() { + Object result = DatabaseClient.create(this.connectionFactory) + .sql(DatabaseDriver.ORACLE.getValidationQuery()) + .map((row, metadata) -> row.get(0)) + .first() + .block(); + assertThat(result).isEqualTo("Hello"); + } + + @Configuration(proxyBeanMethods = false) + @ImportAutoConfiguration(R2dbcAutoConfiguration.class) + static class TestConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java index e70f4b2303e..394b92858e2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java @@ -41,6 +41,8 @@ public final class DockerImageNames { private static final String NEO4J_VERSION = "4.4.11"; + private static final String ORACLE_XE_VERSION = "18.4.0-slim"; + private static final String POSTGRESQL_VERSION = "14.0"; private static final String RABBIT_VERSION = "3.11-alpine"; @@ -110,6 +112,10 @@ public final class DockerImageNames { return DockerImageName.parse("neo4j").withTag(NEO4J_VERSION); } + public static DockerImageName oracleXe() { + return DockerImageName.parse("gvenzl/oracle-xe").withTag(ORACLE_XE_VERSION); + } + /** * Return a {@link DockerImageName} suitable for running PostgreSQL. * @return a docker image name for running postgresql