#2 - Add DatabaseClient.
Provide DatabaseClient and add ExternalDatabase class to provide database connection details/encapsulate a dockerized testcontainer.
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* http://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.data.jdbc.core.function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import io.r2dbc.postgresql.PostgresqlConnectionConfiguration;
|
||||
import io.r2dbc.postgresql.PostgresqlConnectionFactory;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import lombok.Data;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.postgresql.ds.PGSimpleDataSource;
|
||||
import org.springframework.data.jdbc.core.function.ExternalDatabase.ProvidedDatabase;
|
||||
import org.springframework.data.jdbc.core.mapping.Table;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link DatabaseClient} against PostgreSQL.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class DatabaseClientIntegrationTests {
|
||||
|
||||
/**
|
||||
* Local test database at {@code postgres:@localhost:5432/postgres}.
|
||||
*/
|
||||
@ClassRule public static final ExternalDatabase database = ProvidedDatabase.builder().hostname("localhost").port(5432)
|
||||
.database("postgres").username("postgres").password("").build();
|
||||
|
||||
private ConnectionFactory connectionFactory;
|
||||
|
||||
private JdbcTemplate jdbc;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
|
||||
Hooks.onOperatorDebug();
|
||||
|
||||
connectionFactory = new PostgresqlConnectionFactory(
|
||||
PostgresqlConnectionConfiguration.builder().host(database.getHostname()).database(database.getDatabase())
|
||||
.username(database.getUsername()).password(database.getPassword()).build());
|
||||
|
||||
PGSimpleDataSource dataSource = new PGSimpleDataSource();
|
||||
dataSource.setUser(database.getUsername());
|
||||
dataSource.setPassword(database.getPassword());
|
||||
dataSource.setDatabaseName(database.getDatabase());
|
||||
dataSource.setServerName(database.getHostname());
|
||||
dataSource.setPortNumber(database.getPort());
|
||||
|
||||
String tableToCreate = "CREATE TABLE IF NOT EXISTS legoset (\n"
|
||||
+ " id integer CONSTRAINT id PRIMARY KEY,\n" + " name varchar(255) NOT NULL,\n"
|
||||
+ " manual integer NULL\n" + ");";
|
||||
|
||||
jdbc = new JdbcTemplate(dataSource);
|
||||
jdbc.execute(tableToCreate);
|
||||
jdbc.execute("DELETE FROM legoset");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeInsert() {
|
||||
|
||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||
|
||||
databaseClient.execute().sql("INSERT INTO legoset (id, name, manual) VALUES($1, $2, $3)") //
|
||||
.bind(0, 42055) //
|
||||
.bind(1, "SCHAUFELRADBAGGER") //
|
||||
.bindNull("$3") //
|
||||
.fetch().rowsUpdated() //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(1) //
|
||||
.verifyComplete();
|
||||
|
||||
assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).containsEntry("id", 42055);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executeSelect() {
|
||||
|
||||
jdbc.execute("INSERT INTO legoset (id, name, manual) VALUES(42055, 'SCHAUFELRADBAGGER', 12)");
|
||||
|
||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||
|
||||
// TODO: Driver/Decode does not support decoding null values?
|
||||
databaseClient.execute().sql("SELECT id, name, manual FROM legoset") //
|
||||
.as(LegoSet.class) //
|
||||
.fetch().all() //
|
||||
.as(StepVerifier::create) //
|
||||
.consumeNextWith(actual -> {
|
||||
|
||||
assertThat(actual.getId()).isEqualTo(42055);
|
||||
assertThat(actual.getName()).isEqualTo("SCHAUFELRADBAGGER");
|
||||
assertThat(actual.getManual()).isEqualTo(12);
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insert() {
|
||||
|
||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||
|
||||
databaseClient.insert().into("legoset")//
|
||||
.value("id", 42055) //
|
||||
.value("name", "SCHAUFELRADBAGGER") //
|
||||
.nullValue("manual") //
|
||||
.exchange() //
|
||||
.flatMapMany(it -> it.extract((r, m) -> r.get("id", Integer.class)).all()).as(StepVerifier::create) //
|
||||
.expectNext(42055).verifyComplete();
|
||||
|
||||
assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).containsEntry("id", 42055);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void insertTypedObject() {
|
||||
|
||||
LegoSet legoSet = new LegoSet();
|
||||
legoSet.setId(42055);
|
||||
legoSet.setName("SCHAUFELRADBAGGER");
|
||||
legoSet.setManual(12);
|
||||
|
||||
DatabaseClient databaseClient = DatabaseClient.create(connectionFactory);
|
||||
|
||||
databaseClient.insert().into(LegoSet.class)//
|
||||
.using(legoSet).exchange() //
|
||||
.flatMapMany(it -> it.extract((r, m) -> r.get("id", Integer.class)).all()).as(StepVerifier::create) //
|
||||
.expectNext(42055).verifyComplete();
|
||||
|
||||
assertThat(jdbc.queryForMap("SELECT id, name, manual FROM legoset")).containsEntry("id", 42055);
|
||||
}
|
||||
|
||||
@Data
|
||||
@Table("legoset")
|
||||
static class LegoSet {
|
||||
int id;
|
||||
String name;
|
||||
Integer manual;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* http://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.data.jdbc.core.function;
|
||||
|
||||
import lombok.Builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.AssumptionViolatedException;
|
||||
import org.junit.rules.ExternalResource;
|
||||
|
||||
/**
|
||||
* {@link ExternalResource} wrapper to encapsulate {@link ProvidedDatabase} and
|
||||
* {@link org.testcontainers.containers.PostgreSQLContainer}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class ExternalDatabase extends ExternalResource {
|
||||
|
||||
/**
|
||||
* @return the post of the database service.
|
||||
*/
|
||||
public abstract int getPort();
|
||||
|
||||
/**
|
||||
* @return hostname on which the database service runs.
|
||||
*/
|
||||
public abstract String getHostname();
|
||||
|
||||
/**
|
||||
* @return name of the database.
|
||||
*/
|
||||
public abstract String getDatabase();
|
||||
|
||||
/**
|
||||
* @return database user name.
|
||||
*/
|
||||
public abstract String getUsername();
|
||||
|
||||
@Override
|
||||
protected void before() {
|
||||
|
||||
try (Socket socket = new Socket()) {
|
||||
;
|
||||
socket.connect(new InetSocketAddress(getHostname(), getPort()), Math.toIntExact(TimeUnit.SECONDS.toMillis(5)));
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new AssumptionViolatedException(
|
||||
String.format("Cannot connect to %s:%d. Skiping tests.", getHostname(), getPort()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return password for the database user.
|
||||
*/
|
||||
public abstract String getPassword();
|
||||
|
||||
/**
|
||||
* Provided (unmanaged resource) database connection coordinates.
|
||||
*/
|
||||
@Builder
|
||||
static class ProvidedDatabase extends ExternalDatabase {
|
||||
|
||||
private final int port;
|
||||
private final String hostname;
|
||||
private final String database;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.function.ExternalDatabase#getPort()
|
||||
*/
|
||||
@Override
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.function.ExternalDatabase#getHostname()
|
||||
*/
|
||||
@Override
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.function.ExternalDatabase#getDatabase()
|
||||
*/
|
||||
@Override
|
||||
public String getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.function.ExternalDatabase#getUsername()
|
||||
*/
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jdbc.core.function.ExternalDatabase#getPassword()
|
||||
*/
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user