Promote ConnectionFactoryBuilder to the "spring-boot" module
Closes gh-25492pull/25377/head
parent
9ba2cd3be7
commit
54e7d7f060
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.autoconfigure.r2dbc;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import io.r2dbc.spi.ConnectionFactoryOptions;
|
||||||
|
import io.r2dbc.spi.ConnectionFactoryOptions.Builder;
|
||||||
|
import io.r2dbc.spi.Option;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.boot.r2dbc.EmbeddedDatabaseConnection;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a {@link ConnectionFactoryOptions.Builder} based on {@link R2dbcProperties}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
class ConnectionFactoryOptionsInitializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a {@link io.r2dbc.spi.ConnectionFactoryOptions.Builder
|
||||||
|
* ConnectionFactoryOptions.Builder} using the specified properties.
|
||||||
|
* @param properties the properties to use to initialize the builder
|
||||||
|
* @param embeddedDatabaseConnection the embedded connection to use as a fallback
|
||||||
|
* @return an initialized builder
|
||||||
|
* @throws ConnectionFactoryBeanCreationException if no suitable connection could be
|
||||||
|
* determined
|
||||||
|
*/
|
||||||
|
ConnectionFactoryOptions.Builder initialize(R2dbcProperties properties,
|
||||||
|
Supplier<EmbeddedDatabaseConnection> embeddedDatabaseConnection) {
|
||||||
|
if (StringUtils.hasText(properties.getUrl())) {
|
||||||
|
return initializeRegularOptions(properties);
|
||||||
|
}
|
||||||
|
EmbeddedDatabaseConnection embeddedConnection = embeddedDatabaseConnection.get();
|
||||||
|
if (embeddedConnection != EmbeddedDatabaseConnection.NONE) {
|
||||||
|
return initializeEmbeddedOptions(properties, embeddedConnection);
|
||||||
|
}
|
||||||
|
throw connectionFactoryBeanCreationException("Failed to determine a suitable R2DBC Connection URL", properties,
|
||||||
|
embeddedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionFactoryOptions.Builder initializeRegularOptions(R2dbcProperties properties) {
|
||||||
|
ConnectionFactoryOptions urlOptions = ConnectionFactoryOptions.parse(properties.getUrl());
|
||||||
|
Builder optionsBuilder = urlOptions.mutate();
|
||||||
|
configureIf(optionsBuilder, urlOptions, ConnectionFactoryOptions.USER, properties::getUsername,
|
||||||
|
StringUtils::hasText);
|
||||||
|
configureIf(optionsBuilder, urlOptions, ConnectionFactoryOptions.PASSWORD, properties::getPassword,
|
||||||
|
StringUtils::hasText);
|
||||||
|
configureIf(optionsBuilder, urlOptions, ConnectionFactoryOptions.DATABASE,
|
||||||
|
() -> determineDatabaseName(properties), StringUtils::hasText);
|
||||||
|
if (properties.getProperties() != null) {
|
||||||
|
properties.getProperties().forEach((key, value) -> optionsBuilder.option(Option.valueOf(key), value));
|
||||||
|
}
|
||||||
|
return optionsBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Builder initializeEmbeddedOptions(R2dbcProperties properties,
|
||||||
|
EmbeddedDatabaseConnection embeddedDatabaseConnection) {
|
||||||
|
String url = embeddedDatabaseConnection.getUrl(determineEmbeddedDatabaseName(properties));
|
||||||
|
if (url == null) {
|
||||||
|
throw connectionFactoryBeanCreationException("Failed to determine a suitable R2DBC Connection URL",
|
||||||
|
properties, embeddedDatabaseConnection);
|
||||||
|
}
|
||||||
|
Builder builder = ConnectionFactoryOptions.parse(url).mutate();
|
||||||
|
String username = determineEmbeddedUsername(properties);
|
||||||
|
if (StringUtils.hasText(username)) {
|
||||||
|
builder.option(ConnectionFactoryOptions.USER, username);
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(properties.getPassword())) {
|
||||||
|
builder.option(ConnectionFactoryOptions.PASSWORD, properties.getPassword());
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineDatabaseName(R2dbcProperties properties) {
|
||||||
|
if (properties.isGenerateUniqueName()) {
|
||||||
|
return properties.determineUniqueName();
|
||||||
|
}
|
||||||
|
if (StringUtils.hasLength(properties.getName())) {
|
||||||
|
return properties.getName();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineEmbeddedDatabaseName(R2dbcProperties properties) {
|
||||||
|
String databaseName = determineDatabaseName(properties);
|
||||||
|
return (databaseName != null) ? databaseName : "testdb";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String determineEmbeddedUsername(R2dbcProperties properties) {
|
||||||
|
String username = ifHasText(properties.getUsername());
|
||||||
|
return (username != null) ? username : "sa";
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends CharSequence> void configureIf(Builder optionsBuilder, ConnectionFactoryOptions originalOptions,
|
||||||
|
Option<T> option, Supplier<T> valueSupplier, Predicate<T> setIf) {
|
||||||
|
if (originalOptions.hasOption(option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
T value = valueSupplier.get();
|
||||||
|
if (setIf.test(value)) {
|
||||||
|
optionsBuilder.option(option, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionFactoryBeanCreationException connectionFactoryBeanCreationException(String message,
|
||||||
|
R2dbcProperties properties, EmbeddedDatabaseConnection embeddedDatabaseConnection) {
|
||||||
|
return new ConnectionFactoryBeanCreationException(message, properties, embeddedDatabaseConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String ifHasText(String candidate) {
|
||||||
|
return (StringUtils.hasText(candidate)) ? candidate : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ConnectionFactoryBeanCreationException extends BeanCreationException {
|
||||||
|
|
||||||
|
private final R2dbcProperties properties;
|
||||||
|
|
||||||
|
private final EmbeddedDatabaseConnection embeddedDatabaseConnection;
|
||||||
|
|
||||||
|
ConnectionFactoryBeanCreationException(String message, R2dbcProperties properties,
|
||||||
|
EmbeddedDatabaseConnection embeddedDatabaseConnection) {
|
||||||
|
super(message);
|
||||||
|
this.properties = properties;
|
||||||
|
this.embeddedDatabaseConnection = embeddedDatabaseConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
EmbeddedDatabaseConnection getEmbeddedDatabaseConnection() {
|
||||||
|
return this.embeddedDatabaseConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
R2dbcProperties getProperties() {
|
||||||
|
return this.properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.r2dbc;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import io.r2dbc.spi.ConnectionFactories;
|
||||||
|
import io.r2dbc.spi.ConnectionFactory;
|
||||||
|
import io.r2dbc.spi.ConnectionFactoryOptions;
|
||||||
|
import io.r2dbc.spi.ConnectionFactoryOptions.Builder;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builder for {@link ConnectionFactory}.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @author Tadaya Tsuyukubo
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public final class ConnectionFactoryBuilder {
|
||||||
|
|
||||||
|
private final Builder optionsBuilder;
|
||||||
|
|
||||||
|
private ConnectionFactoryBuilder(Builder optionsBuilder) {
|
||||||
|
this.optionsBuilder = optionsBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new {@link ConnectionFactoryBuilder} based on the specified R2DBC url.
|
||||||
|
* @param url the url to use
|
||||||
|
* @return a new builder initialized with the options exposed in the specified url
|
||||||
|
* @see EmbeddedDatabaseConnection#getUrl(String)
|
||||||
|
*/
|
||||||
|
public static ConnectionFactoryBuilder withUrl(String url) {
|
||||||
|
Assert.hasText(url, () -> "Url must not be null");
|
||||||
|
return withOptions(ConnectionFactoryOptions.parse(url).mutate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new {@link ConnectionFactoryBuilder} based on the specified
|
||||||
|
* {@link Builder options}.
|
||||||
|
* @param options the options to use to initialize the builder
|
||||||
|
* @return a new builder initialized with the settings defined in the given
|
||||||
|
* {@link Builder options}
|
||||||
|
*/
|
||||||
|
public static ConnectionFactoryBuilder withOptions(Builder options) {
|
||||||
|
return new ConnectionFactoryBuilder(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure additional options.
|
||||||
|
* @param options a {@link Consumer} to customize the options
|
||||||
|
* @return this for method chaining
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryBuilder configure(Consumer<Builder> options) {
|
||||||
|
options.accept(this.optionsBuilder);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the {@linkplain ConnectionFactoryOptions#USER username}.
|
||||||
|
* @param username the connection factory username
|
||||||
|
* @return this for method chaining
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryBuilder username(String username) {
|
||||||
|
return configure((options) -> options.option(ConnectionFactoryOptions.USER, username));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the {@linkplain ConnectionFactoryOptions#PASSWORD password}.
|
||||||
|
* @param password the connection factory password
|
||||||
|
* @return this for method chaining
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryBuilder password(CharSequence password) {
|
||||||
|
return configure((options) -> options.option(ConnectionFactoryOptions.PASSWORD, password));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the {@linkplain ConnectionFactoryOptions#HOST host name}.
|
||||||
|
* @param host the connection factory hostname
|
||||||
|
* @return this for method chaining
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryBuilder hostname(String host) {
|
||||||
|
return configure((options) -> options.option(ConnectionFactoryOptions.HOST, host));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the {@linkplain ConnectionFactoryOptions#PORT port}.
|
||||||
|
* @param port the connection factory port
|
||||||
|
* @return this for method chaining
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryBuilder port(int port) {
|
||||||
|
return configure((options) -> options.option(ConnectionFactoryOptions.PORT, port));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the {@linkplain ConnectionFactoryOptions#DATABASE database}.
|
||||||
|
* @param database the connection factory database
|
||||||
|
* @return this for method chaining
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryBuilder database(String database) {
|
||||||
|
return configure((options) -> options.option(ConnectionFactoryOptions.DATABASE, database));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link ConnectionFactory} based on the state of this builder.
|
||||||
|
* @return a connection factory
|
||||||
|
*/
|
||||||
|
public ConnectionFactory build() {
|
||||||
|
return ConnectionFactories.get(buildOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link ConnectionFactoryOptions} based on the state of this builder.
|
||||||
|
* @return the options
|
||||||
|
*/
|
||||||
|
public ConnectionFactoryOptions buildOptions() {
|
||||||
|
return this.optionsBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.r2dbc;
|
||||||
|
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connection details for embedded databases compatible with r2dbc.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 2.5.0
|
||||||
|
*/
|
||||||
|
public enum EmbeddedDatabaseConnection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No Connection.
|
||||||
|
*/
|
||||||
|
NONE(null, null),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* H2 Database Connection.
|
||||||
|
*/
|
||||||
|
H2("io.r2dbc.h2.H2ConnectionFactoryProvider",
|
||||||
|
"r2dbc:h2:mem:///%s?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
|
||||||
|
|
||||||
|
private final String driverClassName;
|
||||||
|
|
||||||
|
private final String url;
|
||||||
|
|
||||||
|
EmbeddedDatabaseConnection(String driverClassName, String url) {
|
||||||
|
this.driverClassName = driverClassName;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the driver class name.
|
||||||
|
* @return the driver class name
|
||||||
|
*/
|
||||||
|
public String getDriverClassName() {
|
||||||
|
return this.driverClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the R2DBC URL for the connection using the specified {@code databaseName}.
|
||||||
|
* @param databaseName the name of the database
|
||||||
|
* @return the connection URL
|
||||||
|
*/
|
||||||
|
public String getUrl(String databaseName) {
|
||||||
|
Assert.hasText(databaseName, "DatabaseName must not be empty");
|
||||||
|
return (this.url != null) ? String.format(this.url, databaseName) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the most suitable {@link EmbeddedDatabaseConnection} for the given class
|
||||||
|
* loader.
|
||||||
|
* @param classLoader the class loader used to check for classes
|
||||||
|
* @return an {@link EmbeddedDatabaseConnection} or {@link #NONE}.
|
||||||
|
*/
|
||||||
|
public static EmbeddedDatabaseConnection get(ClassLoader classLoader) {
|
||||||
|
for (EmbeddedDatabaseConnection candidate : EmbeddedDatabaseConnection.values()) {
|
||||||
|
if (candidate != NONE && ClassUtils.isPresent(candidate.getDriverClassName(), classLoader)) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for R2DBC connectivity.
|
||||||
|
*/
|
||||||
|
package org.springframework.boot.r2dbc;
|
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.r2dbc;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import io.r2dbc.h2.H2ConnectionFactoryMetadata;
|
||||||
|
import io.r2dbc.spi.ConnectionFactory;
|
||||||
|
import io.r2dbc.spi.ConnectionFactoryOptions;
|
||||||
|
import io.r2dbc.spi.Option;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ConnectionFactoryBuilder}.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @author Tadaya Tsuyukubo
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
class ConnectionFactoryBuilderTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createWithNullUrlShouldFail() {
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> ConnectionFactoryBuilder.withUrl(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createWithEmptyUrlShouldFail() {
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> ConnectionFactoryBuilder.withUrl(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createWithEmbeddedConnectionNoneShouldFail() {
|
||||||
|
assertThatIllegalArgumentException()
|
||||||
|
.isThrownBy(() -> ConnectionFactoryBuilder.withUrl(EmbeddedDatabaseConnection.NONE.getUrl("test")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildOptionsWithBasicUrlShouldExposeOptions() {
|
||||||
|
ConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl("r2dbc:simple://:pool:").buildOptions();
|
||||||
|
assertThat(options.hasOption(ConnectionFactoryOptions.USER)).isFalse();
|
||||||
|
assertThat(options.hasOption(ConnectionFactoryOptions.PASSWORD)).isFalse();
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo("simple");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildOptionsWithEmbeddedConnectionH2ShouldExposeOptions() {
|
||||||
|
ConnectionFactoryOptions options = ConnectionFactoryBuilder
|
||||||
|
.withUrl(EmbeddedDatabaseConnection.H2.getUrl("testdb")).buildOptions();
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo("h2");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL)).isEqualTo("mem");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo("testdb");
|
||||||
|
assertThat(options.hasOption(ConnectionFactoryOptions.HOST)).isFalse();
|
||||||
|
assertThat(options.hasOption(ConnectionFactoryOptions.PORT)).isFalse();
|
||||||
|
assertThat(options.hasOption(ConnectionFactoryOptions.USER)).isFalse();
|
||||||
|
assertThat(options.hasOption(ConnectionFactoryOptions.PASSWORD)).isFalse();
|
||||||
|
assertThat(options.getValue(Option.<String>valueOf("options")))
|
||||||
|
.isEqualTo("DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildOptionsWithCompleteUrlShouldExposeOptions() {
|
||||||
|
ConnectionFactoryOptions options = ConnectionFactoryBuilder
|
||||||
|
.withUrl("r2dbc:simple:proto://user:password@myhost:4711/mydatabase").buildOptions();
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.DRIVER)).isEqualTo("simple");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.PROTOCOL)).isEqualTo("proto");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo("user");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo("password");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.HOST)).isEqualTo("myhost");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.PORT)).isEqualTo(4711);
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo("mydatabase");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildOptionsWithSpecificSettingsShouldOverrideUrlOptions() {
|
||||||
|
ConnectionFactoryOptions options = ConnectionFactoryBuilder
|
||||||
|
.withUrl("r2dbc:simple://user:password@myhost/mydatabase").username("another-user")
|
||||||
|
.password("another-password").hostname("another-host").port(1234).database("another-database")
|
||||||
|
.buildOptions();
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.USER)).isEqualTo("another-user");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo("another-password");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.HOST)).isEqualTo("another-host");
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.PORT)).isEqualTo(1234);
|
||||||
|
assertThat(options.getRequiredValue(ConnectionFactoryOptions.DATABASE)).isEqualTo("another-database");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildOptionsWithDriverPropertiesShouldExposeOptions() {
|
||||||
|
ConnectionFactoryOptions options = ConnectionFactoryBuilder.withUrl("r2dbc:simple://user:password@myhost")
|
||||||
|
.configure(
|
||||||
|
(o) -> o.option(Option.valueOf("simpleOne"), "one").option(Option.valueOf("simpleTwo"), "two"))
|
||||||
|
.buildOptions();
|
||||||
|
assertThat(options.getRequiredValue(Option.<String>valueOf("simpleOne"))).isEqualTo("one");
|
||||||
|
assertThat(options.getRequiredValue(Option.<String>valueOf("simpleTwo"))).isEqualTo("two");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void buildShouldExposeConnectionFactory() {
|
||||||
|
String databaseName = UUID.randomUUID().toString();
|
||||||
|
ConnectionFactory connectionFactory = ConnectionFactoryBuilder
|
||||||
|
.withUrl(EmbeddedDatabaseConnection.H2.getUrl(databaseName)).build();
|
||||||
|
assertThat(connectionFactory).isNotNull();
|
||||||
|
assertThat(connectionFactory.getMetadata().getName()).isEqualTo(H2ConnectionFactoryMetadata.NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.r2dbc;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link EmbeddedDatabaseConnection}.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
*/
|
||||||
|
class EmbeddedDatabaseConnectionTests {
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("urlParameters")
|
||||||
|
void getUrlWithTestDatabase(EmbeddedDatabaseConnection connection, String expectUrl) {
|
||||||
|
assertThat(connection.getUrl("test-database")).isEqualTo(expectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getReturnsH2ByDefault() {
|
||||||
|
assertThat(EmbeddedDatabaseConnection.get(EmbeddedDatabaseConnectionTests.class.getClassLoader()))
|
||||||
|
.isEqualTo(EmbeddedDatabaseConnection.H2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getWhenH2IsNotOnTheClasspathReturnsNone() {
|
||||||
|
assertThat(EmbeddedDatabaseConnection.get(new HidePackagesClassLoader("io.r2dbc.h2")))
|
||||||
|
.isEqualTo(EmbeddedDatabaseConnection.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Arguments> urlParameters() {
|
||||||
|
return Stream.of(Arguments.arguments(EmbeddedDatabaseConnection.NONE, null),
|
||||||
|
Arguments.arguments(EmbeddedDatabaseConnection.H2,
|
||||||
|
"r2dbc:h2:mem:///test-database?options=DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HidePackagesClassLoader extends URLClassLoader {
|
||||||
|
|
||||||
|
private final String[] hiddenPackages;
|
||||||
|
|
||||||
|
HidePackagesClassLoader(String... hiddenPackages) {
|
||||||
|
super(new URL[0], EmbeddedDatabaseConnectionTests.HidePackagesClassLoader.class.getClassLoader());
|
||||||
|
this.hiddenPackages = hiddenPackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||||
|
if (Arrays.stream(this.hiddenPackages).anyMatch(name::startsWith)) {
|
||||||
|
throw new ClassNotFoundException();
|
||||||
|
}
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue