From 6d893b2fe246d78160e24c5c984d7e90fdc7301d Mon Sep 17 00:00:00 2001 From: Eddu Melendez Date: Tue, 18 Apr 2023 12:52:37 +0100 Subject: [PATCH 1/2] Add support for Oracle R2DBC Service Connection See gh-34852 --- .../spring-boot-testcontainers/build.gradle | 1 + ...2dbcContainerConnectionDetailsFactory.java | 64 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 1 + 3 files changed, 66 insertions(+) create mode 100644 spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactory.java diff --git a/spring-boot-project/spring-boot-testcontainers/build.gradle b/spring-boot-project/spring-boot-testcontainers/build.gradle index b8fdd467d70..a03a1cb4997 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") 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..c1d33a6b4bc --- /dev/null +++ b/spring-boot-project/spring-boot-testcontainers/src/main/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactory.java @@ -0,0 +1,64 @@ +/* + * 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.getContainer()); + } + + /** + * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}. + */ + private static final class R2dbcDatabaseContainerConnectionDetails implements R2dbcConnectionDetails { + + private final OracleContainer container; + + private R2dbcDatabaseContainerConnectionDetails(OracleContainer container) { + this.container = container; + } + + @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 From 0da209db08cadd965cbf60e539dcb8a1c1c1ca82 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 18 Apr 2023 13:47:46 +0100 Subject: [PATCH 2/2] Polish "Add support for Oracle R2DBC Service Connection" See gh-34852 --- .../src/docs/asciidoc/features/testing.adoc | 2 +- .../spring-boot-testcontainers/build.gradle | 3 + ...2dbcContainerConnectionDetailsFactory.java | 10 +-- ...ontainerConnectionDetailsFactoryTests.java | 69 +++++++++++++++++++ .../testcontainers/DockerImageNames.java | 6 ++ 5 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 spring-boot-project/spring-boot-testcontainers/src/test/java/org/springframework/boot/testcontainers/service/connection/r2dbc/OracleR2dbcContainerConnectionDetailsFactoryTests.java 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 a03a1cb4997..08b4171666f 100644 --- a/spring-boot-project/spring-boot-testcontainers/build.gradle +++ b/spring-boot-project/spring-boot-testcontainers/build.gradle @@ -42,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 index c1d33a6b4bc..3d11143de1e 100644 --- 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 @@ -40,18 +40,20 @@ class OracleR2dbcContainerConnectionDetailsFactory @Override public R2dbcConnectionDetails getContainerConnectionDetails(ContainerConnectionSource source) { - return new R2dbcDatabaseContainerConnectionDetails(source.getContainer()); + return new R2dbcDatabaseContainerConnectionDetails(source); } /** * {@link R2dbcConnectionDetails} backed by a {@link ContainerConnectionSource}. */ - private static final class R2dbcDatabaseContainerConnectionDetails implements R2dbcConnectionDetails { + private static final class R2dbcDatabaseContainerConnectionDetails extends ContainerConnectionDetails + implements R2dbcConnectionDetails { private final OracleContainer container; - private R2dbcDatabaseContainerConnectionDetails(OracleContainer container) { - this.container = container; + private R2dbcDatabaseContainerConnectionDetails(ContainerConnectionSource source) { + super(source); + this.container = source.getContainer(); } @Override 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