diff --git a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalDataSourceBuildUtil.java b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalDataSourceBuildUtil.java new file mode 100644 index 0000000000000..eb08ca225c362 --- /dev/null +++ b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalDataSourceBuildUtil.java @@ -0,0 +1,33 @@ +package io.quarkus.agroal.deployment; + +import jakarta.enterprise.inject.Default; + +import org.jboss.jandex.AnnotationInstance; + +import io.quarkus.agroal.DataSource; +import io.quarkus.arc.processor.DotNames; +import io.quarkus.datasource.common.runtime.DataSourceUtil; + +public final class AgroalDataSourceBuildUtil { + private AgroalDataSourceBuildUtil() { + } + + public static AnnotationInstance qualifier(String dataSourceName) { + if (DataSourceUtil.isDefault(dataSourceName)) { + return AnnotationInstance.builder(Default.class).build(); + } else { + return AnnotationInstance.builder(DataSource.class).value(dataSourceName).build(); + } + } + + public static AnnotationInstance[] qualifiers(String dataSourceName) { + if (DataSourceUtil.isDefault(dataSourceName)) { + return new AnnotationInstance[] { AnnotationInstance.builder(Default.class).build() }; + } else { + return new AnnotationInstance[] { + AnnotationInstance.builder(DotNames.NAMED).value(dataSourceName).build(), + AnnotationInstance.builder(DataSource.class).value(dataSourceName).build(), + }; + } + } +} diff --git a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java index ae4f74b82faf1..b7bf482799c2c 100644 --- a/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java +++ b/extensions/agroal/deployment/src/main/java/io/quarkus/agroal/deployment/AgroalProcessor.java @@ -1,5 +1,6 @@ package io.quarkus.agroal.deployment; +import static io.quarkus.agroal.deployment.AgroalDataSourceBuildUtil.qualifiers; import static io.quarkus.deployment.Capability.OPENTELEMETRY_TRACER; import java.sql.Driver; @@ -16,7 +17,6 @@ import javax.sql.XADataSource; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Default; import org.jboss.jandex.ClassType; import org.jboss.jandex.DotName; @@ -284,6 +284,7 @@ void generateDataSourceBeans(AgroalRecorder recorder, .addType(DATA_SOURCE) .addType(AGROAL_DATA_SOURCE) .scope(ApplicationScoped.class) + .qualifiers(qualifiers(dataSourceName)) .setRuntimeInit() .unremovable() .addInjectionPoint(ClassType.create(DotName.createSimple(DataSources.class))) @@ -291,15 +292,10 @@ void generateDataSourceBeans(AgroalRecorder recorder, // are created after runtime configuration has been set up .createWith(recorder.agroalDataSourceSupplier(dataSourceName, dataSourcesRuntimeConfig)); - if (aggregatedBuildTimeConfigBuildItem.isDefault()) { - configurator.addQualifier(Default.class); - } else { + if (!DataSourceUtil.isDefault(dataSourceName)) { // this definitely not ideal, but 'elytron-jdbc-security' uses it (although it could be easily changed) // which means that perhaps other extensions might depend on this as well... configurator.name(dataSourceName); - - configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", dataSourceName).done(); - configurator.addQualifier().annotation(DataSource.class).addValue("value", dataSourceName).done(); } syntheticBeanBuildItemBuildProducer.produce(configurator.done()); diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..fecba5eb20ae7 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,57 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import javax.sql.DataSource; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.agroal.api.AgroalDataSource; +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigActiveFalseDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + InjectableInstance dataSource; + + @Inject + InjectableInstance agroalDataSource; + + @Test + public void dataSource() { + doTest(dataSource); + } + + @Test + public void agroalDataSource() { + doTest(agroalDataSource); + } + + private void doTest(InjectableInstance instance) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var ds = instance.get(); + assertThat(ds).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> ds.getConnection()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckConfigActiveFalseTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java similarity index 58% rename from extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckConfigActiveFalseTest.java rename to extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java index a6a4fe8f5c03e..2bcc9ea38fc8b 100644 --- a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/DataSourceHealthCheckConfigActiveFalseTest.java +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java @@ -7,24 +7,23 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DataSourceHealthCheckConfigActiveFalseTest { +public class ConfigActiveFalseDefaultDatasourceHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withEmptyApplication() - .withConfigurationResource("application-default-datasource.properties") .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.active", "false") // this data source is broken, but will be deactivated, // so the overall check should pass - .overrideConfigKey("quarkus.datasource.brokenDS.db-kind", "h2") - .overrideConfigKey("quarkus.datasource.brokenDS.jdbc.url", "BROKEN") - .overrideConfigKey("quarkus.datasource.brokenDS.active", "false"); + .overrideConfigKey("quarkus.datasource.jdbc.url", "BROKEN"); @Test public void testDataSourceHealthCheckExclusion() { RestAssured.when().get("/q/health/ready") .then() - .body("status", CoreMatchers.equalTo("UP")); + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"\"", CoreMatchers.nullValue()); } } diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..4b5cd1506cc30 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,47 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.sql.SQLException; + +import javax.sql.DataSource; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.CreationException; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + assertThatThrownBy(() -> myBean.useDatasource()) + .isInstanceOf(CreationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + DataSource ds; + + public void useDatasource() throws SQLException { + ds.getConnection(); + } + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceTest.java deleted file mode 100644 index 4e71a02d8503e..0000000000000 --- a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseDefaultDatasourceTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.quarkus.agroal.test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.sql.SQLException; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.CreationException; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.agroal.api.AgroalDataSource; -import io.quarkus.arc.Arc; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; - -public class ConfigActiveFalseDefaultDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.active", "false"); - - @Inject - MyBean myBean; - - @Test - public void dataSource() { - DataSource ds = Arc.container().instance(DataSource.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(ds).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> ds.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void agroalDataSource() { - AgroalDataSource ds = Arc.container().instance(AgroalDataSource.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(ds).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> ds.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - assertThatThrownBy(() -> myBean.useDatasource()) - .isInstanceOf(CreationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - DataSource ds; - - public void useDatasource() throws SQLException { - ds.getConnection(); - } - } -} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..4bc4ac48d0c01 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,62 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import javax.sql.DataSource; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.agroal.api.AgroalDataSource; +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigActiveFalseNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.users.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2"); + + @Inject + @io.quarkus.agroal.DataSource("users") + InjectableInstance dataSource; + + @Inject + @io.quarkus.agroal.DataSource("users") + InjectableInstance agroalDataSource; + + @Test + public void dataSource() { + doTest(dataSource); + } + + @Test + public void agroalDataSource() { + doTest(agroalDataSource); + } + + private void doTest(InjectableInstance instance) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean cannot be null. + var ds = instance.get(); + assertThat(ds).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> ds.getConnection()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'users' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" + + " to 'true' and configure datasource 'users'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceHealthCheckTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..ad587dccd82e4 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.agroal.test; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigActiveFalseNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.users.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") + // this data source is broken, but will be deactivated, + // so the overall check should pass + .overrideConfigKey("quarkus.datasource.users.jdbc.url", "BROKEN"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"users\"", CoreMatchers.nullValue()); + } + +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..2f402ee176c9a --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,51 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.sql.SQLException; + +import javax.sql.DataSource; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.CreationException; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigActiveFalseNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.users.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2"); + + @Inject + MyBean myBean; + + @Test + public void test() { + assertThatThrownBy(() -> myBean.useDatasource()) + .isInstanceOf(CreationException.class) + .hasMessageContainingAll("Datasource 'users' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" + + " to 'true' and configure datasource 'users'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @io.quarkus.agroal.DataSource("users") + DataSource ds; + + public void useDatasource() throws SQLException { + ds.getConnection(); + } + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceTest.java deleted file mode 100644 index 812aeadd02514..0000000000000 --- a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigActiveFalseNamedDatasourceTest.java +++ /dev/null @@ -1,96 +0,0 @@ -package io.quarkus.agroal.test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.sql.SQLException; - -import javax.sql.DataSource; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.CreationException; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; - -public class ConfigActiveFalseNamedDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.users.active", "false") - // We need at least one build-time property for the datasource, - // otherwise it's considered unconfigured at build time... - .overrideConfigKey("quarkus.datasource.users.db-kind", "h2"); - - @Inject - MyBean myBean; - - @Test - public void dataSource() { - DataSource ds = Arc.container().instance(DataSource.class, - new io.quarkus.agroal.DataSource.DataSourceLiteral("users")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(ds).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> ds.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'users' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" - + " to 'true' and configure datasource 'users'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void agroalDataSource() { - DataSource ds = Arc.container().instance(DataSource.class, - new io.quarkus.agroal.DataSource.DataSourceLiteral("users")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(ds).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> ds.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'users' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" - + " to 'true' and configure datasource 'users'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - assertThatThrownBy(() -> myBean.useDatasource()) - .isInstanceOf(CreationException.class) - .hasMessageContainingAll("Datasource 'users' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" - + " to 'true' and configure datasource 'users'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - @io.quarkus.agroal.DataSource("users") - DataSource ds; - - public void useDatasource() throws SQLException { - ds.getConnection(); - } - } -} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..a697a3db89796 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,52 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import javax.sql.DataSource; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.agroal.api.AgroalDataSource; +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigUrlMissingDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + InjectableInstance dataSource; + + @Inject + InjectableInstance agroalDataSource; + + @Test + public void dataSource() { + doTest(dataSource); + } + + @Test + public void agroalDataSource() { + doTest(agroalDataSource); + } + + private void doTest(InjectableInstance instance) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var ds = instance.get(); + assertThat(ds).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> ds.getConnection()) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("quarkus.datasource.jdbc.url has not been defined"); + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..bfe53bdf9c463 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java @@ -0,0 +1,28 @@ +package io.quarkus.agroal.test; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingDefaultDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // UnconfiguredDataSource always reports as healthy... + // https://github.com/quarkusio/quarkus/issues/36666 + .body("status", CoreMatchers.equalTo("UP")) + .body("checks[0].data.\"\"", CoreMatchers.equalTo("UP")); + } + +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..7413575685c63 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,44 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.sql.SQLException; + +import javax.sql.DataSource; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigUrlMissingDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + assertThatThrownBy(() -> myBean.useDatasource()) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("quarkus.datasource.jdbc.url has not been defined"); + } + + @ApplicationScoped + public static class MyBean { + @Inject + DataSource ds; + + public void useDatasource() throws SQLException { + ds.getConnection(); + } + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..e91b9d797c873 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,57 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import javax.sql.DataSource; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.agroal.api.AgroalDataSource; +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigUrlMissingNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2"); + + @Inject + @io.quarkus.agroal.DataSource("users") + InjectableInstance dataSource; + + @Inject + @io.quarkus.agroal.DataSource("users") + InjectableInstance agroalDataSource; + + @Test + public void dataSource() { + doTest(dataSource); + } + + @Test + public void agroalDataSource() { + doTest(agroalDataSource); + } + + private void doTest(InjectableInstance instance) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean cannot be null. + var ds = instance.get(); + assertThat(ds).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> ds.getConnection()) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("quarkus.datasource.\"users\".jdbc.url has not been defined"); + } +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceHealthCheckTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..b12f402689ee6 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceHealthCheckTest.java @@ -0,0 +1,31 @@ +package io.quarkus.agroal.test; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // UnconfiguredDataSource always reports as healthy... + // https://github.com/quarkusio/quarkus/issues/36666 + .body("status", CoreMatchers.equalTo("UP")) + .body("checks[0].data.\"users\"", CoreMatchers.equalTo("UP")); + } + +} diff --git a/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..8ca6ac3626977 --- /dev/null +++ b/extensions/agroal/deployment/src/test/java/io/quarkus/agroal/test/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,48 @@ +package io.quarkus.agroal.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.sql.SQLException; + +import javax.sql.DataSource; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigUrlMissingNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2"); + + @Inject + MyBean myBean; + + @Test + public void test() { + assertThatThrownBy(() -> myBean.useDatasource()) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("quarkus.datasource.\"users\".jdbc.url has not been defined"); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @io.quarkus.agroal.DataSource("users") + DataSource ds; + + public void useDatasource() throws SQLException { + ds.getConnection(); + } + } +} diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalDataSourceUtil.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalDataSourceUtil.java new file mode 100644 index 0000000000000..524a48b0e577e --- /dev/null +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/AgroalDataSourceUtil.java @@ -0,0 +1,31 @@ +package io.quarkus.agroal.runtime; + +import java.lang.annotation.Annotation; + +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.spi.Bean; + +import io.quarkus.agroal.DataSource; +import io.quarkus.datasource.common.runtime.DataSourceUtil; + +public final class AgroalDataSourceUtil { + private AgroalDataSourceUtil() { + } + + public static String dataSourceName(Bean bean) { + for (Object qualifier : bean.getQualifiers()) { + if (qualifier instanceof DataSource) { + return ((DataSource) qualifier).value(); + } + } + return DataSourceUtil.DEFAULT_DATASOURCE_NAME; + } + + public static Annotation qualifier(String dataSourceName) { + if (DataSourceUtil.isDefault(dataSourceName)) { + return Default.Literal.INSTANCE; + } else { + return new DataSource.DataSourceLiteral(dataSourceName); + } + } +} diff --git a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java index a8b005fc4aa53..5f72e43467730 100644 --- a/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java +++ b/extensions/agroal/runtime/src/main/java/io/quarkus/agroal/runtime/DataSources.java @@ -17,7 +17,6 @@ import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import jakarta.enterprise.inject.Any; -import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.inject.Singleton; import jakarta.transaction.TransactionManager; @@ -39,7 +38,6 @@ import io.agroal.api.security.SimplePassword; import io.agroal.api.transaction.TransactionIntegration; import io.agroal.narayana.NarayanaTransactionIntegration; -import io.quarkus.agroal.DataSource; import io.quarkus.agroal.runtime.JdbcDriver.JdbcDriverLiteral; import io.quarkus.arc.Arc; import io.quarkus.credentials.CredentialsProvider; @@ -59,7 +57,12 @@ * The {@code createDataSource} method is called at runtime (see * {@link AgroalRecorder#agroalDataSourceSupplier(String, DataSourcesRuntimeConfig)}) * in order to produce the actual {@code AgroalDataSource} objects. + * + * @deprecated This class should not be used from applications or other extensions. + * For applications, use CDI to retrieve datasources instead. + * For extensions, use {@link AgroalDataSourceUtil} instead. */ +@Deprecated @Singleton public class DataSources { @@ -290,9 +293,7 @@ public AgroalDataSource doCreateDataSource(String dataSourceName, boolean failIf // Set pool interceptors for this datasource Collection interceptorList = agroalPoolInterceptors - .select(dataSourceName == null || DataSourceUtil.isDefault(dataSourceName) - ? Default.Literal.INSTANCE - : new DataSource.DataSourceLiteral(dataSourceName)) + .select(AgroalDataSourceUtil.qualifier(dataSourceName)) .stream().collect(Collectors.toList()); if (!interceptorList.isEmpty()) { dataSource.setPoolInterceptors(interceptorList); diff --git a/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java b/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java index 8158ad25b7e3c..fe35e781ae7e5 100644 --- a/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java +++ b/extensions/datasource/common/src/main/java/io/quarkus/datasource/common/runtime/DataSourceUtil.java @@ -12,7 +12,7 @@ public final class DataSourceUtil { public static final String DEFAULT_DATASOURCE_NAME = ""; public static boolean isDefault(String dataSourceName) { - return DEFAULT_DATASOURCE_NAME.equals(dataSourceName); + return dataSourceName == null || DEFAULT_DATASOURCE_NAME.equals(dataSourceName); } public static boolean hasDefault(Collection dataSourceNames) { @@ -20,7 +20,7 @@ public static boolean hasDefault(Collection dataSourceNames) { } public static String dataSourcePropertyKey(String datasourceName, String radical) { - if (datasourceName == null || DataSourceUtil.isDefault(datasourceName)) { + if (DataSourceUtil.isDefault(datasourceName)) { return "quarkus.datasource." + radical; } else { return "quarkus.datasource.\"" + datasourceName + "\"." + radical; @@ -28,7 +28,7 @@ public static String dataSourcePropertyKey(String datasourceName, String radical } public static List dataSourcePropertyKeys(String datasourceName, String radical) { - if (datasourceName == null || DataSourceUtil.isDefault(datasourceName)) { + if (DataSourceUtil.isDefault(datasourceName)) { return List.of("quarkus.datasource." + radical); } else { // Two possible syntaxes: with or without quotes diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java similarity index 89% rename from extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceTest.java rename to extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java index 79ff4aad04ff4..7ef6a8fa83699 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -13,19 +13,19 @@ import io.quarkus.test.QuarkusUnitTest; -public class FlywayExtensionConfigActiveFalseDefaultDatasourceTest { +public class FlywayExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .overrideConfigKey("quarkus.datasource.active", "false"); @Inject - Instance flywayForDefaultDatasource; + Instance flyway; @Test @DisplayName("If the default datasource is deactivated, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForDefaultDatasource::get) + assertThatThrownBy(flyway::get) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource '' for Flyway", diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..135149791d7b6 --- /dev/null +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,46 @@ +package io.quarkus.flyway.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.flywaydb.core.Flyway; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class FlywayExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + @DisplayName("If the default datasource is deactivated, the application should boot, but Flyway should be deactivated for that datasource") + public void testBootSucceedsButFlywayDeactivated() { + assertThatThrownBy(myBean::useFlyway) + .cause() + .hasMessageContainingAll("Unable to find datasource '' for Flyway", + "Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Flyway flyway; + + public void useFlyway() { + flyway.getConfiguration(); + } + } +} diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceDynamicInjectionTest.java similarity index 93% rename from extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceTest.java rename to extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceDynamicInjectionTest.java index a00dd3f237b13..13c55ccdba628 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceDynamicInjectionTest.java @@ -14,7 +14,7 @@ import io.quarkus.flyway.FlywayDataSource; import io.quarkus.test.QuarkusUnitTest; -public class FlywayExtensionConfigActiveFalseNamedDataSourceTest { +public class FlywayExtensionConfigActiveFalseNamedDataSourceDynamicInjectionTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -31,12 +31,12 @@ public class FlywayExtensionConfigActiveFalseNamedDataSourceTest { @Inject @FlywayDataSource("users") - Instance flywayForNamedDatasource; + Instance flyway; @Test @DisplayName("If a named datasource is deactivated, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForNamedDatasource::get) + assertThatThrownBy(flyway::get) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource 'users' for Flyway", diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceStaticInjectionTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceStaticInjectionTest.java new file mode 100644 index 0000000000000..d552365308213 --- /dev/null +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigActiveFalseNamedDataSourceStaticInjectionTest.java @@ -0,0 +1,57 @@ +package io.quarkus.flyway.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.flywaydb.core.Flyway; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.flyway.FlywayDataSource; +import io.quarkus.test.QuarkusUnitTest; + +public class FlywayExtensionConfigActiveFalseNamedDataSourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.users.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") + // We need this otherwise the *default* datasource may impact this test + .overrideConfigKey("quarkus.datasource.db-kind", "h2") + .overrideConfigKey("quarkus.datasource.username", "sa") + .overrideConfigKey("quarkus.datasource.password", "sa") + .overrideConfigKey("quarkus.datasource.jdbc.url", + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); + + @Inject + MyBean myBean; + + @Test + @DisplayName("If a named datasource is deactivated, the application should boot, but Flyway should be deactivated for that datasource") + public void testBootSucceedsButFlywayDeactivated() { + assertThatThrownBy(myBean::useFlyway) + .cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Flyway", + "Datasource 'users' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" + + " to 'true' and configure datasource 'users'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @FlywayDataSource("users") + Flyway flyway; + + public void useFlyway() { + flyway.getConfiguration(); + } + } +} diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..76864cc578b91 --- /dev/null +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,38 @@ +package io.quarkus.flyway.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.enterprise.inject.CreationException; +import jakarta.enterprise.inject.Instance; +import jakarta.inject.Inject; + +import org.flywaydb.core.Flyway; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class FlywayExtensionConfigUrlMissingDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + Instance flyway; + + @Test + @DisplayName("If the URL is missing for the default datasource, the application should boot, but Flyway should be deactivated for that datasource") + public void testBootSucceedsButFlywayDeactivated() { + assertThatThrownBy(flyway::get) + .isInstanceOf(CreationException.class) + .cause() + .hasMessageContainingAll("Unable to find datasource '' for Flyway", + "Datasource '' is not configured.", + "To solve this, configure datasource ''.", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + +} diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingDefaultDatasourceStaticInjectionTest.java similarity index 50% rename from extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java rename to extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingDefaultDatasourceStaticInjectionTest.java index c172cdecb9a73..2393a0fbffb6a 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyDefaultDatasourceTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingDefaultDatasourceStaticInjectionTest.java @@ -3,8 +3,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.CreationException; -import jakarta.enterprise.inject.Instance; import jakarta.inject.Inject; import org.flywaydb.core.Flyway; @@ -14,34 +12,19 @@ import io.quarkus.test.QuarkusUnitTest; -public class FlywayExtensionConfigEmptyDefaultDatasourceTest { +public class FlywayExtensionConfigUrlMissingDefaultDatasourceStaticInjectionTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - // The datasource won't be truly "unconfigured" if dev services are enabled + // The URL won't be missing if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false"); - @Inject - Instance flywayForDefaultDatasource; - @Inject MyBean myBean; @Test - @DisplayName("If there is no config for the default datasource, the application should boot, but Flyway should be deactivated for that datasource") + @DisplayName("If the URL is missing for the default datasource, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForDefaultDatasource::get) - .isInstanceOf(CreationException.class) - .cause() - .hasMessageContainingAll("Unable to find datasource '' for Flyway", - "Datasource '' is not configured.", - "To solve this, configure datasource ''.", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - @DisplayName("If there is no config for the default datasource, the application should boot even if we inject a bean that depends on Liquibase, but actually using Liquibase should fail") - public void testBootSucceedsWithInjectedBeanDependingOnFlywayButFlywayDeactivated() { assertThatThrownBy(() -> myBean.useFlyway()) .cause() .hasMessageContainingAll("Unable to find datasource '' for Flyway", @@ -53,10 +36,10 @@ public void testBootSucceedsWithInjectedBeanDependingOnFlywayButFlywayDeactivate @ApplicationScoped public static class MyBean { @Inject - Flyway flywayForDefaultDatasource; + Flyway flyway; public void useFlyway() { - flywayForDefaultDatasource.getConfiguration(); + flyway.getConfiguration(); } } } diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyNamedDataSourceTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingNamedDataSourceDynamicInjectionTest.java similarity index 54% rename from extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyNamedDataSourceTest.java rename to extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingNamedDataSourceDynamicInjectionTest.java index a195ce306b47c..6f1bc9bd8ed8a 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigEmptyNamedDataSourceTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingNamedDataSourceDynamicInjectionTest.java @@ -2,8 +2,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; +import jakarta.enterprise.inject.CreationException; import jakarta.enterprise.inject.Instance; -import jakarta.enterprise.inject.UnsatisfiedResolutionException; import jakarta.inject.Inject; import org.flywaydb.core.Flyway; @@ -14,28 +14,35 @@ import io.quarkus.flyway.FlywayDataSource; import io.quarkus.test.QuarkusUnitTest; -public class FlywayExtensionConfigEmptyNamedDataSourceTest { +public class FlywayExtensionConfigUrlMissingNamedDataSourceDynamicInjectionTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") // We need this otherwise the *default* datasource may impact this test .overrideConfigKey("quarkus.datasource.db-kind", "h2") .overrideConfigKey("quarkus.datasource.username", "sa") .overrideConfigKey("quarkus.datasource.password", "sa") .overrideConfigKey("quarkus.datasource.jdbc.url", - "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1") - // The datasource won't be truly "unconfigured" if dev services are enabled - .overrideConfigKey("quarkus.devservices.enabled", "false"); + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); @Inject @FlywayDataSource("users") - Instance flywayForNamedDatasource; + Instance flyway; @Test - @DisplayName("If there is no config for a named datasource, the application should boot, but Flyway should be deactivated for that datasource") + @DisplayName("If the URL is missing for a named datasource, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForNamedDatasource::get) - .isInstanceOf(UnsatisfiedResolutionException.class) - .hasMessageContaining("No bean found"); + assertThatThrownBy(flyway::get) + .isInstanceOf(CreationException.class) + .cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Flyway", + "Datasource 'users' is not configured.", + "To solve this, configure datasource 'users'.", + "Refer to https://quarkus.io/guides/datasource for guidance."); } } diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingNamedDataSourceStaticInjectionTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingNamedDataSourceStaticInjectionTest.java new file mode 100644 index 0000000000000..abe1a7bc9bdcb --- /dev/null +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionConfigUrlMissingNamedDataSourceStaticInjectionTest.java @@ -0,0 +1,56 @@ +package io.quarkus.flyway.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.flywaydb.core.Flyway; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.flyway.FlywayDataSource; +import io.quarkus.test.QuarkusUnitTest; + +public class FlywayExtensionConfigUrlMissingNamedDataSourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") + // We need this otherwise the *default* datasource may impact this test + .overrideConfigKey("quarkus.datasource.db-kind", "h2") + .overrideConfigKey("quarkus.datasource.username", "sa") + .overrideConfigKey("quarkus.datasource.password", "sa") + .overrideConfigKey("quarkus.datasource.jdbc.url", + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); + + @Inject + MyBean myBean; + + @Test + @DisplayName("If the URL is missing for a named datasource, the application should boot, but Flyway should be deactivated for that datasource") + public void testBootSucceedsButFlywayDeactivated() { + assertThatThrownBy(() -> myBean.useFlyway()) + .cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Flyway", + "Datasource 'users' is not configured.", + "To solve this, configure datasource 'users'.", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @FlywayDataSource("users") + Flyway flyway; + + public void useFlyway() { + flyway.getConfiguration(); + } + } +} diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java index 240237ff5d727..d6f4dd9c9e6d0 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java @@ -23,12 +23,12 @@ public class FlywayExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest .overrideConfigKey("quarkus.flyway.migrate-at-start", "true"); @Inject - Instance flywayForDefaultDatasource; + Instance flyway; @Test @DisplayName("If the default datasource is deactivated, even if migrate-at-start is enabled, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForDefaultDatasource::get) + assertThatThrownBy(flyway::get) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource '' for Flyway", diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceUrlMissingTest.java similarity index 84% rename from extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java rename to extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceUrlMissingTest.java index 0f9f506d16d0a..4cfaab211de12 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartDefaultDatasourceUrlMissingTest.java @@ -13,23 +13,23 @@ import io.quarkus.test.QuarkusUnitTest; -public class FlywayExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest { +public class FlywayExtensionMigrateAtStartDefaultDatasourceUrlMissingTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addAsResource("db/migration/V1.0.0__Quarkus.sql")) .overrideConfigKey("quarkus.flyway.migrate-at-start", "true") - // The datasource won't be truly "unconfigured" if dev services are enabled + // The URL won't be missing if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false"); @Inject - Instance flywayForDefaultDatasource; + Instance flyway; @Test @DisplayName("If there is no config for the default datasource, even if migrate-at-start is enabled, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForDefaultDatasource::get) + assertThatThrownBy(flyway::get) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource '' for Flyway", diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java index 7c2e303c9d4ce..e21e2d4996e97 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java @@ -34,12 +34,12 @@ public class FlywayExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest { @Inject @FlywayDataSource("users") - Instance flywayForNamedDatasource; + Instance flyway; @Test @DisplayName("If a named datasource is deactivated, even if migrate-at-start is enabled, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForNamedDatasource::get) + assertThatThrownBy(flyway::get) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource 'users' for Flyway", diff --git a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigEmptyTest.java b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest.java similarity index 61% rename from extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigEmptyTest.java rename to extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest.java index 48e507e40783d..db55982bde28f 100644 --- a/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigEmptyTest.java +++ b/extensions/flyway/deployment/src/test/java/io/quarkus/flyway/test/FlywayExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest.java @@ -2,8 +2,8 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; +import jakarta.enterprise.inject.CreationException; import jakarta.enterprise.inject.Instance; -import jakarta.enterprise.inject.UnsatisfiedResolutionException; import jakarta.inject.Inject; import org.flywaydb.core.Flyway; @@ -14,31 +14,38 @@ import io.quarkus.flyway.FlywayDataSource; import io.quarkus.test.QuarkusUnitTest; -public class FlywayExtensionMigrateAtStartNamedDatasourceConfigEmptyTest { +public class FlywayExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addAsResource("db/migration/V1.0.0__Quarkus.sql")) .overrideConfigKey("quarkus.flyway.users.migrate-at-start", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") // We need this otherwise the *default* datasource may impact this test .overrideConfigKey("quarkus.datasource.db-kind", "h2") .overrideConfigKey("quarkus.datasource.username", "sa") .overrideConfigKey("quarkus.datasource.password", "sa") .overrideConfigKey("quarkus.datasource.jdbc.url", - "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1") - // The datasource won't be truly "unconfigured" if dev services are enabled - .overrideConfigKey("quarkus.devservices.enabled", "false"); + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); @Inject @FlywayDataSource("users") - Instance flywayForNamedDatasource; + Instance flyway; @Test @DisplayName("If there is no config for a named datasource, even if migrate-at-start is enabled, the application should boot, but Flyway should be deactivated for that datasource") public void testBootSucceedsButFlywayDeactivated() { - assertThatThrownBy(flywayForNamedDatasource::get) - .isInstanceOf(UnsatisfiedResolutionException.class) - .hasMessageContaining("No bean found"); + assertThatThrownBy(flyway::get) + .isInstanceOf(CreationException.class) + .cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Flyway", + "Datasource 'users' is not configured.", + "To solve this, configure datasource 'users'.", + "Refer to https://quarkus.io/guides/datasource for guidance."); } } diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest.java new file mode 100644 index 0000000000000..b0837e60ef069 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest.java @@ -0,0 +1,40 @@ +package io.quarkus.hibernate.orm.config.datasource; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.config.MyEntity; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClass(MyEntity.class)) + .overrideConfigKey("quarkus.hibernate-orm.datasource", "ds-1") + .overrideConfigKey("quarkus.hibernate-orm.database.generation", "drop-and-create") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "h2") + .assertException(t -> assertThat(t) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll( + "Unable to find datasource 'ds-1' for persistence unit ''", + "Datasource 'ds-1' is not configured.", + "To solve this, configure datasource 'ds-1'.", + "Refer to https://quarkus.io/guides/datasource for guidance.")); + + @Test + public void testInvalidConfiguration() { + // deployment exception should happen first + Assertions.fail(); + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceMissingTest.java similarity index 94% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceMissingTest.java index 95da175428278..134c09c40fed2 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceMissingTest.java @@ -10,7 +10,7 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; -public class EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest { +public class EntitiesInDefaultPUWithExplicitDatasourceMissingTest { @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest.java similarity index 88% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest.java index 5e301b02be941..384bf91369390 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest.java @@ -10,13 +10,13 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; -public class EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest { +public class EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest { @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClass(MyEntity.class)) - // The datasource won't be truly "unconfigured" if dev services are enabled + // The URL won't be missing if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") .assertException(t -> assertThat(t) .isInstanceOf(ConfigurationException.class) diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitDatasourceConfigUrlMissingTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitDatasourceConfigUrlMissingTest.java new file mode 100644 index 0000000000000..5161bfd2e4cf2 --- /dev/null +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitDatasourceConfigUrlMissingTest.java @@ -0,0 +1,40 @@ +package io.quarkus.hibernate.orm.config.datasource; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.orm.config.namedpu.MyEntity; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class EntitiesInNamedPUWithExplicitDatasourceConfigUrlMissingTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addPackage(MyEntity.class.getPackage().getName())) + .overrideConfigKey("quarkus.hibernate-orm.pu-1.datasource", "ds-1") + .overrideConfigKey("quarkus.hibernate-orm.pu-1.database.generation", "drop-and-create") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "h2") + .assertException(t -> assertThat(t) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll( + "Unable to find datasource 'ds-1' for persistence unit 'pu-1'", + "Datasource 'ds-1' is not configured.", + "To solve this, configure datasource 'ds-1'.", + "Refer to https://quarkus.io/guides/datasource for guidance.")); + + @Test + public void testInvalidConfiguration() { + // deployment exception should happen first + Assertions.fail(); + } + +} diff --git a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitDatasourceMissingTest.java similarity index 95% rename from extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java rename to extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitDatasourceMissingTest.java index bc7f76483c09a..f59962e11570c 100644 --- a/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-orm/deployment/src/test/java/io/quarkus/hibernate/orm/config/datasource/EntitiesInNamedPUWithExplicitDatasourceMissingTest.java @@ -10,7 +10,7 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; -public class EntitiesInNamedPUWithExplicitUnconfiguredDatasourceTest { +public class EntitiesInNamedPUWithExplicitDatasourceMissingTest { @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java index 4bc6dbed953d0..7e82d2a73d26a 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java @@ -5,15 +5,13 @@ import java.util.Locale; import java.util.Optional; -import jakarta.enterprise.inject.Default; - import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.jboss.logging.Logger; import io.agroal.api.AgroalDataSource; import io.quarkus.agroal.DataSource; +import io.quarkus.agroal.runtime.AgroalDataSourceUtil; import io.quarkus.arc.Arc; -import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.hibernate.orm.runtime.customized.QuarkusConnectionProvider; import io.quarkus.hibernate.orm.runtime.migration.MultiTenancyStrategy; @@ -74,11 +72,7 @@ private static AgroalDataSource tenantDataSource(Optional dataSourceName } private static AgroalDataSource getDataSource(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return Arc.container().instance(AgroalDataSource.class, Default.Literal.INSTANCE).get(); - } else { - return Arc.container().instance(AgroalDataSource.class, new DataSource.DataSourceLiteral(dataSourceName)).get(); - } + return Arc.container().instance(AgroalDataSource.class, AgroalDataSourceUtil.qualifier(dataSourceName)).get(); } private static class SchemaTenantConnectionProvider extends QuarkusConnectionProvider { diff --git a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigActiveFalseTest.java b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigActiveFalseTest.java new file mode 100644 index 0000000000000..9a30b6406361f --- /dev/null +++ b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigActiveFalseTest.java @@ -0,0 +1,39 @@ +package io.quarkus.hibernate.reactive.config.datasource; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.reactive.config.MyEntity; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class EntitiesInDefaultPUWithExplicitDatasourceConfigActiveFalseTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClass(MyEntity.class)) + .overrideConfigKey("quarkus.hibernate-orm.datasource", "ds-1") + .overrideConfigKey("quarkus.hibernate-orm.database.generation", "drop-and-create") + .overrideConfigKey("quarkus.datasource.\"ds-1\".active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.\"ds-1\".db-kind", "h2") + .assertException(t -> assertThat(t) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll( + // Hibernate Reactive doesn't support explicitly setting the datasource (yet), + // so it will just notice the default datasource is not configured! + "The default datasource must be configured for Hibernate Reactive", + "Refer to https://quarkus.io/guides/datasource for guidance.")); + + @Test + public void testInvalidConfiguration() { + // deployment exception should happen first + Assertions.fail(); + } + +} diff --git a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest.java b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest.java new file mode 100644 index 0000000000000..cabc1d49db783 --- /dev/null +++ b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest.java @@ -0,0 +1,40 @@ +package io.quarkus.hibernate.reactive.config.datasource; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.hibernate.reactive.config.MyEntity; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; + +public class EntitiesInDefaultPUWithExplicitDatasourceConfigUrlMissingTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addClass(MyEntity.class)) + .overrideConfigKey("quarkus.hibernate-orm.datasource", "ds-1") + .overrideConfigKey("quarkus.hibernate-orm.database.generation", "drop-and-create") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "h2") + .assertException(t -> assertThat(t) + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll( + // Hibernate Reactive doesn't support explicitly setting the datasource (yet), + // so it will just notice the default datasource is not configured! + "The default datasource must be configured for Hibernate Reactive", + "Refer to https://quarkus.io/guides/datasource for guidance.")); + + @Test + public void testInvalidConfiguration() { + // deployment exception should happen first + Assertions.fail(); + } + +} diff --git a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceMissingTest.java similarity index 62% rename from extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java rename to extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceMissingTest.java index a70236bce167b..343d71d02550e 100644 --- a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithExplicitDatasourceMissingTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -9,7 +10,7 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; -public class EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest { +public class EntitiesInDefaultPUWithExplicitDatasourceMissingTest { @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() @@ -19,12 +20,16 @@ public class EntitiesInDefaultPUWithExplicitUnconfiguredDatasourceTest { .overrideConfigKey("quarkus.hibernate-orm.database.generation", "drop-and-create") .assertException(t -> assertThat(t) .isInstanceOf(ConfigurationException.class) - .hasMessageContaining( - "The default datasource must be configured for Hibernate Reactive. Refer to https://quarkus.io/guides/datasource for guidance.")); + .hasMessageContainingAll( + // Hibernate Reactive doesn't support explicitly setting the datasource (yet), + // so it will just notice the default datasource is not configured! + "The default datasource must be configured for Hibernate Reactive", + "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test public void testInvalidConfiguration() { - // bootstrap will succeed and ignore the fact that a datasource is unconfigured... + // deployment exception should happen first + Assertions.fail(); } } diff --git a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest.java similarity index 66% rename from extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java rename to extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest.java index 495a8b8dc4fc6..e92c8052c1c8b 100644 --- a/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest.java +++ b/extensions/hibernate-reactive/deployment/src/test/java/io/quarkus/hibernate/reactive/config/datasource/EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -9,22 +10,24 @@ import io.quarkus.runtime.configuration.ConfigurationException; import io.quarkus.test.QuarkusUnitTest; -public class EntitiesInDefaultPUWithImplicitUnconfiguredDatasourceTest { +public class EntitiesInDefaultPUWithImplicitDatasourceConfigUrlMissingTest { @RegisterExtension static QuarkusUnitTest runner = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addClass(MyEntity.class)) - // The datasource won't be truly "unconfigured" if dev services are enabled + // The URL won't be missing if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") .assertException(t -> assertThat(t) .isInstanceOf(ConfigurationException.class) - .hasMessageContaining( - "The default datasource must be configured for Hibernate Reactive. Refer to https://quarkus.io/guides/datasource for guidance.")); + .hasMessageContainingAll( + "The default datasource must be configured for Hibernate Reactive", + "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test public void testInvalidConfiguration() { - // bootstrap will succeed and ignore the fact that a datasource is unconfigured... + // deployment exception should happen first + Assertions.fail(); } } diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java similarity index 90% rename from extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceTest.java rename to extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java index ed35e12bfd237..f84932288d860 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -13,19 +13,19 @@ import io.quarkus.liquibase.LiquibaseFactory; import io.quarkus.test.QuarkusUnitTest; -public class LiquibaseExtensionConfigActiveFalseDefaultDatasourceTest { +public class LiquibaseExtensionConfigActiveFalseDefaultDatasourceDynamicInjectionTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .overrideConfigKey("quarkus.datasource.active", "false"); @Inject - Instance liquibaseForDefaultDatasource; + Instance liquibase; @Test @DisplayName("If the default datasource is deactivated, the application should boot, but Liquibase should be deactivated for that datasource") public void testBootSucceedsButLiquibaseDeactivated() { - assertThatThrownBy(() -> liquibaseForDefaultDatasource.get().getConfiguration()) + assertThatThrownBy(() -> liquibase.get().getConfiguration()) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource '' for Liquibase", diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..6e1c4760a5c75 --- /dev/null +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,47 @@ +package io.quarkus.liquibase.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.liquibase.LiquibaseFactory; +import io.quarkus.test.QuarkusUnitTest; + +public class LiquibaseExtensionConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + @DisplayName("If the default datasource is deactivated, the application should boot, but Liquibase should be deactivated for that datasource") + public void testBootSucceedsButLiquibaseDeactivated() { + assertThatThrownBy(myBean::useLiquibase) + .cause() + .hasMessageContainingAll("Unable to find datasource '' for Liquibase", + "Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + LiquibaseFactory liquibase; + + public void useLiquibase() { + liquibase.getConfiguration(); + } + } + +} diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceDynamicInjectionTest.java similarity index 91% rename from extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceTest.java rename to extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceDynamicInjectionTest.java index 583e2d934dadc..06c35584f3785 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceDynamicInjectionTest.java @@ -14,7 +14,7 @@ import io.quarkus.liquibase.LiquibaseFactory; import io.quarkus.test.QuarkusUnitTest; -public class LiquibaseExtensionConfigActiveFalseNamedDatasourceTest { +public class LiquibaseExtensionConfigActiveFalseNamedDatasourceDynamicInjectionTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() @@ -28,14 +28,15 @@ public class LiquibaseExtensionConfigActiveFalseNamedDatasourceTest { .overrideConfigKey("quarkus.datasource.password", "sa") .overrideConfigKey("quarkus.datasource.jdbc.url", "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); + @Inject @LiquibaseDataSource("users") - Instance liquibaseForNamedDatasource; + Instance liquibase; @Test @DisplayName("If a named datasource is deactivated, the application should boot, but Liquibase should be deactivated for that datasource") public void testBootSucceedsButLiquibaseDeactivated() { - assertThatThrownBy(() -> liquibaseForNamedDatasource.get().getConfiguration()) + assertThatThrownBy(() -> liquibase.get().getConfiguration()) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource 'users' for Liquibase", diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceStaticInjectionTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..198665b5afa45 --- /dev/null +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigActiveFalseNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,57 @@ +package io.quarkus.liquibase.test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.liquibase.LiquibaseDataSource; +import io.quarkus.liquibase.LiquibaseFactory; +import io.quarkus.test.QuarkusUnitTest; + +public class LiquibaseExtensionConfigActiveFalseNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.users.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") + // We need this otherwise it's going to be the *default* datasource making everything fail + .overrideConfigKey("quarkus.datasource.db-kind", "h2") + .overrideConfigKey("quarkus.datasource.username", "sa") + .overrideConfigKey("quarkus.datasource.password", "sa") + .overrideConfigKey("quarkus.datasource.jdbc.url", + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); + + @Inject + MyBean myBean; + + @Test + @DisplayName("If a named datasource is deactivated, the application should boot, but Liquibase should be deactivated for that datasource") + public void testBootSucceedsButLiquibaseDeactivated() { + assertThatThrownBy(myBean::useLiquibase) + .cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Liquibase", + "Datasource 'users' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"users\".active'" + + " to 'true' and configure datasource 'users'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @LiquibaseDataSource("users") + LiquibaseFactory liquibase; + + public void useLiquibase() { + liquibase.getConfiguration(); + } + } +} diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyNamedDatasourceTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyNamedDatasourceTest.java deleted file mode 100644 index 8e532e29c17a0..0000000000000 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyNamedDatasourceTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.quarkus.liquibase.test; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import jakarta.enterprise.inject.Instance; -import jakarta.enterprise.inject.UnsatisfiedResolutionException; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.liquibase.LiquibaseDataSource; -import io.quarkus.liquibase.LiquibaseFactory; -import io.quarkus.test.QuarkusUnitTest; - -public class LiquibaseExtensionConfigEmptyNamedDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - // The datasource won't be truly "unconfigured" if dev services are enabled - .overrideConfigKey("quarkus.devservices.enabled", "false") - // We need this otherwise it's going to be the *default* datasource making everything fail - .overrideConfigKey("quarkus.datasource.db-kind", "h2") - .overrideConfigKey("quarkus.datasource.username", "sa") - .overrideConfigKey("quarkus.datasource.password", "sa") - .overrideConfigKey("quarkus.datasource.jdbc.url", - "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); - @Inject - @LiquibaseDataSource("users") - Instance liquibaseForNamedDatasource; - - @Test - @DisplayName("If there is no config for a named datasource, the application should boot, but Liquibase should be deactivated for that datasource") - public void testBootSucceedsButLiquibaseDeactivated() { - assertThatThrownBy(() -> liquibaseForNamedDatasource.get().getConfiguration()) - .isInstanceOf(UnsatisfiedResolutionException.class) - .hasMessageContaining("No bean found"); - } -} diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigUrlMissingDefaultDatasourceTest.java similarity index 83% rename from extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java rename to extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigUrlMissingDefaultDatasourceTest.java index ac28eb20acf10..705a8dfc64c0e 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigEmptyDefaultDatasourceTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigUrlMissingDefaultDatasourceTest.java @@ -9,11 +9,11 @@ import io.quarkus.test.QuarkusUnitTest; -public class LiquibaseExtensionConfigEmptyDefaultDatasourceTest { +public class LiquibaseExtensionConfigUrlMissingDefaultDatasourceTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - // The datasource won't be truly "unconfigured" if dev services are enabled + // The URL won't be missing if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") .assertException(t -> assertThat(t).cause().cause() .hasMessageContainingAll("Unable to find datasource '' for Liquibase", @@ -22,7 +22,7 @@ public class LiquibaseExtensionConfigEmptyDefaultDatasourceTest { "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test - @DisplayName("If there is no config for the default datasource, the application should fail to boot") + @DisplayName("If the URL is missing for the default datasource, the application should fail to boot") public void testBootFails() { // Should not be reached because boot should fail. assertTrue(false); diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigUrlMissingNamedDatasourceTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigUrlMissingNamedDatasourceTest.java new file mode 100644 index 0000000000000..8c42d114326b9 --- /dev/null +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionConfigUrlMissingNamedDatasourceTest.java @@ -0,0 +1,39 @@ +package io.quarkus.liquibase.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class LiquibaseExtensionConfigUrlMissingNamedDatasourceTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") + // We need this otherwise it's going to be the *default* datasource making everything fail + .overrideConfigKey("quarkus.datasource.db-kind", "h2") + .overrideConfigKey("quarkus.datasource.username", "sa") + .overrideConfigKey("quarkus.datasource.password", "sa") + .overrideConfigKey("quarkus.datasource.jdbc.url", + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1") + .assertException(t -> assertThat(t).cause().cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Liquibase", + "Datasource 'users' is not configured.", + "To solve this, configure datasource 'users'.", + "Refer to https://quarkus.io/guides/datasource for guidance.")); + + @Test + @DisplayName("If the URL is missing for a named datasource, the application should fail to boot") + public void testBootSucceedsButLiquibaseDeactivated() { + // Should not be reached because boot should fail. + assertTrue(false); + } +} diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java index dccc77efe2e06..94c1e7fcfb445 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseTest.java @@ -23,12 +23,12 @@ public class LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigActiveFalseT .overrideConfigKey("quarkus.liquibase.migrate-at-start", "true"); @Inject - Instance liquibaseForDefaultDatasource; + Instance liquibase; @Test @DisplayName("If the default datasource is deactivated, even if migrate-at-start is enabled, the application should boot, but Liquibase should be deactivated for that datasource") public void testBootSucceedsButLiquibaseDeactivated() { - assertThatThrownBy(() -> liquibaseForDefaultDatasource.get().getConfiguration()) + assertThatThrownBy(() -> liquibase.get().getConfiguration()) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource '' for Liquibase", diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigUrlMissingTest.java similarity index 89% rename from extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java rename to extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigUrlMissingTest.java index bad255b85ccf3..edba6f3726165 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigUrlMissingTest.java @@ -9,14 +9,14 @@ import io.quarkus.test.QuarkusUnitTest; -public class LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest { +public class LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigUrlMissingTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() .withApplicationRoot((jar) -> jar .addAsResource("db/changeLog.xml", "db/changeLog.xml")) .overrideConfigKey("quarkus.liquibase.migrate-at-start", "true") - // The datasource won't be truly "unconfigured" if dev services are enabled + // The URL won't be missing if dev services are enabled .overrideConfigKey("quarkus.devservices.enabled", "false") .assertException(t -> assertThat(t).cause().cause() .hasMessageContainingAll("Unable to find datasource '' for Liquibase", @@ -25,7 +25,7 @@ public class LiquibaseExtensionMigrateAtStartDefaultDatasourceConfigEmptyTest { "Refer to https://quarkus.io/guides/datasource for guidance.")); @Test - @DisplayName("If there is no config for the default datasource, and if migrate-at-start is enabled, the application should fail to boot") + @DisplayName("If the URL is missing for the default datasource, and if migrate-at-start is enabled, the application should fail to boot") public void testBootFails() { // Should not be reached because boot should fail. assertTrue(false); diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java index bfc68585954d6..91e939fa9be41 100644 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTest.java @@ -34,12 +34,12 @@ public class LiquibaseExtensionMigrateAtStartNamedDatasourceConfigActiveFalseTes @Inject @LiquibaseDataSource("users") - Instance liquibaseForNamedDatasource; + Instance liquibase; @Test @DisplayName("If a named datasource is deactivated, even if migrate-at-start is enabled, the application should boot, but Liquibase should be deactivated for that datasource") public void testBootSucceedsButLiquibaseDeactivated() { - assertThatThrownBy(() -> liquibaseForNamedDatasource.get().getConfiguration()) + assertThatThrownBy(() -> liquibase.get().getConfiguration()) .isInstanceOf(CreationException.class) .cause() .hasMessageContainingAll("Unable to find datasource 'users' for Liquibase", diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigEmptyTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigEmptyTest.java deleted file mode 100644 index 3cc31a063195b..0000000000000 --- a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigEmptyTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package io.quarkus.liquibase.test; - -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import jakarta.enterprise.inject.Instance; -import jakarta.enterprise.inject.UnsatisfiedResolutionException; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.liquibase.LiquibaseDataSource; -import io.quarkus.liquibase.LiquibaseFactory; -import io.quarkus.test.QuarkusUnitTest; - -public class LiquibaseExtensionMigrateAtStartNamedDatasourceConfigEmptyTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .withApplicationRoot((jar) -> jar - .addAsResource("db/changeLog.xml", "db/changeLog.xml")) - .overrideConfigKey("quarkus.liquibase.users.migrate-at-start", "true") - // The datasource won't be truly "unconfigured" if dev services are enabled - .overrideConfigKey("quarkus.devservices.enabled", "false") - // We need this otherwise it's going to be the *default* datasource making everything fail - .overrideConfigKey("quarkus.datasource.db-kind", "h2") - .overrideConfigKey("quarkus.datasource.username", "sa") - .overrideConfigKey("quarkus.datasource.password", "sa") - .overrideConfigKey("quarkus.datasource.jdbc.url", - "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1"); - - @Inject - @LiquibaseDataSource("users") - Instance liquibaseForNamedDatasource; - - @Test - @DisplayName("If there is no config for a named datasource, even if migrate-at-start is enabled, the application should boot, but Liquibase should be deactivated for that datasource") - public void testBootSucceedsButLiquibaseDeactivated() { - assertThatThrownBy(() -> liquibaseForNamedDatasource.get().getConfiguration()) - .isInstanceOf(UnsatisfiedResolutionException.class) - .hasMessageContaining("No bean found"); - } -} diff --git a/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest.java b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest.java new file mode 100644 index 0000000000000..2ebc29ac30650 --- /dev/null +++ b/extensions/liquibase/deployment/src/test/java/io/quarkus/liquibase/test/LiquibaseExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest.java @@ -0,0 +1,42 @@ +package io.quarkus.liquibase.test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class LiquibaseExtensionMigrateAtStartNamedDatasourceConfigUrlMissingTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar + .addAsResource("db/changeLog.xml", "db/changeLog.xml")) + .overrideConfigKey("quarkus.liquibase.users.migrate-at-start", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.users.db-kind", "h2") + // We need this otherwise it's going to be the *default* datasource making everything fail + .overrideConfigKey("quarkus.datasource.db-kind", "h2") + .overrideConfigKey("quarkus.datasource.username", "sa") + .overrideConfigKey("quarkus.datasource.password", "sa") + .overrideConfigKey("quarkus.datasource.jdbc.url", + "jdbc:h2:tcp://localhost/mem:test-quarkus-migrate-at-start;DB_CLOSE_DELAY=-1") + .assertException(t -> assertThat(t).cause().cause() + .hasMessageContainingAll("Unable to find datasource 'users' for Liquibase", + "Datasource 'users' is not configured.", + "To solve this, configure datasource 'users'.", + "Refer to https://quarkus.io/guides/datasource for guidance.")); + + @Test + @DisplayName("If the URL is missing for a named datasource, and if migrate-at-start is enabled, the application should fail to boot") + public void testBootFails() { + // Should not be reached because boot should fail. + assertTrue(false); + } +} diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java index 474203b44aa08..b153b8dcd4c20 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseBuildTimeConfig.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.Map; +import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigItem; @@ -30,7 +31,9 @@ public static LiquibaseBuildTimeConfig defaultConfig() { * Gets the {@link LiquibaseBuildTimeConfig} for the given datasource name. */ public LiquibaseDataSourceBuildTimeConfig getConfigForDataSourceName(String dataSourceName) { - return namedDataSources.getOrDefault(dataSourceName, LiquibaseDataSourceBuildTimeConfig.defaultConfig()); + return DataSourceUtil.isDefault(dataSourceName) + ? defaultDataSource + : namedDataSources.getOrDefault(dataSourceName, LiquibaseDataSourceBuildTimeConfig.defaultConfig()); } /** diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java index 3d5c71c857b76..ae368b0ac4b95 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseFactoryProducer.java @@ -2,7 +2,6 @@ import javax.sql.DataSource; -import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.liquibase.LiquibaseFactory; /** @@ -28,12 +27,10 @@ public LiquibaseFactoryProducer(LiquibaseBuildTimeConfig liquibaseBuildTimeConfi } public LiquibaseFactory createLiquibaseFactory(DataSource dataSource, String dataSourceName) { - LiquibaseDataSourceBuildTimeConfig matchingBuildTimeConfig = DataSourceUtil.isDefault(dataSourceName) - ? liquibaseBuildTimeConfig.defaultDataSource - : liquibaseBuildTimeConfig.getConfigForDataSourceName(dataSourceName); - LiquibaseDataSourceRuntimeConfig matchingRuntimeConfig = DataSourceUtil.isDefault(dataSourceName) - ? liquibaseRuntimeConfig.defaultDataSource - : liquibaseRuntimeConfig.getConfigForDataSourceName(dataSourceName); + LiquibaseDataSourceBuildTimeConfig matchingBuildTimeConfig = liquibaseBuildTimeConfig + .getConfigForDataSourceName(dataSourceName); + LiquibaseDataSourceRuntimeConfig matchingRuntimeConfig = liquibaseRuntimeConfig + .getConfigForDataSourceName(dataSourceName); return new LiquibaseCreator(matchingRuntimeConfig, matchingBuildTimeConfig) .createLiquibaseFactory(dataSource, dataSourceName); } diff --git a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java index 8db555447dfc1..20f904d8c6629 100644 --- a/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java +++ b/extensions/liquibase/runtime/src/main/java/io/quarkus/liquibase/runtime/LiquibaseRuntimeConfig.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.Map; +import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigItem; @@ -28,7 +29,9 @@ public static LiquibaseRuntimeConfig defaultConfig() { * Gets the {@link LiquibaseDataSourceRuntimeConfig} for the given datasource name. */ public LiquibaseDataSourceRuntimeConfig getConfigForDataSourceName(String dataSourceName) { - return namedDataSources.getOrDefault(dataSourceName, LiquibaseDataSourceRuntimeConfig.defaultConfig()); + return DataSourceUtil.isDefault(dataSourceName) + ? defaultDataSource + : namedDataSources.getOrDefault(dataSourceName, LiquibaseDataSourceRuntimeConfig.defaultConfig()); } /** diff --git a/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/ReactiveDataSourceBuildUtil.java b/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/ReactiveDataSourceBuildUtil.java new file mode 100644 index 0000000000000..a3b822262953c --- /dev/null +++ b/extensions/reactive-datasource/deployment/src/main/java/io/quarkus/reactive/datasource/deployment/ReactiveDataSourceBuildUtil.java @@ -0,0 +1,33 @@ +package io.quarkus.reactive.datasource.deployment; + +import jakarta.enterprise.inject.Default; + +import org.jboss.jandex.AnnotationInstance; + +import io.quarkus.arc.processor.DotNames; +import io.quarkus.datasource.common.runtime.DataSourceUtil; +import io.quarkus.reactive.datasource.ReactiveDataSource; + +public final class ReactiveDataSourceBuildUtil { + private ReactiveDataSourceBuildUtil() { + } + + public static AnnotationInstance qualifier(String dataSourceName) { + if (dataSourceName == null || DataSourceUtil.isDefault(dataSourceName)) { + return AnnotationInstance.builder(Default.class).build(); + } else { + return AnnotationInstance.builder(ReactiveDataSource.class).value(dataSourceName).build(); + } + } + + public static AnnotationInstance[] qualifiers(String dataSourceName) { + if (DataSourceUtil.isDefault(dataSourceName)) { + return new AnnotationInstance[] { AnnotationInstance.builder(Default.class).build() }; + } else { + return new AnnotationInstance[] { + AnnotationInstance.builder(DotNames.NAMED).value(dataSourceName).build(), + AnnotationInstance.builder(ReactiveDataSource.class).value(dataSourceName).build(), + }; + } + } +} diff --git a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDataSourceUtil.java b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDataSourceUtil.java new file mode 100644 index 0000000000000..19302697524ef --- /dev/null +++ b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDataSourceUtil.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.datasource.runtime; + +import java.lang.annotation.Annotation; + +import jakarta.enterprise.inject.Default; +import jakarta.enterprise.inject.spi.Bean; + +import io.quarkus.datasource.common.runtime.DataSourceUtil; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.vertx.sqlclient.Pool; + +public final class ReactiveDataSourceUtil { + private ReactiveDataSourceUtil() { + } + + public static String dataSourceName(Bean bean) { + for (Object qualifier : bean.getQualifiers()) { + if (qualifier instanceof ReactiveDataSource) { + return ((ReactiveDataSource) qualifier).value(); + } + } + return DataSourceUtil.DEFAULT_DATASOURCE_NAME; + } + + public static Annotation qualifier(String dataSourceName) { + if (DataSourceUtil.isDefault(dataSourceName)) { + return Default.Literal.INSTANCE; + } else { + return new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName); + } + } +} diff --git a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java index 840dec97bd7e7..722c2a19712ad 100644 --- a/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java +++ b/extensions/reactive-datasource/runtime/src/main/java/io/quarkus/reactive/datasource/runtime/ReactiveDatasourceHealthCheck.java @@ -14,8 +14,6 @@ import org.eclipse.microprofile.health.HealthCheckResponseBuilder; import org.jboss.logging.Logger; -import io.quarkus.datasource.common.runtime.DataSourceUtil; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.vertx.core.AsyncResult; import io.vertx.core.Context; import io.vertx.core.Vertx; @@ -109,13 +107,12 @@ private void checkFailure(AsyncResult> ar, HealthCheckResponseBuilde } } - protected String getPoolName(Bean bean) { - for (Object qualifier : bean.getQualifiers()) { - if (qualifier instanceof ReactiveDataSource) { - return ((ReactiveDataSource) qualifier).value(); - } - } - return DataSourceUtil.DEFAULT_DATASOURCE_NAME; + /** + * @deprecated Use {@link ReactiveDataSourceUtil#dataSourceName(Bean)} instead. + */ + @Deprecated + protected String getPoolName(Bean bean) { + return ReactiveDataSourceUtil.dataSourceName(bean); } } diff --git a/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java b/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java index a56deb4a8ecec..b3b14dfec16a9 100644 --- a/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java +++ b/extensions/reactive-db2-client/deployment/src/main/java/io/quarkus/reactive/db2/client/deployment/ReactiveDB2ClientProcessor.java @@ -1,5 +1,8 @@ package io.quarkus.reactive.db2.client.deployment; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifier; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifiers; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +29,6 @@ import io.quarkus.arc.deployment.ValidationPhaseBuildItem; import io.quarkus.arc.deployment.devui.Name; import io.quarkus.arc.processor.BeanInfo; -import io.quarkus.arc.processor.DotNames; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.datasource.common.runtime.DatabaseKind; import io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem; @@ -48,7 +50,6 @@ import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.deployment.VertxPoolBuildItem; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveBuildTimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveBuildTimeConfig; @@ -68,9 +69,6 @@ class ReactiveDB2ClientProcessor { private static final ParameterizedType POOL_CREATOR_INJECTION_TYPE = ParameterizedType.create( DotName.createSimple(Instance.class), new Type[] { ClassType.create(DotName.createSimple(DB2PoolCreator.class.getName())) }, null); - private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0]; - - private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class); private static final DotName VERTX_DB2_POOL = DotName.createSimple(DB2Pool.class); private static final Type VERTX_DB2_POOL_TYPE = Type.create(VERTX_DB2_POOL, Type.Kind.CLASS); @@ -212,14 +210,13 @@ private void createPoolIfDefined(DB2PoolRecorder recorder, .defaultBean() .addType(Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(poolFunction) .unremovable() .setRuntimeInit(); - addQualifiers(db2PoolBeanConfigurator, dataSourceName); - syntheticBeans.produce(db2PoolBeanConfigurator.done()); ExtendedBeanConfigurator mutinyDB2PoolConfigurator = SyntheticBeanBuildItem @@ -227,25 +224,16 @@ private void createPoolIfDefined(DB2PoolRecorder recorder, .defaultBean() .addType(io.vertx.mutiny.sqlclient.Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(VERTX_DB2_POOL_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(VERTX_DB2_POOL_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(recorder.mutinyDB2Pool(dataSourceName)) .unremovable() .setRuntimeInit(); - addQualifiers(mutinyDB2PoolConfigurator, dataSourceName); - syntheticBeans.produce(mutinyDB2PoolConfigurator.done()); } - private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return EMPTY_ANNOTATIONS; - } - return new AnnotationInstance[] { - AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() }; - } - private static boolean isReactiveDB2PoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, DataSourcesReactiveBuildTimeConfig dataSourcesReactiveBuildTimeConfig, String dataSourceName, List defaultDataSourceDbKindBuildItems, @@ -292,16 +280,6 @@ private boolean hasPools(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, return false; } - private static void addQualifiers(ExtendedBeanConfigurator configurator, String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - configurator.addQualifier(DotNames.DEFAULT); - } else { - configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", dataSourceName).done(); - configurator.addQualifier().annotation(ReactiveDataSource.class).addValue("value", dataSourceName) - .done(); - } - } - private static class DB2PoolCreatorBeanClassPredicate implements Predicate> { private static final Type DB2_POOL_CREATOR = Type.create(DotName.createSimple(DB2PoolCreator.class.getName()), Type.Kind.CLASS); diff --git a/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java b/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java index df15e717770c0..f755605237783 100644 --- a/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java +++ b/extensions/reactive-db2-client/runtime/src/main/java/io/quarkus/reactive/db2/client/runtime/DB2PoolRecorder.java @@ -2,6 +2,7 @@ import static io.quarkus.credentials.CredentialsProvider.PASSWORD_PROPERTY_NAME; import static io.quarkus.credentials.CredentialsProvider.USER_PROPERTY_NAME; +import static io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil.qualifier; import static io.quarkus.reactive.datasource.runtime.UnitisedTime.unitised; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksTrustOptions; @@ -10,13 +11,11 @@ import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxTrustOptions; -import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.util.TypeLiteral; @@ -29,7 +28,6 @@ import io.quarkus.datasource.runtime.DataSourceRuntimeConfig; import io.quarkus.datasource.runtime.DataSourceSupport; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.runtime.ConnectOptionsSupplier; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveRuntimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveRuntimeConfig; @@ -79,28 +77,19 @@ public DB2Pool apply(SyntheticCreationalContext context) { public Function, io.vertx.mutiny.db2client.DB2Pool> mutinyDB2Pool( String dataSourceName) { return new Function<>() { - @SuppressWarnings("unchecked") @Override - public io.vertx.mutiny.db2client.DB2Pool apply(SyntheticCreationalContext context) { + public io.vertx.mutiny.db2client.DB2Pool apply( + SyntheticCreationalContext context) { DataSourceSupport datasourceSupport = (DataSourceSupport) context.getInjectedReference(DataSourceSupport.class); if (datasourceSupport.getInactiveNames().contains(dataSourceName)) { throw DataSourceUtil.dataSourceInactive(dataSourceName); } - DB2Pool db2Pool = (DB2Pool) context.getInjectedReference(DB2Pool.class, - getReactiveDataSourceQualifier(dataSourceName)); + DB2Pool db2Pool = context.getInjectedReference(DB2Pool.class, qualifier(dataSourceName)); return io.vertx.mutiny.db2client.DB2Pool.newInstance(db2Pool); } }; } - private static Annotation getReactiveDataSourceQualifier(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return Default.Literal.INSTANCE; - } - - return new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName); - } - private DB2Pool initialize(VertxInternal vertx, Integer eventLoopCount, String dataSourceName, @@ -254,13 +243,7 @@ private DB2ConnectOptions toConnectOptions(String dataSourceName, DataSourceRunt private DB2Pool createPool(Vertx vertx, PoolOptions poolOptions, DB2ConnectOptions dB2ConnectOptions, String dataSourceName, Supplier> databases, SyntheticCreationalContext context) { - Instance instance; - if (DataSourceUtil.isDefault(dataSourceName)) { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL); - } else { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, - new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName)); - } + Instance instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, qualifier(dataSourceName)); if (instance.isResolvable()) { DB2PoolCreator.Input input = new DefaultInput(vertx, poolOptions, dB2ConnectOptions); return instance.get().create(input); diff --git a/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java b/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java index f181091fd72f8..32eb30d69feb7 100644 --- a/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java +++ b/extensions/reactive-mssql-client/deployment/src/main/java/io/quarkus/reactive/mssql/client/deployment/ReactiveMSSQLClientProcessor.java @@ -1,5 +1,8 @@ package io.quarkus.reactive.mssql.client.deployment; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifier; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifiers; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +29,6 @@ import io.quarkus.arc.deployment.ValidationPhaseBuildItem; import io.quarkus.arc.deployment.devui.Name; import io.quarkus.arc.processor.BeanInfo; -import io.quarkus.arc.processor.DotNames; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.datasource.common.runtime.DatabaseKind; import io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem; @@ -48,7 +50,6 @@ import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.deployment.VertxPoolBuildItem; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveBuildTimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveBuildTimeConfig; @@ -68,8 +69,6 @@ class ReactiveMSSQLClientProcessor { private static final ParameterizedType POOL_CREATOR_INJECTION_TYPE = ParameterizedType.create( DotName.createSimple(Instance.class), new Type[] { ClassType.create(DotName.createSimple(MSSQLPoolCreator.class.getName())) }, null); - private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0]; - private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class); private static final DotName VERTX_MSSQL_POOL = DotName.createSimple(MSSQLPool.class); private static final Type VERTX_MSSQL_POOL_TYPE = Type.create(VERTX_MSSQL_POOL, Type.Kind.CLASS); @@ -210,14 +209,13 @@ private void createPoolIfDefined(MSSQLPoolRecorder recorder, .defaultBean() .addType(Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(poolFunction) .unremovable() .setRuntimeInit(); - addQualifiers(msSQLPoolBeanConfigurator, dataSourceName); - syntheticBeans.produce(msSQLPoolBeanConfigurator.done()); ExtendedBeanConfigurator mutinyMSSQLPoolConfigurator = SyntheticBeanBuildItem @@ -225,25 +223,16 @@ private void createPoolIfDefined(MSSQLPoolRecorder recorder, .defaultBean() .addType(io.vertx.mutiny.sqlclient.Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(VERTX_MSSQL_POOL_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(VERTX_MSSQL_POOL_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(recorder.mutinyMSSQLPool(dataSourceName)) .unremovable() .setRuntimeInit(); - addQualifiers(mutinyMSSQLPoolConfigurator, dataSourceName); - syntheticBeans.produce(mutinyMSSQLPoolConfigurator.done()); } - private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return EMPTY_ANNOTATIONS; - } - return new AnnotationInstance[] { - AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() }; - } - private static boolean isReactiveMSSQLPoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, DataSourcesReactiveBuildTimeConfig dataSourcesReactiveBuildTimeConfig, String dataSourceName, List defaultDataSourceDbKindBuildItems, @@ -289,16 +278,6 @@ private boolean hasPools(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, return false; } - private static void addQualifiers(ExtendedBeanConfigurator configurator, String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - configurator.addQualifier(DotNames.DEFAULT); - } else { - configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", dataSourceName).done(); - configurator.addQualifier().annotation(ReactiveDataSource.class).addValue("value", dataSourceName) - .done(); - } - } - private static class MSSQLPoolCreatorBeanClassPredicate implements Predicate> { private static final Type MSSQL_POOL_CREATOR = Type.create(DotName.createSimple(MSSQLPoolCreator.class.getName()), Type.Kind.CLASS); diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..46661dc547901 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,75 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mssqlclient.MSSQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckConfigActiveFalseTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java similarity index 58% rename from extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckConfigActiveFalseTest.java rename to extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java index 08f702e03f64d..4f1c66304616c 100644 --- a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/DataSourceHealthCheckConfigActiveFalseTest.java +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java @@ -7,24 +7,23 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DataSourceHealthCheckConfigActiveFalseTest { +public class ConfigActiveFalseDefaultDatasourceHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withEmptyApplication() - .withConfigurationResource("application-default-datasource.properties") .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.active", "false") // this data source is broken, but will be deactivated, // so the overall check should pass - .overrideConfigKey("quarkus.datasource.brokenDS.db-kind", "mssql") - .overrideConfigKey("quarkus.datasource.brokenDS.reactive.url", "BROKEN") - .overrideConfigKey("quarkus.datasource.brokenDS.active", "false"); + .overrideConfigKey("quarkus.datasource.reactive.url", "BROKEN"); @Test public void testDataSourceHealthCheckExclusion() { RestAssured.when().get("/q/health/ready") .then() - .body("status", CoreMatchers.equalTo("UP")); + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"\"", CoreMatchers.nullValue()); } } diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..a13418fb0050d --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,49 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceTest.java deleted file mode 100644 index 8ad9fbeb363d6..0000000000000 --- a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseDefaultDatasourceTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package io.quarkus.reactive.mssql.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.mssqlclient.MSSQLPool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseDefaultDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.active", "false"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - MSSQLPool pool = Arc.container().instance(MSSQLPool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.mssqlclient.MSSQLPool pool = Arc.container().instance(io.vertx.mutiny.mssqlclient.MSSQLPool.class) - .get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..4754d0888cae4 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,82 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mssqlclient.MSSQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..1f6b4aa776aa3 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.mssql.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigActiveFalseNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql") + // this data source is broken, but will be deactivated, + // so the overall check should pass + .overrideConfigKey("quarkus.datasource.ds-1.reactive.url", "BROKEN"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"users\"", CoreMatchers.nullValue()); + } + +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..ff80fe8b84745 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,54 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceTest.java deleted file mode 100644 index 352e3bb17086f..0000000000000 --- a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigActiveFalseNamedDatasourceTest.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.quarkus.reactive.mssql.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.reactive.datasource.ReactiveDataSource; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.mssqlclient.MSSQLPool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseNamedDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.ds-1.active", "false") - // We need at least one build-time property for the datasource, - // otherwise it's considered unconfigured at build time... - .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - MSSQLPool pool = Arc.container().instance(MSSQLPool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.mssqlclient.MSSQLPool pool = Arc.container().instance(io.vertx.mutiny.mssqlclient.MSSQLPool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - @ReactiveDataSource("ds-1") - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..c6f64d2b4ab73 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,68 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mssqlclient.MSSQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, MSSQLPool -> MSSQLPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, MSSQLPool -> MSSQLPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(ConnectException.class); + } +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..bc8f8cd210979 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java @@ -0,0 +1,29 @@ +package io.quarkus.reactive.mssql.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingDefaultDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.\"\"", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..1171055d4838e --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,46 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(ConnectException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..3d715cc0148b2 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,76 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mssqlclient.MSSQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, MSSQLPool -> MSSQLPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, MSSQLPool -> MSSQLPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(ConnectException.class); + } +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..74fcd4f25744b --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.mssql.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.ds-1", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..f231af8cb0d16 --- /dev/null +++ b/extensions/reactive-mssql-client/deployment/src/test/java/io/quarkus/reactive/mssql/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,51 @@ +package io.quarkus.reactive.mssql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mssql"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(ConnectException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java b/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java index 5e83d38e83701..f90fd0326dc4a 100644 --- a/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java +++ b/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/MSSQLPoolRecorder.java @@ -2,6 +2,7 @@ import static io.quarkus.credentials.CredentialsProvider.PASSWORD_PROPERTY_NAME; import static io.quarkus.credentials.CredentialsProvider.USER_PROPERTY_NAME; +import static io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil.qualifier; import static io.quarkus.reactive.datasource.runtime.UnitisedTime.unitised; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksTrustOptions; @@ -10,13 +11,11 @@ import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxTrustOptions; -import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.util.TypeLiteral; @@ -29,7 +28,6 @@ import io.quarkus.datasource.runtime.DataSourceRuntimeConfig; import io.quarkus.datasource.runtime.DataSourceSupport; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.runtime.ConnectOptionsSupplier; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveRuntimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveRuntimeConfig; @@ -93,20 +91,11 @@ public io.vertx.mutiny.mssqlclient.MSSQLPool apply(SyntheticCreationalContext co } return io.vertx.mutiny.mssqlclient.MSSQLPool.newInstance( - (MSSQLPool) context.getInjectedReference(MSSQLPool.class, - getReactiveDataSourceQualifier(dataSourceName))); + (MSSQLPool) context.getInjectedReference(MSSQLPool.class, qualifier(dataSourceName))); } }; } - private static Annotation getReactiveDataSourceQualifier(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return Default.Literal.INSTANCE; - } - - return new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName); - } - private MSSQLPool initialize(VertxInternal vertx, Integer eventLoopCount, String dataSourceName, DataSourceRuntimeConfig dataSourceRuntimeConfig, @@ -258,13 +247,8 @@ private MSSQLConnectOptions toMSSQLConnectOptions(String dataSourceName, DataSou private MSSQLPool createPool(Vertx vertx, PoolOptions poolOptions, MSSQLConnectOptions mSSQLConnectOptions, String dataSourceName, Supplier> databases, SyntheticCreationalContext context) { - Instance instance; - if (DataSourceUtil.isDefault(dataSourceName)) { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL); - } else { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, - new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName)); - } + Instance instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, + qualifier(dataSourceName)); if (instance.isResolvable()) { MSSQLPoolCreator.Input input = new DefaultInput(vertx, poolOptions, mSSQLConnectOptions); return instance.get().create(input); diff --git a/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/health/ReactiveMSSQLDataSourcesHealthCheck.java b/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/health/ReactiveMSSQLDataSourcesHealthCheck.java index a9a2c28a34685..d56c9a7a01350 100644 --- a/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/health/ReactiveMSSQLDataSourcesHealthCheck.java +++ b/extensions/reactive-mssql-client/runtime/src/main/java/io/quarkus/reactive/mssql/client/runtime/health/ReactiveMSSQLDataSourcesHealthCheck.java @@ -12,6 +12,7 @@ import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InstanceHandle; import io.quarkus.datasource.runtime.DataSourceSupport; +import io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil; import io.quarkus.reactive.datasource.runtime.ReactiveDatasourceHealthCheck; import io.vertx.mssqlclient.MSSQLPool; @@ -29,7 +30,7 @@ protected void init() { DataSourceSupport support = container.instance(DataSourceSupport.class).get(); Set excludedNames = support.getInactiveOrHealthCheckExcludedNames(); for (InstanceHandle handle : container.select(MSSQLPool.class, Any.Literal.INSTANCE).handles()) { - String poolName = getPoolName(handle.getBean()); + String poolName = ReactiveDataSourceUtil.dataSourceName(handle.getBean()); if (!excludedNames.contains(poolName)) { addPool(poolName, handle.get()); } diff --git a/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java b/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java index e2e679dfc042c..ad51699bda129 100644 --- a/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java +++ b/extensions/reactive-mysql-client/deployment/src/main/java/io/quarkus/reactive/mysql/client/deployment/ReactiveMySQLClientProcessor.java @@ -1,5 +1,8 @@ package io.quarkus.reactive.mysql.client.deployment; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifier; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifiers; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +29,6 @@ import io.quarkus.arc.deployment.ValidationPhaseBuildItem; import io.quarkus.arc.deployment.devui.Name; import io.quarkus.arc.processor.BeanInfo; -import io.quarkus.arc.processor.DotNames; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.datasource.common.runtime.DatabaseKind; import io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem; @@ -48,7 +50,6 @@ import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.deployment.VertxPoolBuildItem; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveBuildTimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveBuildTimeConfig; @@ -68,8 +69,6 @@ class ReactiveMySQLClientProcessor { private static final ParameterizedType POOL_CREATOR_INJECTION_TYPE = ParameterizedType.create( DotName.createSimple(Instance.class), new Type[] { ClassType.create(DotName.createSimple(MySQLPoolCreator.class.getName())) }, null); - private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0]; - private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class); private static final DotName VERTX_MYSQL_POOL = DotName.createSimple(MySQLPool.class); private static final Type VERTX_MYSQL_POOL_TYPE = Type.create(VERTX_MYSQL_POOL, Type.Kind.CLASS); @@ -211,14 +210,13 @@ private void createPoolIfDefined(MySQLPoolRecorder recorder, .defaultBean() .addType(Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(poolFunction) .unremovable() .setRuntimeInit(); - addQualifiers(mySQLPoolBeanConfigurator, dataSourceName); - syntheticBeans.produce(mySQLPoolBeanConfigurator.done()); ExtendedBeanConfigurator mutinyMySQLPoolConfigurator = SyntheticBeanBuildItem @@ -226,25 +224,16 @@ private void createPoolIfDefined(MySQLPoolRecorder recorder, .defaultBean() .addType(io.vertx.mutiny.sqlclient.Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(VERTX_MYSQL_POOL_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(VERTX_MYSQL_POOL_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(recorder.mutinyMySQLPool(dataSourceName)) .unremovable() .setRuntimeInit(); - addQualifiers(mutinyMySQLPoolConfigurator, dataSourceName); - syntheticBeans.produce(mutinyMySQLPoolConfigurator.done()); } - private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return EMPTY_ANNOTATIONS; - } - return new AnnotationInstance[] { - AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() }; - } - private static boolean isReactiveMySQLPoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, DataSourcesReactiveBuildTimeConfig dataSourcesReactiveBuildTimeConfig, String dataSourceName, List defaultDataSourceDbKindBuildItems, @@ -291,16 +280,6 @@ private boolean hasPools(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, return false; } - private static void addQualifiers(ExtendedBeanConfigurator configurator, String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - configurator.addQualifier(DotNames.DEFAULT); - } else { - configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", dataSourceName).done(); - configurator.addQualifier().annotation(ReactiveDataSource.class).addValue("value", dataSourceName) - .done(); - } - } - private static class MySQLPoolCreatorBeanClassPredicate implements Predicate> { private static final Type MYSQL_POOL_CREATOR = Type.create(DotName.createSimple(MySQLPoolCreator.class.getName()), Type.Kind.CLASS); diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..cd586106c9846 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,75 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mysqlclient.MySQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckConfigActiveFalseTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java similarity index 58% rename from extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckConfigActiveFalseTest.java rename to extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java index 40f9830df3787..ca55c8fd072de 100644 --- a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/DataSourceHealthCheckConfigActiveFalseTest.java +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java @@ -7,24 +7,23 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DataSourceHealthCheckConfigActiveFalseTest { +public class ConfigActiveFalseDefaultDatasourceHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withEmptyApplication() - .withConfigurationResource("application-default-datasource.properties") .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.active", "false") // this data source is broken, but will be deactivated, // so the overall check should pass - .overrideConfigKey("quarkus.datasource.brokenDS.db-kind", "mysql") - .overrideConfigKey("quarkus.datasource.brokenDS.reactive.url", "BROKEN") - .overrideConfigKey("quarkus.datasource.brokenDS.active", "false"); + .overrideConfigKey("quarkus.datasource.reactive.url", "BROKEN"); @Test public void testDataSourceHealthCheckExclusion() { RestAssured.when().get("/q/health/ready") .then() - .body("status", CoreMatchers.equalTo("UP")); + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"\"", CoreMatchers.nullValue()); } } diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..1aab5a2a7e964 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,49 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceTest.java deleted file mode 100644 index 0a7e67f1f6fe1..0000000000000 --- a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseDefaultDatasourceTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package io.quarkus.reactive.mysql.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.mysqlclient.MySQLPool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseDefaultDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.active", "false"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - MySQLPool pool = Arc.container().instance(MySQLPool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.mysqlclient.MySQLPool pool = Arc.container().instance(io.vertx.mutiny.mysqlclient.MySQLPool.class) - .get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..5f32384ea0807 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,82 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mysqlclient.MySQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..a8482821f7a05 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.mysql.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigActiveFalseNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql") + // this data source is broken, but will be deactivated, + // so the overall check should pass + .overrideConfigKey("quarkus.datasource.ds-1.reactive.url", "BROKEN"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"users\"", CoreMatchers.nullValue()); + } + +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..233909063e4f6 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,54 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceTest.java deleted file mode 100644 index 5a6ba912c67cd..0000000000000 --- a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigActiveFalseNamedDatasourceTest.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.quarkus.reactive.mysql.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.reactive.datasource.ReactiveDataSource; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.mysqlclient.MySQLPool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseNamedDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.ds-1.active", "false") - // We need at least one build-time property for the datasource, - // otherwise it's considered unconfigured at build time... - .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - MySQLPool pool = Arc.container().instance(MySQLPool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.mysqlclient.MySQLPool pool = Arc.container().instance(io.vertx.mutiny.mysqlclient.MySQLPool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - @ReactiveDataSource("ds-1") - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..2f877897ba059 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,68 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mysqlclient.MySQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, MYSQLPool -> MYSQLPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, MYSQLPool -> MYSQLPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(ConnectException.class); + } +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..0c68d63a3a3c1 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java @@ -0,0 +1,29 @@ +package io.quarkus.reactive.mysql.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingDefaultDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.\"\"", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..206b61928b60a --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,46 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(ConnectException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..09e8a178ef59e --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,76 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.mysqlclient.MySQLPool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, mySQLPool -> mySQLPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, mySQLPool -> mySQLPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(ConnectException.class); + } +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..23b7e93b73cf4 --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.mysql.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.ds-1", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..defb3ea36062f --- /dev/null +++ b/extensions/reactive-mysql-client/deployment/src/test/java/io/quarkus/reactive/mysql/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,51 @@ +package io.quarkus.reactive.mysql.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "mysql"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(ConnectException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java index 87e331c35dd5f..7585d52e36a93 100644 --- a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java +++ b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/MySQLPoolRecorder.java @@ -2,6 +2,7 @@ import static io.quarkus.credentials.CredentialsProvider.PASSWORD_PROPERTY_NAME; import static io.quarkus.credentials.CredentialsProvider.USER_PROPERTY_NAME; +import static io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil.qualifier; import static io.quarkus.reactive.datasource.runtime.UnitisedTime.unitised; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksTrustOptions; @@ -10,7 +11,6 @@ import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxTrustOptions; -import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -18,7 +18,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.util.TypeLiteral; @@ -29,7 +28,6 @@ import io.quarkus.datasource.runtime.DataSourceRuntimeConfig; import io.quarkus.datasource.runtime.DataSourceSupport; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.runtime.ConnectOptionsSupplier; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveRuntimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveRuntimeConfig; @@ -87,20 +85,11 @@ public io.vertx.mutiny.mysqlclient.MySQLPool apply(SyntheticCreationalContext co throw DataSourceUtil.dataSourceInactive(dataSourceName); } return io.vertx.mutiny.mysqlclient.MySQLPool.newInstance( - (MySQLPool) context.getInjectedReference(MySQLPool.class, - getReactiveDataSourceQualifier(dataSourceName))); + (MySQLPool) context.getInjectedReference(MySQLPool.class, qualifier(dataSourceName))); } }; } - private static Annotation getReactiveDataSourceQualifier(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return Default.Literal.INSTANCE; - } - - return new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName); - } - private MySQLPool initialize(VertxInternal vertx, Integer eventLoopCount, String dataSourceName, @@ -276,13 +265,8 @@ private List toMySQLConnectOptions(String dataSourceName, private MySQLPool createPool(Vertx vertx, PoolOptions poolOptions, List mySQLConnectOptionsList, String dataSourceName, Supplier> databases, SyntheticCreationalContext context) { - Instance instance; - if (DataSourceUtil.isDefault(dataSourceName)) { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL); - } else { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, - new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName)); - } + Instance instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, + qualifier(dataSourceName)); if (instance.isResolvable()) { MySQLPoolCreator.Input input = new DefaultInput(vertx, poolOptions, mySQLConnectOptionsList); return instance.get().create(input); diff --git a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/health/ReactiveMySQLDataSourcesHealthCheck.java b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/health/ReactiveMySQLDataSourcesHealthCheck.java index 656d585acce53..1e4218856b7c9 100644 --- a/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/health/ReactiveMySQLDataSourcesHealthCheck.java +++ b/extensions/reactive-mysql-client/runtime/src/main/java/io/quarkus/reactive/mysql/client/runtime/health/ReactiveMySQLDataSourcesHealthCheck.java @@ -12,6 +12,7 @@ import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InstanceHandle; import io.quarkus.datasource.runtime.DataSourceSupport; +import io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil; import io.quarkus.reactive.datasource.runtime.ReactiveDatasourceHealthCheck; import io.vertx.mysqlclient.MySQLPool; @@ -29,7 +30,7 @@ protected void init() { DataSourceSupport support = container.instance(DataSourceSupport.class).get(); Set excludedNames = support.getInactiveOrHealthCheckExcludedNames(); for (InstanceHandle handle : container.select(MySQLPool.class, Any.Literal.INSTANCE).handles()) { - String poolName = getPoolName(handle.getBean()); + String poolName = ReactiveDataSourceUtil.dataSourceName(handle.getBean()); if (!excludedNames.contains(poolName)) { addPool(poolName, handle.get()); } diff --git a/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java b/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java index 0ad7ba26e1887..fb178117dc6a7 100644 --- a/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java +++ b/extensions/reactive-oracle-client/deployment/src/main/java/io/quarkus/reactive/oracle/client/deployment/ReactiveOracleClientProcessor.java @@ -1,5 +1,8 @@ package io.quarkus.reactive.oracle.client.deployment; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifier; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifiers; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +29,6 @@ import io.quarkus.arc.deployment.ValidationPhaseBuildItem; import io.quarkus.arc.deployment.devui.Name; import io.quarkus.arc.processor.BeanInfo; -import io.quarkus.arc.processor.DotNames; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.datasource.common.runtime.DatabaseKind; import io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem; @@ -48,7 +50,6 @@ import io.quarkus.deployment.builditem.ShutdownContextBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.deployment.VertxPoolBuildItem; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveBuildTimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveBuildTimeConfig; @@ -68,8 +69,6 @@ class ReactiveOracleClientProcessor { private static final ParameterizedType POOL_CREATOR_INJECTION_TYPE = ParameterizedType.create( DotName.createSimple(Instance.class), new Type[] { ClassType.create(DotName.createSimple(OraclePoolCreator.class.getName())) }, null); - private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0]; - private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class); private static final DotName VERTX_ORACLE_POOL = DotName.createSimple(OraclePool.class); private static final Type VERTX_ORACLE_POOL_TYPE = Type.create(VERTX_ORACLE_POOL, Type.Kind.CLASS); @@ -212,14 +211,13 @@ private void createPoolIfDefined(OraclePoolRecorder recorder, .defaultBean() .addType(Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(poolFunction) .unremovable() .setRuntimeInit(); - addQualifiers(oraclePoolBeanConfigurator, dataSourceName); - syntheticBeans.produce(oraclePoolBeanConfigurator.done()); ExtendedBeanConfigurator mutinyOraclePoolConfigurator = SyntheticBeanBuildItem @@ -227,25 +225,16 @@ private void createPoolIfDefined(OraclePoolRecorder recorder, .defaultBean() .addType(io.vertx.mutiny.sqlclient.Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(VERTX_ORACLE_POOL_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(VERTX_ORACLE_POOL_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(recorder.mutinyOraclePool(dataSourceName)) .unremovable() .setRuntimeInit(); - addQualifiers(mutinyOraclePoolConfigurator, dataSourceName); - syntheticBeans.produce(mutinyOraclePoolConfigurator.done()); } - private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return EMPTY_ANNOTATIONS; - } - return new AnnotationInstance[] { - AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() }; - } - private static boolean isReactiveOraclePoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, DataSourcesReactiveBuildTimeConfig dataSourcesReactiveBuildTimeConfig, String dataSourceName, List defaultDataSourceDbKindBuildItems, @@ -291,16 +280,6 @@ private boolean hasPools(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, return false; } - private static void addQualifiers(ExtendedBeanConfigurator configurator, String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - configurator.addQualifier(DotNames.DEFAULT); - } else { - configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", dataSourceName).done(); - configurator.addQualifier().annotation(ReactiveDataSource.class).addValue("value", dataSourceName) - .done(); - } - } - private static class OraclePoolCreatorBeanClassPredicate implements Predicate> { private static final Type ORACLE_POOL_CREATOR = Type.create(DotName.createSimple(OraclePoolCreator.class.getName()), Type.Kind.CLASS); diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..08164d6c1416b --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,75 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.oracleclient.OraclePool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckConfigActiveFalseTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java similarity index 58% rename from extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckConfigActiveFalseTest.java rename to extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java index 7791728100211..562a1b56dc94d 100644 --- a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/DataSourceHealthCheckConfigActiveFalseTest.java +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java @@ -7,24 +7,23 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DataSourceHealthCheckConfigActiveFalseTest { +public class ConfigActiveFalseDefaultDatasourceHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withEmptyApplication() - .withConfigurationResource("application-default-datasource.properties") .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.active", "false") // this data source is broken, but will be deactivated, // so the overall check should pass - .overrideConfigKey("quarkus.datasource.brokenDS.db-kind", "oracle") - .overrideConfigKey("quarkus.datasource.brokenDS.reactive.url", "BROKEN") - .overrideConfigKey("quarkus.datasource.brokenDS.active", "false"); + .overrideConfigKey("quarkus.datasource.reactive.url", "BROKEN"); @Test public void testDataSourceHealthCheckExclusion() { RestAssured.when().get("/q/health/ready") .then() - .body("status", CoreMatchers.equalTo("UP")); + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"\"", CoreMatchers.nullValue()); } } diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..5d8f5b37e1f3e --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,49 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceTest.java deleted file mode 100644 index d71964ecbf67d..0000000000000 --- a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseDefaultDatasourceTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package io.quarkus.reactive.oracle.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.oracleclient.OraclePool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseDefaultDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.active", "false"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - OraclePool pool = Arc.container().instance(OraclePool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.oracleclient.OraclePool pool = Arc.container().instance(io.vertx.mutiny.oracleclient.OraclePool.class) - .get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..5ad96d83652d9 --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,82 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.oracleclient.OraclePool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..9636be1efdfd0 --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.oracle.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigActiveFalseNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle") + // this data source is broken, but will be deactivated, + // so the overall check should pass + .overrideConfigKey("quarkus.datasource.ds-1.reactive.url", "BROKEN"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"users\"", CoreMatchers.nullValue()); + } + +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..03d07806c6b91 --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,54 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceTest.java deleted file mode 100644 index 546c7179e563a..0000000000000 --- a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigActiveFalseNamedDatasourceTest.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.quarkus.reactive.oracle.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.reactive.datasource.ReactiveDataSource; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.oracleclient.OraclePool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseNamedDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.ds-1.active", "false") - // We need at least one build-time property for the datasource, - // otherwise it's considered unconfigured at build time... - .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - OraclePool pool = Arc.container().instance(OraclePool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.oracleclient.OraclePool pool = Arc.container().instance(io.vertx.mutiny.oracleclient.OraclePool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - @ReactiveDataSource("ds-1") - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..da9d012753aa6 --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,68 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.oracleclient.OracleException; +import io.vertx.oracleclient.OraclePool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, ORACLEPool -> ORACLEPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, ORACLEPool -> ORACLEPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(OracleException.class); + } +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..d7fb1b8bdef00 --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java @@ -0,0 +1,29 @@ +package io.quarkus.reactive.oracle.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingDefaultDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.\"\"", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..1abbc848c5b9e --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,46 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.oracleclient.OracleException; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(OracleException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..b143a597a0657 --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,76 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.oracleclient.OracleException; +import io.vertx.oracleclient.OraclePool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, oraclePool -> oraclePool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, oraclePool -> oraclePool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(OracleException.class); + } +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..0857ac9fb261d --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.oracle.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.ds-1", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..754a96aac352e --- /dev/null +++ b/extensions/reactive-oracle-client/deployment/src/test/java/io/quarkus/reactive/oracle/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,51 @@ +package io.quarkus.reactive.oracle.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.oracleclient.OracleException; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "oracle"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(OracleException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java b/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java index 6e3b9a831fe83..907493aaa1efc 100644 --- a/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java +++ b/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/OraclePoolRecorder.java @@ -2,15 +2,14 @@ import static io.quarkus.credentials.CredentialsProvider.PASSWORD_PROPERTY_NAME; import static io.quarkus.credentials.CredentialsProvider.USER_PROPERTY_NAME; +import static io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil.qualifier; import static io.quarkus.reactive.datasource.runtime.UnitisedTime.unitised; -import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.util.TypeLiteral; @@ -23,7 +22,6 @@ import io.quarkus.datasource.runtime.DataSourceRuntimeConfig; import io.quarkus.datasource.runtime.DataSourceSupport; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.runtime.ConnectOptionsSupplier; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveRuntimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveRuntimeConfig; @@ -83,20 +81,11 @@ public io.vertx.mutiny.oracleclient.OraclePool apply(SyntheticCreationalContext throw DataSourceUtil.dataSourceInactive(dataSourceName); } return io.vertx.mutiny.oracleclient.OraclePool.newInstance( - (OraclePool) context.getInjectedReference(OraclePool.class, - getReactiveDataSourceQualifier(dataSourceName))); + (OraclePool) context.getInjectedReference(OraclePool.class, qualifier(dataSourceName))); } }; } - private static Annotation getReactiveDataSourceQualifier(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return Default.Literal.INSTANCE; - } - - return new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName); - } - private OraclePool initialize(VertxInternal vertx, Integer eventLoopCount, String dataSourceName, @@ -225,13 +214,8 @@ private OracleConnectOptions toOracleConnectOptions(String dataSourceName, DataS private OraclePool createPool(Vertx vertx, PoolOptions poolOptions, OracleConnectOptions oracleConnectOptions, String dataSourceName, Supplier> databases, SyntheticCreationalContext context) { - Instance instance; - if (DataSourceUtil.isDefault(dataSourceName)) { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL); - } else { - instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, - new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName)); - } + Instance instance = context.getInjectedReference(POOL_CREATOR_TYPE_LITERAL, + qualifier(dataSourceName)); if (instance.isResolvable()) { OraclePoolCreator.Input input = new DefaultInput(vertx, poolOptions, oracleConnectOptions); return instance.get().create(input); diff --git a/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/health/ReactiveOracleDataSourcesHealthCheck.java b/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/health/ReactiveOracleDataSourcesHealthCheck.java index cc3370616f4eb..797b703cb1ef8 100644 --- a/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/health/ReactiveOracleDataSourcesHealthCheck.java +++ b/extensions/reactive-oracle-client/runtime/src/main/java/io/quarkus/reactive/oracle/client/runtime/health/ReactiveOracleDataSourcesHealthCheck.java @@ -12,6 +12,7 @@ import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InstanceHandle; import io.quarkus.datasource.runtime.DataSourceSupport; +import io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil; import io.quarkus.reactive.datasource.runtime.ReactiveDatasourceHealthCheck; import io.vertx.oracleclient.OraclePool; @@ -29,7 +30,7 @@ protected void init() { DataSourceSupport support = container.instance(DataSourceSupport.class).get(); Set excludedNames = support.getInactiveOrHealthCheckExcludedNames(); for (InstanceHandle handle : container.select(OraclePool.class, Any.Literal.INSTANCE).handles()) { - String poolName = getPoolName(handle.getBean()); + String poolName = ReactiveDataSourceUtil.dataSourceName(handle.getBean()); if (!excludedNames.contains(poolName)) { addPool(poolName, handle.get()); } diff --git a/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java b/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java index 66894cc1fc4b6..b97f2b082b5e0 100644 --- a/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java +++ b/extensions/reactive-pg-client/deployment/src/main/java/io/quarkus/reactive/pg/client/deployment/ReactivePgClientProcessor.java @@ -1,5 +1,8 @@ package io.quarkus.reactive.pg.client.deployment; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifier; +import static io.quarkus.reactive.datasource.deployment.ReactiveDataSourceBuildUtil.qualifiers; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -26,7 +29,6 @@ import io.quarkus.arc.deployment.ValidationPhaseBuildItem; import io.quarkus.arc.deployment.devui.Name; import io.quarkus.arc.processor.BeanInfo; -import io.quarkus.arc.processor.DotNames; import io.quarkus.datasource.common.runtime.DataSourceUtil; import io.quarkus.datasource.common.runtime.DatabaseKind; import io.quarkus.datasource.deployment.spi.DefaultDataSourceDbKindBuildItem; @@ -49,7 +51,6 @@ import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem; import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.deployment.VertxPoolBuildItem; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveBuildTimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveBuildTimeConfig; @@ -69,8 +70,6 @@ class ReactivePgClientProcessor { private static final ParameterizedType POOL_CREATOR_INJECTION_TYPE = ParameterizedType.create( DotName.createSimple(Instance.class), new Type[] { ClassType.create(DotName.createSimple(PgPoolCreator.class.getName())) }, null); - private static final AnnotationInstance[] EMPTY_ANNOTATIONS = new AnnotationInstance[0]; - private static final DotName REACTIVE_DATASOURCE = DotName.createSimple(ReactiveDataSource.class); private static final DotName VERTX_PG_POOL = DotName.createSimple(PgPool.class); private static final Type VERTX_PG_POOL_TYPE = Type.create(VERTX_PG_POOL, Type.Kind.CLASS); @@ -216,14 +215,13 @@ private void createPoolIfDefined(PgPoolRecorder recorder, .defaultBean() .addType(Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(POOL_CREATOR_INJECTION_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(poolFunction) .unremovable() .setRuntimeInit(); - addQualifiers(pgPoolBeanConfigurator, dataSourceName); - syntheticBeans.produce(pgPoolBeanConfigurator.done()); // the Mutiny pool is created by using the Vertx pool @@ -232,25 +230,16 @@ private void createPoolIfDefined(PgPoolRecorder recorder, .defaultBean() .addType(io.vertx.mutiny.sqlclient.Pool.class) .scope(ApplicationScoped.class) - .addInjectionPoint(VERTX_PG_POOL_TYPE, injectionPointAnnotations(dataSourceName)) + .qualifiers(qualifiers(dataSourceName)) + .addInjectionPoint(VERTX_PG_POOL_TYPE, qualifier(dataSourceName)) .addInjectionPoint(ClassType.create(DataSourceSupport.class)) .createWith(recorder.mutinyPgPool(dataSourceName)) .unremovable() .setRuntimeInit(); - addQualifiers(mutinyPgPoolConfigurator, dataSourceName); - syntheticBeans.produce(mutinyPgPoolConfigurator.done()); } - private AnnotationInstance[] injectionPointAnnotations(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return EMPTY_ANNOTATIONS; - } - return new AnnotationInstance[] { - AnnotationInstance.builder(REACTIVE_DATASOURCE).add("value", dataSourceName).build() }; - } - private static boolean isReactivePostgreSQLPoolDefined(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, DataSourcesReactiveBuildTimeConfig dataSourcesReactiveBuildTimeConfig, String dataSourceName, List defaultDataSourceDbKindBuildItems, @@ -297,16 +286,6 @@ private boolean hasPools(DataSourcesBuildTimeConfig dataSourcesBuildTimeConfig, return false; } - private static void addQualifiers(ExtendedBeanConfigurator configurator, String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - configurator.addQualifier(DotNames.DEFAULT); - } else { - configurator.addQualifier().annotation(DotNames.NAMED).addValue("value", dataSourceName).done(); - configurator.addQualifier().annotation(ReactiveDataSource.class).addValue("value", dataSourceName) - .done(); - } - } - private static class PgPoolCreatorBeanClassPredicate implements Predicate> { private static final Type PG_POOL_CREATOR = Type.create(DotName.createSimple(PgPoolCreator.class.getName()), Type.Kind.CLASS); diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..02db403659cdd --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,75 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.pgclient.PgPool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckConfigActiveFalseTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java similarity index 58% rename from extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckConfigActiveFalseTest.java rename to extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java index 1b9c7d61639ff..a2f594622fd6c 100644 --- a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/DataSourceHealthCheckConfigActiveFalseTest.java +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceHealthCheckTest.java @@ -7,24 +7,23 @@ import io.quarkus.test.QuarkusUnitTest; import io.restassured.RestAssured; -public class DataSourceHealthCheckConfigActiveFalseTest { +public class ConfigActiveFalseDefaultDatasourceHealthCheckTest { @RegisterExtension static final QuarkusUnitTest config = new QuarkusUnitTest() - .withEmptyApplication() - .withConfigurationResource("application-default-datasource.properties") .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.active", "false") // this data source is broken, but will be deactivated, // so the overall check should pass - .overrideConfigKey("quarkus.datasource.brokenDS.db-kind", "postgresql") - .overrideConfigKey("quarkus.datasource.brokenDS.reactive.url", "BROKEN") - .overrideConfigKey("quarkus.datasource.brokenDS.active", "false"); + .overrideConfigKey("quarkus.datasource.reactive.url", "BROKEN"); @Test public void testDataSourceHealthCheckExclusion() { RestAssured.when().get("/q/health/ready") .then() - .body("status", CoreMatchers.equalTo("UP")); + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"\"", CoreMatchers.nullValue()); } } diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..ccfaf9aab951f --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,49 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.active", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" + + " to 'true' and configure datasource ''", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceTest.java deleted file mode 100644 index 8dbb1f8094e8a..0000000000000 --- a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseDefaultDatasourceTest.java +++ /dev/null @@ -1,133 +0,0 @@ -package io.quarkus.reactive.pg.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseDefaultDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.active", "false"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - PgPool pool = Arc.container().instance(PgPool.class).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.pgclient.PgPool pool = Arc.container().instance(io.vertx.mutiny.pgclient.PgPool.class) - .get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource '' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.active'" - + " to 'true' and configure datasource ''", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..3c3f1aed3969e --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,82 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.pgclient.PgPool; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "postgresql"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, Pool::getConnection); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + @Test + public void vendorPool() { + doTest(vendorPool, Pool::getConnection); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, io.vertx.mutiny.sqlclient.Pool::getConnection); + } + + private void doTest(InjectableInstance instance, Consumer action) { + // The bean is always available to be injected during static init + // since we don't know whether the datasource will be active at runtime. + // So the bean proxy cannot be null. + var pool = instance.get(); + assertThat(pool).isNotNull(); + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> action.accept(pool)) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..8a176414a55a1 --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.pg.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigActiveFalseNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "pg") + // this data source is broken, but will be deactivated, + // so the overall check should pass + .overrideConfigKey("quarkus.datasource.ds-1.reactive.url", "BROKEN"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + .body("status", CoreMatchers.equalTo("UP")) + // If the datasource is inactive, there should not be a health check + .body("checks[0].data.\"users\"", CoreMatchers.nullValue()); + } + +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..7201f116fa02c --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,54 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.runtime.configuration.ConfigurationException; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigActiveFalseNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.ds-1.active", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "postgresql"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // However, any attempt to use it at runtime will fail. + assertThatThrownBy(() -> myBean.usePool()) + .isInstanceOf(RuntimeException.class) + .cause() + .isInstanceOf(ConfigurationException.class) + .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", + "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", + "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" + + " to 'true' and configure datasource 'ds-1'", + "Refer to https://quarkus.io/guides/datasource for guidance."); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage(); + } + } +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceTest.java deleted file mode 100644 index e40b129e6cabd..0000000000000 --- a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigActiveFalseNamedDatasourceTest.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.quarkus.reactive.pg.client; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.concurrent.CompletionStage; - -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Inject; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import io.quarkus.arc.Arc; -import io.quarkus.reactive.datasource.ReactiveDataSource; -import io.quarkus.runtime.configuration.ConfigurationException; -import io.quarkus.test.QuarkusUnitTest; -import io.vertx.pgclient.PgPool; -import io.vertx.sqlclient.Pool; - -public class ConfigActiveFalseNamedDatasourceTest { - - @RegisterExtension - static final QuarkusUnitTest config = new QuarkusUnitTest() - .overrideConfigKey("quarkus.datasource.ds-1.active", "false") - // We need at least one build-time property for the datasource, - // otherwise it's considered unconfigured at build time... - .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "postgresql"); - - @Inject - MyBean myBean; - - @Test - public void pool() { - Pool pool = Arc.container().instance(Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyPool() { - io.vertx.mutiny.sqlclient.Pool pool = Arc.container().instance(io.vertx.mutiny.sqlclient.Pool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void vendorPool() { - PgPool pool = Arc.container().instance(PgPool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void mutinyVendorPool() { - io.vertx.mutiny.pgclient.PgPool pool = Arc.container().instance(io.vertx.mutiny.pgclient.PgPool.class, - new ReactiveDataSource.ReactiveDataSourceLiteral("ds-1")).get(); - - // The bean is always available to be injected during static init - // since we don't know whether the datasource will be active at runtime. - // So the bean cannot be null. - assertThat(pool).isNotNull(); - // However, any attempt to use it at runtime will fail. - assertThatThrownBy(() -> pool.getConnection()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @Test - public void injectedBean() { - assertThatThrownBy(() -> myBean.usePool()) - .isInstanceOf(RuntimeException.class) - .cause() - .isInstanceOf(ConfigurationException.class) - .hasMessageContainingAll("Datasource 'ds-1' was deactivated through configuration properties.", - "To solve this, avoid accessing this datasource at runtime, for instance by deactivating consumers (persistence units, ...).", - "Alternatively, activate the datasource by setting configuration property 'quarkus.datasource.\"ds-1\".active'" - + " to 'true' and configure datasource 'ds-1'", - "Refer to https://quarkus.io/guides/datasource for guidance."); - } - - @ApplicationScoped - public static class MyBean { - @Inject - @ReactiveDataSource("ds-1") - Pool pool; - - public CompletionStage usePool() { - return pool.getConnection().toCompletionStage(); - } - } -} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..a6b2517b3c305 --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceDynamicInjectionTest.java @@ -0,0 +1,68 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.pgclient.PgPool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + InjectableInstance pool; + + @Inject + InjectableInstance mutinyPool; + + @Inject + InjectableInstance vendorPool; + + @Inject + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, PGPool -> PGPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, PGPool -> PGPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(ConnectException.class); + } +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..dde82b176d34e --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceHealthCheckTest.java @@ -0,0 +1,29 @@ +package io.quarkus.reactive.pg.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingDefaultDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.\"\"", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..56d3c2cda7224 --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingDefaultDatasourceStaticInjectionTest.java @@ -0,0 +1,46 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingDefaultDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(ConnectException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java new file mode 100644 index 0000000000000..fd28bc7ac09a3 --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceDynamicInjectionTest.java @@ -0,0 +1,76 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.function.Consumer; + +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.arc.InjectableInstance; +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.pgclient.PgPool; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceDynamicInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "pg"); + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance pool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance vendorPool; + + @Inject + @ReactiveDataSource("ds-1") + InjectableInstance mutinyVendorPool; + + @Test + public void pool() { + doTest(pool, pool1 -> pool1.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyPool() { + doTest(mutinyPool, pool1 -> pool1.getConnection().subscribe().asCompletionStage().join()); + } + + @Test + public void vendorPool() { + doTest(vendorPool, pgPool -> pgPool.getConnection().toCompletionStage().toCompletableFuture().join()); + } + + @Test + public void mutinyVendorPool() { + doTest(mutinyVendorPool, pgPool -> pgPool.getConnection().subscribe().asCompletionStage().join()); + } + + private void doTest(InjectableInstance instance, Consumer action) { + var pool = instance.get(); + assertThat(pool).isNotNull(); + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> action.accept(pool)) + .cause() + .isInstanceOf(ConnectException.class); + } +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java new file mode 100644 index 0000000000000..e345e322d925d --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceHealthCheckTest.java @@ -0,0 +1,32 @@ +package io.quarkus.reactive.pg.client; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.restassured.RestAssured; + +public class ConfigUrlMissingNamedDatasourceHealthCheckTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .overrideConfigKey("quarkus.datasource.health.enabled", "true") + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "pg"); + + @Test + public void testDataSourceHealthCheckExclusion() { + RestAssured.when().get("/q/health/ready") + .then() + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a failing health check. + .body("status", CoreMatchers.equalTo("DOWN")) + .body("checks[0].data.ds-1", CoreMatchers.startsWithIgnoringCase("DOWN")); + } + +} diff --git a/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java new file mode 100644 index 0000000000000..9dbc5069db523 --- /dev/null +++ b/extensions/reactive-pg-client/deployment/src/test/java/io/quarkus/reactive/pg/client/ConfigUrlMissingNamedDatasourceStaticInjectionTest.java @@ -0,0 +1,51 @@ +package io.quarkus.reactive.pg.client; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.net.ConnectException; +import java.util.concurrent.CompletionStage; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.reactive.datasource.ReactiveDataSource; +import io.quarkus.test.QuarkusUnitTest; +import io.vertx.sqlclient.Pool; + +public class ConfigUrlMissingNamedDatasourceStaticInjectionTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + // The URL won't be missing if dev services are enabled + .overrideConfigKey("quarkus.devservices.enabled", "false") + // We need at least one build-time property for the datasource, + // otherwise it's considered unconfigured at build time... + .overrideConfigKey("quarkus.datasource.ds-1.db-kind", "pg"); + + @Inject + MyBean myBean; + + @Test + public void test() { + // When the URL is missing, the client assumes a default one. + // See https://github.com/quarkusio/quarkus/issues/43517 + // In this case the default won't work, resulting in a connection exception. + assertThatThrownBy(() -> myBean.usePool().toCompletableFuture().join()) + .cause() + .isInstanceOf(ConnectException.class); + } + + @ApplicationScoped + public static class MyBean { + @Inject + @ReactiveDataSource("ds-1") + Pool pool; + + public CompletionStage usePool() { + return pool.getConnection().toCompletionStage().toCompletableFuture(); + } + } +} diff --git a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java index 0658058a59d21..4c49c78c87e2c 100644 --- a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java +++ b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/PgPoolRecorder.java @@ -2,6 +2,7 @@ import static io.quarkus.credentials.CredentialsProvider.PASSWORD_PROPERTY_NAME; import static io.quarkus.credentials.CredentialsProvider.USER_PROPERTY_NAME; +import static io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil.qualifier; import static io.quarkus.reactive.datasource.runtime.UnitisedTime.unitised; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configureJksTrustOptions; @@ -10,14 +11,12 @@ import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxKeyCertOptions; import static io.quarkus.vertx.core.runtime.SSLConfigHelper.configurePfxTrustOptions; -import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; -import jakarta.enterprise.inject.Default; import jakarta.enterprise.inject.Instance; import jakarta.enterprise.util.TypeLiteral; @@ -28,7 +27,6 @@ import io.quarkus.datasource.runtime.DataSourceRuntimeConfig; import io.quarkus.datasource.runtime.DataSourceSupport; import io.quarkus.datasource.runtime.DataSourcesRuntimeConfig; -import io.quarkus.reactive.datasource.ReactiveDataSource; import io.quarkus.reactive.datasource.runtime.ConnectOptionsSupplier; import io.quarkus.reactive.datasource.runtime.DataSourceReactiveRuntimeConfig; import io.quarkus.reactive.datasource.runtime.DataSourcesReactiveRuntimeConfig; @@ -87,19 +85,11 @@ public io.vertx.mutiny.pgclient.PgPool apply(SyntheticCreationalContext context) } return io.vertx.mutiny.pgclient.PgPool.newInstance( - (PgPool) context.getInjectedReference(PgPool.class, getReactiveDataSourceQualifier(dataSourceName))); + (PgPool) context.getInjectedReference(PgPool.class, qualifier(dataSourceName))); } }; } - private static Annotation getReactiveDataSourceQualifier(String dataSourceName) { - if (DataSourceUtil.isDefault(dataSourceName)) { - return Default.Literal.INSTANCE; - } - - return new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName); - } - private PgPool initialize(VertxInternal vertx, Integer eventLoopCount, String dataSourceName, @@ -265,13 +255,8 @@ private List toPgConnectOptions(String dataSourceName, DataSou private PgPool createPool(Vertx vertx, PoolOptions poolOptions, List pgConnectOptionsList, String dataSourceName, Supplier> databases, SyntheticCreationalContext context) { - Instance instance; - if (DataSourceUtil.isDefault(dataSourceName)) { - instance = context.getInjectedReference(PG_POOL_CREATOR_TYPE_LITERAL); - } else { - instance = context.getInjectedReference(PG_POOL_CREATOR_TYPE_LITERAL, - new ReactiveDataSource.ReactiveDataSourceLiteral(dataSourceName)); - } + Instance instance = context.getInjectedReference(PG_POOL_CREATOR_TYPE_LITERAL, + qualifier(dataSourceName)); if (instance.isResolvable()) { PgPoolCreator.Input input = new DefaultInput(vertx, poolOptions, pgConnectOptionsList); return instance.get().create(input); diff --git a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/health/ReactivePgDataSourcesHealthCheck.java b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/health/ReactivePgDataSourcesHealthCheck.java index 9cfc47a61dc2a..3adf20310f7d8 100644 --- a/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/health/ReactivePgDataSourcesHealthCheck.java +++ b/extensions/reactive-pg-client/runtime/src/main/java/io/quarkus/reactive/pg/client/runtime/health/ReactivePgDataSourcesHealthCheck.java @@ -12,6 +12,7 @@ import io.quarkus.arc.ArcContainer; import io.quarkus.arc.InstanceHandle; import io.quarkus.datasource.runtime.DataSourceSupport; +import io.quarkus.reactive.datasource.runtime.ReactiveDataSourceUtil; import io.quarkus.reactive.datasource.runtime.ReactiveDatasourceHealthCheck; import io.vertx.pgclient.PgPool; @@ -29,7 +30,7 @@ protected void init() { DataSourceSupport support = container.instance(DataSourceSupport.class).get(); Set excludedNames = support.getInactiveOrHealthCheckExcludedNames(); for (InstanceHandle handle : container.select(PgPool.class, Any.Literal.INSTANCE).handles()) { - String poolName = getPoolName(handle.getBean()); + String poolName = ReactiveDataSourceUtil.dataSourceName(handle.getBean()); if (!excludedNames.contains(poolName)) { addPool(poolName, handle.get()); }