Skip to content

Commit 52695d0

Browse files
authored
build(test): use testcontainers for postgresql tests (#4831)
1 parent 883b695 commit 52695d0

File tree

26 files changed

+358
-343
lines changed

26 files changed

+358
-343
lines changed

.github/workflows/verify.yaml

-9
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,6 @@ jobs:
4747

4848
Postgresql-Integration-Tests:
4949
runs-on: ubuntu-latest
50-
51-
services:
52-
postgres:
53-
image: postgres:14.2
54-
ports:
55-
- 5432:5432
56-
env:
57-
POSTGRES_PASSWORD: password
58-
5950
steps:
6051
- uses: actions/checkout@v4
6152
- uses: eclipse-edc/.github/.github/actions/setup-build@main
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* Copyright (c) 2025 Cofinity-X
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Apache License, Version 2.0 which is available at
6+
* https://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* SPDX-License-Identifier: Apache-2.0
9+
*
10+
* Contributors:
11+
* Cofinity-X - initial API and implementation
12+
*
13+
*/
14+
15+
package org.eclipse.edc.sql.testfixtures;
16+
17+
import org.eclipse.edc.spi.system.configuration.Config;
18+
import org.eclipse.edc.spi.system.configuration.ConfigFactory;
19+
import org.junit.jupiter.api.extension.AfterAllCallback;
20+
import org.junit.jupiter.api.extension.BeforeAllCallback;
21+
import org.junit.jupiter.api.extension.ExtensionContext;
22+
import org.testcontainers.containers.PostgreSQLContainer;
23+
24+
import java.sql.DriverManager;
25+
import java.sql.SQLException;
26+
import java.util.Map;
27+
28+
import static java.lang.String.format;
29+
import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT;
30+
31+
/**
32+
* Extension to be used in end-to-end tests with Postgresql persistence
33+
*/
34+
public class PostgresqlEndToEndExtension implements BeforeAllCallback, AfterAllCallback {
35+
36+
private static final String DEFAULT_IMAGE = "postgres:17.3";
37+
38+
private final PostgreSQLContainer<?> postgres;
39+
40+
public PostgresqlEndToEndExtension() {
41+
this(DEFAULT_IMAGE);
42+
}
43+
44+
public PostgresqlEndToEndExtension(String dockerImageName) {
45+
postgres = new PostgreSQLContainer<>(dockerImageName);
46+
}
47+
48+
@Override
49+
public void beforeAll(ExtensionContext context) {
50+
postgres.start();
51+
}
52+
53+
@Override
54+
public void afterAll(ExtensionContext context) {
55+
postgres.stop();
56+
postgres.close();
57+
}
58+
59+
/**
60+
* Return config suitable for EDC runtime for default database.
61+
*
62+
* @return the config.
63+
*/
64+
public Config config() {
65+
return configFor(postgres.getDatabaseName());
66+
}
67+
68+
/**
69+
* Return config suitable for EDC runtime giving the database name.
70+
*
71+
* @param databaseName the database name;
72+
* @return the config.
73+
*/
74+
public Config configFor(String databaseName) {
75+
var settings = Map.of(
76+
"edc.datasource.default.url", "jdbc:postgresql://%s:%d/%s"
77+
.formatted(postgres.getHost(), postgres.getMappedPort(POSTGRESQL_PORT), databaseName),
78+
"edc.datasource.default.user", postgres.getUsername(),
79+
"edc.datasource.default.password", postgres.getPassword(),
80+
"edc.sql.schema.autocreate", "true"
81+
);
82+
83+
return ConfigFactory.fromMap(settings);
84+
}
85+
86+
public void createDatabase(String name) {
87+
var jdbcUrl = postgres.getJdbcUrl() + postgres.getDatabaseName();
88+
try (var connection = DriverManager.getConnection(jdbcUrl, postgres.getUsername(), postgres.getPassword())) {
89+
connection.createStatement().execute(format("create database %s;", name));
90+
} catch (SQLException e) {
91+
// database could already exist
92+
}
93+
}
94+
95+
}

extensions/common/sql/sql-test-fixtures/src/testFixtures/java/org/eclipse/edc/sql/testfixtures/PostgresqlEndToEndInstance.java

-49
This file was deleted.

extensions/common/sql/sql-test-fixtures/src/testFixtures/java/org/eclipse/edc/sql/testfixtures/PostgresqlLocalInstance.java

-62
This file was deleted.

extensions/common/sql/sql-test-fixtures/src/testFixtures/java/org/eclipse/edc/sql/testfixtures/PostgresqlStoreSetupExtension.java

+37-56
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
package org.eclipse.edc.sql.testfixtures;
1616

17-
import org.eclipse.edc.spi.system.configuration.Config;
18-
import org.eclipse.edc.spi.system.configuration.ConfigFactory;
1917
import org.eclipse.edc.sql.DriverManagerConnectionFactory;
2018
import org.eclipse.edc.sql.QueryExecutor;
2119
import org.eclipse.edc.sql.SqlQueryExecutor;
@@ -36,90 +34,58 @@
3634
import java.sql.Connection;
3735
import java.sql.SQLException;
3836
import java.util.List;
39-
import java.util.Map;
4037
import java.util.Properties;
4138
import java.util.UUID;
4239

43-
import static java.lang.String.format;
44-
import static org.eclipse.edc.util.io.Ports.getFreePort;
45-
4640
/**
47-
* Extension for running PG SQL store implementation. It automatically creates a test database and provided all the base data structure
48-
* for a SQL store to run such as {@link DataSourceRegistry}, {@link TransactionContext} and data source name which is automatically generated
41+
* Extension for running PostgreSQL store implementation tests. It starts a database container and provides all the base
42+
* data structure for a SQL store to run such as {@link DataSourceRegistry}, {@link TransactionContext} and data source
43+
* name which is automatically generated.
4944
*/
5045
public class PostgresqlStoreSetupExtension implements BeforeEachCallback, BeforeAllCallback, AfterAllCallback, ParameterResolver {
5146

52-
public static final String POSTGRES_IMAGE_NAME = "postgres:16.1";
53-
private final PostgreSQLContainer<?> postgreSqlContainer = new PostgreSQLContainer<>(POSTGRES_IMAGE_NAME)
54-
.withExposedPorts(5432)
55-
.withUsername("postgres")
56-
.withPassword("password")
57-
.withDatabaseName("itest");
58-
private final PostgresqlLocalInstance postgres;
47+
private static final String DEFAULT_IMAGE = "postgres:17.3";
48+
49+
private final PostgreSQLContainer<?> postgres;
5950
private final QueryExecutor queryExecutor = new SqlQueryExecutor();
6051
private final TransactionContext transactionContext = new NoopTransactionContext();
6152
private final DataSourceRegistry dataSourceRegistry = new DefaultDataSourceRegistry();
6253
private final String datasourceName = UUID.randomUUID().toString();
63-
private final String jdbcUrlPrefix;
6454

6555
public PostgresqlStoreSetupExtension() {
66-
var exposedPort = getFreePort();
67-
postgreSqlContainer.setPortBindings(List.of("%s:5432".formatted(exposedPort)));
68-
jdbcUrlPrefix = format("jdbc:postgresql://%s:%s/", postgreSqlContainer.getHost(), exposedPort);
69-
postgres = new PostgresqlLocalInstance(postgreSqlContainer.getUsername(), postgreSqlContainer.getPassword(), jdbcUrlPrefix);
70-
}
71-
72-
public String getDatasourceName() {
73-
return datasourceName;
56+
this(DEFAULT_IMAGE);
7457
}
7558

76-
public Connection getConnection() {
77-
try {
78-
return dataSourceRegistry.resolve(datasourceName).getConnection();
79-
} catch (SQLException e) {
80-
throw new RuntimeException(e);
81-
}
82-
}
83-
84-
public int runQuery(String query) {
85-
return transactionContext.execute(() -> queryExecutor.execute(getConnection(), query));
86-
}
87-
88-
public TransactionContext getTransactionContext() {
89-
return transactionContext;
90-
}
91-
92-
public DataSourceRegistry getDataSourceRegistry() {
93-
return dataSourceRegistry;
59+
public PostgresqlStoreSetupExtension(String dockerImageName) {
60+
postgres = new PostgreSQLContainer<>(dockerImageName);
9461
}
9562

9663
@Override
9764
public void beforeAll(ExtensionContext context) {
98-
postgreSqlContainer.start();
99-
postgres.createDatabase(postgreSqlContainer.getDatabaseName());
65+
postgres.start();
10066
}
10167

10268
@Override
10369
public void beforeEach(ExtensionContext context) {
10470
var properties = new Properties();
105-
properties.put("user", postgreSqlContainer.getUsername());
106-
properties.put("password", postgreSqlContainer.getPassword());
71+
properties.put("user", postgres.getUsername());
72+
properties.put("password", postgres.getPassword());
10773
var connectionFactory = new DriverManagerConnectionFactory();
108-
var jdbcUrl = jdbcUrlPrefix + postgreSqlContainer.getDatabaseName();
74+
var jdbcUrl = postgres.getJdbcUrl() + postgres.getDatabaseName();
10975
var dataSource = new ConnectionFactoryDataSource(connectionFactory, jdbcUrl, properties);
11076
dataSourceRegistry.register(datasourceName, dataSource);
11177
}
11278

11379
@Override
11480
public void afterAll(ExtensionContext context) {
115-
postgreSqlContainer.stop();
116-
postgreSqlContainer.close();
81+
postgres.stop();
82+
postgres.close();
11783
}
11884

11985
@Override
12086
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
12187
var type = parameterContext.getParameter().getParameterizedType();
122-
return List.of(PostgresqlStoreSetupExtension.class, Connection.class, QueryExecutor.class, PostgresqlLocalInstance.class).contains(type);
88+
return List.of(PostgresqlStoreSetupExtension.class, Connection.class, QueryExecutor.class).contains(type);
12389
}
12490

12591
@Override
@@ -131,17 +97,32 @@ public Object resolveParameter(ParameterContext parameterContext, ExtensionConte
13197
return getConnection();
13298
} else if (type.equals(QueryExecutor.class)) {
13399
return queryExecutor;
134-
} else if (type.equals(PostgresqlLocalInstance.class)) {
135-
return postgres;
136100
}
137101
return null;
138102
}
139103

140-
public Config getDatasourceConfig() {
141-
return ConfigFactory.fromMap(getDatasourceConfiguration());
104+
public String getDatasourceName() {
105+
return datasourceName;
106+
}
107+
108+
public Connection getConnection() {
109+
try {
110+
return dataSourceRegistry.resolve(datasourceName).getConnection();
111+
} catch (SQLException e) {
112+
throw new RuntimeException(e);
113+
}
114+
}
115+
116+
public int runQuery(String query) {
117+
return transactionContext.execute(() -> queryExecutor.execute(getConnection(), query));
142118
}
143119

144-
public Map<String, String> getDatasourceConfiguration() {
145-
return postgres.createDefaultDatasourceConfiguration(postgreSqlContainer.getDatabaseName());
120+
public TransactionContext getTransactionContext() {
121+
return transactionContext;
146122
}
123+
124+
public DataSourceRegistry getDataSourceRegistry() {
125+
return dataSourceRegistry;
126+
}
127+
147128
}

extensions/common/store/sql/edr-index-sql/src/test/java/org/eclipse/edc/edr/store/index/sql/SqlEndpointDataReferenceEntryIndexTest.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
import org.junit.jupiter.api.BeforeEach;
2929
import org.junit.jupiter.api.extension.ExtendWith;
3030

31-
import java.io.IOException;
32-
3331
@ComponentTest
3432
@ExtendWith(PostgresqlStoreSetupExtension.class)
3533
public class SqlEndpointDataReferenceEntryIndexTest extends EndpointDataReferenceEntryIndexTestBase {
@@ -39,7 +37,7 @@ public class SqlEndpointDataReferenceEntryIndexTest extends EndpointDataReferenc
3937
private SqlEndpointDataReferenceEntryIndex entryIndex;
4038

4139
@BeforeEach
42-
void setUp(PostgresqlStoreSetupExtension extension, QueryExecutor queryExecutor) throws IOException {
40+
void setUp(PostgresqlStoreSetupExtension extension, QueryExecutor queryExecutor) {
4341

4442
entryIndex = new SqlEndpointDataReferenceEntryIndex(extension.getDataSourceRegistry(), extension.getDatasourceName(),
4543
extension.getTransactionContext(), new ObjectMapper(), statements, queryExecutor);

0 commit comments

Comments
 (0)