Skip to content

Commit 067963c

Browse files
authored
Add PostgreSQL container implementation under org.testcontainers.postgresql (#11088)
1 parent d076937 commit 067963c

File tree

6 files changed

+165
-56
lines changed

6 files changed

+165
-56
lines changed

docs/modules/databases/postgres.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Testcontainers module for [PostgresSQL](https://hub.docker.com/_/postgres)
77
You can start a PostgreSQL container instance from any Java application by using:
88

99
<!--codeinclude-->
10-
[Container creation](../../../modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java) inside_block:container
10+
[Container creation](../../../modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLContainerTest.java) inside_block:container
1111
<!--/codeinclude-->
1212

1313
See [Database containers](./index.md) for documentation and usage that is common to all relational database container types.
@@ -28,19 +28,19 @@ See [JDBC](./jdbc.md) for documentation.
2828
* [pgvector/pgvector](https://hub.docker.com/r/pgvector/pgvector)
2929

3030
<!--codeinclude-->
31-
[Using pgvector](../../../modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java) inside_block:pgvectorContainer
31+
[Using pgvector](../../../modules/postgresql/src/test/java/org/testcontainers/postgresql/CompatibleImageTest.java) inside_block:pgvectorContainer
3232
<!--/codeinclude-->
3333

3434
* [postgis/postgis](https://registry.hub.docker.com/r/postgis/postgis)
3535

3636
<!--codeinclude-->
37-
[Using PostGIS](../../../modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java) inside_block:postgisContainer
37+
[Using PostGIS](../../../modules/postgresql/src/test/java/org/testcontainers/postgresql/CompatibleImageTest.java) inside_block:postgisContainer
3838
<!--/codeinclude-->
3939

4040
* [timescale/timescaledb](https://hub.docker.com/r/timescale/timescaledb)
4141

4242
<!--codeinclude-->
43-
[Using TimescaleDB](../../../modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java) inside_block:timescaledbContainer
43+
[Using TimescaleDB](../../../modules/postgresql/src/test/java/org/testcontainers/postgresql/CompatibleImageTest.java) inside_block:timescaledbContainer
4444
<!--/codeinclude-->
4545

4646
## Adding this module to your project dependencies

modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414
* Supported images: {@code postgres}, {@code pgvector/pgvector}
1515
* <p>
1616
* Exposed ports: 5432
17+
*
18+
* @deprecated use {@link org.testcontainers.postgresql.PostgreSQLContainer} instead.
1719
*/
20+
@Deprecated
1821
public class PostgreSQLContainer<SELF extends PostgreSQLContainer<SELF>> extends JdbcDatabaseContainer<SELF> {
1922

2023
public static final String NAME = "postgresql";
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package org.testcontainers.postgresql;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import org.testcontainers.containers.JdbcDatabaseContainer;
5+
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
6+
import org.testcontainers.utility.DockerImageName;
7+
8+
import java.time.Duration;
9+
import java.time.temporal.ChronoUnit;
10+
import java.util.Set;
11+
12+
/**
13+
* Testcontainers implementation for PostgreSQL.
14+
* <p>
15+
* Supported images: {@code postgres}, {@code pgvector/pgvector}
16+
* <p>
17+
* Exposed ports: 5432
18+
*/
19+
public class PostgreSQLContainer extends JdbcDatabaseContainer<PostgreSQLContainer> {
20+
21+
public static final String NAME = "postgresql";
22+
23+
public static final String IMAGE = "postgres";
24+
25+
public static final String DEFAULT_TAG = "9.6.12";
26+
27+
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("postgres");
28+
29+
private static final DockerImageName PGVECTOR_IMAGE_NAME = DockerImageName.parse("pgvector/pgvector");
30+
31+
public static final Integer POSTGRESQL_PORT = 5432;
32+
33+
static final String DEFAULT_USER = "test";
34+
35+
static final String DEFAULT_PASSWORD = "test";
36+
37+
private String databaseName = "test";
38+
39+
private String username = "test";
40+
41+
private String password = "test";
42+
43+
private static final String FSYNC_OFF_OPTION = "fsync=off";
44+
45+
public PostgreSQLContainer(final String dockerImageName) {
46+
this(DockerImageName.parse(dockerImageName));
47+
}
48+
49+
public PostgreSQLContainer(final DockerImageName dockerImageName) {
50+
super(dockerImageName);
51+
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME, PGVECTOR_IMAGE_NAME);
52+
53+
this.waitStrategy =
54+
new LogMessageWaitStrategy()
55+
.withRegEx(".*database system is ready to accept connections.*\\s")
56+
.withTimes(2)
57+
.withStartupTimeout(Duration.of(60, ChronoUnit.SECONDS));
58+
this.setCommand("postgres", "-c", FSYNC_OFF_OPTION);
59+
60+
addExposedPort(POSTGRESQL_PORT);
61+
}
62+
63+
/**
64+
* @return the ports on which to check if the container is ready
65+
* @deprecated use {@link #getLivenessCheckPortNumbers()} instead
66+
*/
67+
@NotNull
68+
@Override
69+
@Deprecated
70+
protected Set<Integer> getLivenessCheckPorts() {
71+
return super.getLivenessCheckPorts();
72+
}
73+
74+
@Override
75+
protected void configure() {
76+
// Disable Postgres driver use of java.util.logging to reduce noise at startup time
77+
withUrlParam("loggerLevel", "OFF");
78+
addEnv("POSTGRES_DB", databaseName);
79+
addEnv("POSTGRES_USER", username);
80+
addEnv("POSTGRES_PASSWORD", password);
81+
}
82+
83+
@Override
84+
public String getDriverClassName() {
85+
return "org.postgresql.Driver";
86+
}
87+
88+
@Override
89+
public String getJdbcUrl() {
90+
String additionalUrlParams = constructUrlParameters("?", "&");
91+
return (
92+
"jdbc:postgresql://" +
93+
getHost() +
94+
":" +
95+
getMappedPort(POSTGRESQL_PORT) +
96+
"/" +
97+
databaseName +
98+
additionalUrlParams
99+
);
100+
}
101+
102+
@Override
103+
public String getDatabaseName() {
104+
return databaseName;
105+
}
106+
107+
@Override
108+
public String getUsername() {
109+
return username;
110+
}
111+
112+
@Override
113+
public String getPassword() {
114+
return password;
115+
}
116+
117+
@Override
118+
public String getTestQueryString() {
119+
return "SELECT 1";
120+
}
121+
122+
@Override
123+
public PostgreSQLContainer withDatabaseName(final String databaseName) {
124+
this.databaseName = databaseName;
125+
return self();
126+
}
127+
128+
@Override
129+
public PostgreSQLContainer withUsername(final String username) {
130+
this.username = username;
131+
return self();
132+
}
133+
134+
@Override
135+
public PostgreSQLContainer withPassword(final String password) {
136+
this.password = password;
137+
return self();
138+
}
139+
140+
@Override
141+
protected void waitUntilContainerStarted() {
142+
getWaitStrategy().waitUntilReady(this);
143+
}
144+
}

modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/CustomizablePostgreSQLTest.java

Lines changed: 0 additions & 37 deletions
This file was deleted.

modules/postgresql/src/test/java/org/testcontainers/containers/CompatibleImageTest.java renamed to modules/postgresql/src/test/java/org/testcontainers/postgresql/CompatibleImageTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.testcontainers.containers;
1+
package org.testcontainers.postgresql;
22

33
import org.junit.jupiter.api.Test;
44
import org.testcontainers.db.AbstractContainerDatabaseTest;
@@ -15,7 +15,7 @@ class CompatibleImageTest extends AbstractContainerDatabaseTest {
1515
void pgvector() throws SQLException {
1616
try (
1717
// pgvectorContainer {
18-
PostgreSQLContainer<?> pgvector = new PostgreSQLContainer<>("pgvector/pgvector:pg16")
18+
PostgreSQLContainer pgvector = new PostgreSQLContainer("pgvector/pgvector:pg16")
1919
// }
2020
) {
2121
pgvector.start();
@@ -30,7 +30,7 @@ void pgvector() throws SQLException {
3030
void postgis() throws SQLException {
3131
try (
3232
// postgisContainer {
33-
PostgreSQLContainer<?> postgis = new PostgreSQLContainer<>(
33+
PostgreSQLContainer postgis = new PostgreSQLContainer(
3434
DockerImageName.parse("postgis/postgis:16-3.4-alpine").asCompatibleSubstituteFor("postgres")
3535
)
3636
// }
@@ -47,7 +47,7 @@ void postgis() throws SQLException {
4747
void timescaledb() throws SQLException {
4848
try (
4949
// timescaledbContainer {
50-
PostgreSQLContainer<?> timescaledb = new PostgreSQLContainer<>(
50+
PostgreSQLContainer timescaledb = new PostgreSQLContainer(
5151
DockerImageName.parse("timescale/timescaledb:2.14.2-pg16").asCompatibleSubstituteFor("postgres")
5252
)
5353
// }

modules/postgresql/src/test/java/org/testcontainers/junit/postgresql/SimplePostgreSQLTest.java renamed to modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLContainerTest.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
package org.testcontainers.junit.postgresql;
1+
package org.testcontainers.postgresql;
22

33
import org.junit.jupiter.api.Test;
44
import org.testcontainers.PostgreSQLTestImages;
5-
import org.testcontainers.containers.PostgreSQLContainer;
65
import org.testcontainers.db.AbstractContainerDatabaseTest;
76

87
import java.sql.ResultSet;
@@ -13,7 +12,7 @@
1312
import static org.assertj.core.api.Assertions.assertThat;
1413
import static org.assertj.core.api.Assertions.assertThatNoException;
1514

16-
class SimplePostgreSQLTest extends AbstractContainerDatabaseTest {
15+
class PostgreSQLContainerTest extends AbstractContainerDatabaseTest {
1716
static {
1817
// Postgres JDBC driver uses JUL; disable it to avoid annoying, irrelevant, stderr logs during connection testing
1918
LogManager.getLogManager().getLogger("").setLevel(Level.OFF);
@@ -22,7 +21,7 @@ class SimplePostgreSQLTest extends AbstractContainerDatabaseTest {
2221
@Test
2322
void testSimple() throws SQLException {
2423
try ( // container {
25-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:9.6.12")
24+
PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:9.6.12")
2625
// }
2726
) {
2827
postgres.start();
@@ -37,7 +36,7 @@ void testSimple() throws SQLException {
3736
@Test
3837
void testCommandOverride() throws SQLException {
3938
try (
40-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
39+
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
4140
.withCommand("postgres -c max_connections=42")
4241
) {
4342
postgres.start();
@@ -51,7 +50,7 @@ void testCommandOverride() throws SQLException {
5150
@Test
5251
void testUnsetCommand() throws SQLException {
5352
try (
54-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
53+
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
5554
.withCommand("postgres -c max_connections=42")
5655
.withCommand()
5756
) {
@@ -66,7 +65,7 @@ void testUnsetCommand() throws SQLException {
6665
@Test
6766
void testMissingInitScript() {
6867
try (
69-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
68+
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
7069
.withInitScript(null)
7170
) {
7271
assertThatNoException().isThrownBy(postgres::start);
@@ -76,7 +75,7 @@ void testMissingInitScript() {
7675
@Test
7776
void testExplicitInitScript() throws SQLException {
7877
try (
79-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
78+
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
8079
.withInitScript("somepath/init_postgresql.sql")
8180
) {
8281
postgres.start();
@@ -91,7 +90,7 @@ void testExplicitInitScript() throws SQLException {
9190
@Test
9291
void testExplicitInitScripts() throws SQLException {
9392
try (
94-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
93+
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
9594
.withInitScripts("somepath/init_postgresql.sql", "somepath/init_postgresql_2.sql")
9695
) {
9796
postgres.start();
@@ -112,7 +111,7 @@ void testExplicitInitScripts() throws SQLException {
112111
@Test
113112
void testWithAdditionalUrlParamInJdbcUrl() {
114113
try (
115-
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
114+
PostgreSQLContainer postgres = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE)
116115
.withUrlParam("charSet", "UNICODE")
117116
) {
118117
postgres.start();
@@ -123,7 +122,7 @@ void testWithAdditionalUrlParamInJdbcUrl() {
123122
}
124123
}
125124

126-
private void assertHasCorrectExposedAndLivenessCheckPorts(PostgreSQLContainer<?> postgres) {
125+
private void assertHasCorrectExposedAndLivenessCheckPorts(PostgreSQLContainer postgres) {
127126
assertThat(postgres.getExposedPorts()).containsExactly(PostgreSQLContainer.POSTGRESQL_PORT);
128127
assertThat(postgres.getLivenessCheckPortNumbers())
129128
.containsExactly(postgres.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT));

0 commit comments

Comments
 (0)