44import io .r2dbc .postgresql .PostgresqlConnectionFactory ;
55import io .r2dbc .spi .ConnectionFactory ;
66
7+ import java .util .function .Supplier ;
8+
79import javax .sql .DataSource ;
810
911import org .postgresql .ds .PGSimpleDataSource ;
1012import org .springframework .data .r2dbc .testing .ExternalDatabase .ProvidedDatabase ;
13+ import org .testcontainers .containers .PostgreSQLContainer ;
1114
1215/**
1316 * Utility class for testing against Postgres.
1417 *
1518 * @author Mark Paluch
19+ * @author Jens Schauder
1620 */
1721public class PostgresTestSupport {
1822
23+ private static ExternalDatabase testContainerDatabase ;
24+
1925public static String CREATE_TABLE_LEGOSET = "CREATE TABLE legoset (\n " //
2026+ " id integer CONSTRAINT id PRIMARY KEY,\n " //
2127+ " name varchar(255) NOT NULL,\n " //
@@ -31,30 +37,91 @@ public class PostgresTestSupport {
3137public static String INSERT_INTO_LEGOSET = "INSERT INTO legoset (id, name, manual) VALUES($1, $2, $3)" ;
3238
3339/**
34- * Returns a locally provided database at {@code postgres:@localhost:5432/postgres}.
40+ * Returns a database either hosted locally at {@code postgres:@localhost:5432/postgres} or running inside Docker .
3541 *
36- * @return
42+ * @return information about the database. Guaranteed to be not {@literal null}.
3743 */
3844public static ExternalDatabase database () {
39- return local ();
45+
46+ if (Boolean .getBoolean ("spring.data.r2dbc.test.preferLocalDatabase" )) {
47+
48+ return getFirstWorkingDatabase ( //
49+ PostgresTestSupport ::local , //
50+ PostgresTestSupport ::testContainer //
51+ );
52+ } else {
53+
54+ return getFirstWorkingDatabase ( //
55+ PostgresTestSupport ::testContainer , //
56+ PostgresTestSupport ::local //
57+ );
58+ }
59+ }
60+
61+ private static ExternalDatabase getFirstWorkingDatabase (Supplier <ExternalDatabase > first ,
62+ Supplier <ExternalDatabase > second ) {
63+
64+ ExternalDatabase database = first .get ();
65+ if (database .checkValidity ()) {
66+ return database ;
67+ } else {
68+ return second .get ();
69+ }
4070}
4171
4272/**
4373 * Returns a locally provided database at {@code postgres:@localhost:5432/postgres}.
44- *
45- * @return
4674 */
4775private static ExternalDatabase local () {
48- return ProvidedDatabase .builder ().hostname ("localhost" ).port (5432 ).database ("postgres" ).username ("postgres" )
76+
77+ return ProvidedDatabase .builder () //
78+ .hostname ("localhost" ) //
79+ .port (5432 ) //
80+ .database ("postgres" ) //
81+ .username ("postgres" ) //
4982.password ("" ).build ();
5083}
5184
85+ /**
86+ * Returns a database provided via Testcontainers.
87+ */
88+ private static ExternalDatabase testContainer () {
89+
90+ if (testContainerDatabase == null ) {
91+
92+ try {
93+ PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer ();
94+ postgreSQLContainer .start ();
95+
96+ testContainerDatabase = ProvidedDatabase .builder () //
97+ .hostname ("localhost" ) //
98+ .port (postgreSQLContainer .getFirstMappedPort ()) //
99+ .database (postgreSQLContainer .getDatabaseName ()) //
100+ .username (postgreSQLContainer .getUsername ()) //
101+ .password (postgreSQLContainer .getPassword ()).build ();
102+
103+ } catch (IllegalStateException ise ) {
104+ // docker is not available.
105+ testContainerDatabase = new ExternalDatabase .NoSuchDatabase ();
106+ }
107+
108+ }
109+
110+ return testContainerDatabase ;
111+ }
112+
52113/**
53114 * Creates a new {@link ConnectionFactory} configured from the {@link ExternalDatabase}..
54115 */
55116public static ConnectionFactory createConnectionFactory (ExternalDatabase database ) {
56- return new PostgresqlConnectionFactory (PostgresqlConnectionConfiguration .builder ().host (database .getHostname ())
57- .database (database .getDatabase ()).username (database .getUsername ()).password (database .getPassword ()).build ());
117+
118+ return new PostgresqlConnectionFactory (PostgresqlConnectionConfiguration .builder () //
119+ .host (database .getHostname ()) //
120+ .database (database .getDatabase ()) //
121+ .port (database .getPort ()) //
122+ .username (database .getUsername ()) //
123+ .password (database .getPassword ()) //
124+ .build ());
58125}
59126
60127/**
@@ -72,4 +139,5 @@ public static DataSource createDataSource(ExternalDatabase database) {
72139
73140return dataSource ;
74141}
142+
75143}
0 commit comments