Skip to content

Commit

Permalink
build(test): use testcontainers for postgresql tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ndr-brt committed Feb 18, 2025
1 parent 031aaa3 commit 3cc9f25
Show file tree
Hide file tree
Showing 25 changed files with 330 additions and 333 deletions.
9 changes: 0 additions & 9 deletions .github/workflows/verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,6 @@ jobs:

Postgresql-Integration-Tests:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:14.2
ports:
- 5432:5432
env:
POSTGRES_PASSWORD: password

steps:
- uses: actions/checkout@v4
- uses: eclipse-edc/.github/.github/actions/setup-build@main
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.sql.testfixtures;

import org.eclipse.edc.spi.system.configuration.Config;
import org.eclipse.edc.spi.system.configuration.ConfigFactory;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.testcontainers.containers.PostgreSQLContainer;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;

import static java.lang.String.format;

/**
* Extension to be used in end-to-end tests with Postgresql persistence
*/
public class PostgresqlEndToEndExtension implements BeforeAllCallback, AfterAllCallback {

private final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17.3");

public PostgresqlEndToEndExtension() {
}

@Override
public void beforeAll(ExtensionContext context) {
postgres.start();
}

@Override
public void afterAll(ExtensionContext context) {
postgres.stop();
postgres.close();
}

/**
* Return config suitable for EDC runtime for default database.
*
* @return the config.
*/
public Config config() {
return configFor(postgres.getDatabaseName());
}

/**
* Return config suitable for EDC runtime giving the database name.
*
* @param databaseName the database name;
* @return the config.
*/
public Config configFor(String databaseName) {
var settings = Map.of(
"edc.datasource.default.url", postgres.getJdbcUrl() + databaseName,
"edc.datasource.default.user", postgres.getUsername(),
"edc.datasource.default.password", postgres.getPassword(),
"edc.sql.schema.autocreate", "true"
);

return ConfigFactory.fromMap(settings);
}

public void createDatabase(String name) {
var jdbcUrl = postgres.getJdbcUrl() + postgres.getDatabaseName();
try (var connection = DriverManager.getConnection(jdbcUrl, postgres.getUsername(), postgres.getPassword())) {
connection.createStatement().execute(format("create database %s;", name));
} catch (SQLException e) {
// database could already exist
}
}

}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@

package org.eclipse.edc.sql.testfixtures;

import org.eclipse.edc.spi.system.configuration.Config;
import org.eclipse.edc.spi.system.configuration.ConfigFactory;
import org.eclipse.edc.sql.DriverManagerConnectionFactory;
import org.eclipse.edc.sql.QueryExecutor;
import org.eclipse.edc.sql.SqlQueryExecutor;
Expand All @@ -36,90 +34,48 @@
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;

import static java.lang.String.format;
import static org.eclipse.edc.util.io.Ports.getFreePort;

/**
* Extension for running PG SQL store implementation. It automatically creates a test database and provided all the base data structure
* for a SQL store to run such as {@link DataSourceRegistry}, {@link TransactionContext} and data source name which is automatically generated
* Extension for running PostgreSQL store implementation tests. It starts a database container and provides all the base
* data structure for a SQL store to run such as {@link DataSourceRegistry}, {@link TransactionContext} and data source
* name which is automatically generated.
*/
public class PostgresqlStoreSetupExtension implements BeforeEachCallback, BeforeAllCallback, AfterAllCallback, ParameterResolver {

public static final String POSTGRES_IMAGE_NAME = "postgres:16.1";
private final PostgreSQLContainer<?> postgreSqlContainer = new PostgreSQLContainer<>(POSTGRES_IMAGE_NAME)
.withExposedPorts(5432)
.withUsername("postgres")
.withPassword("password")
.withDatabaseName("itest");
private final PostgresqlLocalInstance postgres;
private final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:17.3");
private final QueryExecutor queryExecutor = new SqlQueryExecutor();
private final TransactionContext transactionContext = new NoopTransactionContext();
private final DataSourceRegistry dataSourceRegistry = new DefaultDataSourceRegistry();
private final String datasourceName = UUID.randomUUID().toString();
private final String jdbcUrlPrefix;

public PostgresqlStoreSetupExtension() {
var exposedPort = getFreePort();
postgreSqlContainer.setPortBindings(List.of("%s:5432".formatted(exposedPort)));
jdbcUrlPrefix = format("jdbc:postgresql://%s:%s/", postgreSqlContainer.getHost(), exposedPort);
postgres = new PostgresqlLocalInstance(postgreSqlContainer.getUsername(), postgreSqlContainer.getPassword(), jdbcUrlPrefix);
}

public String getDatasourceName() {
return datasourceName;
}

public Connection getConnection() {
try {
return dataSourceRegistry.resolve(datasourceName).getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

public int runQuery(String query) {
return transactionContext.execute(() -> queryExecutor.execute(getConnection(), query));
}

public TransactionContext getTransactionContext() {
return transactionContext;
}

public DataSourceRegistry getDataSourceRegistry() {
return dataSourceRegistry;
}

@Override
public void beforeAll(ExtensionContext context) {
postgreSqlContainer.start();
postgres.createDatabase(postgreSqlContainer.getDatabaseName());
postgres.start();
}

@Override
public void beforeEach(ExtensionContext context) {
var properties = new Properties();
properties.put("user", postgreSqlContainer.getUsername());
properties.put("password", postgreSqlContainer.getPassword());
properties.put("user", postgres.getUsername());
properties.put("password", postgres.getPassword());
var connectionFactory = new DriverManagerConnectionFactory();
var jdbcUrl = jdbcUrlPrefix + postgreSqlContainer.getDatabaseName();
var jdbcUrl = postgres.getJdbcUrl() + postgres.getDatabaseName();
var dataSource = new ConnectionFactoryDataSource(connectionFactory, jdbcUrl, properties);
dataSourceRegistry.register(datasourceName, dataSource);
}

@Override
public void afterAll(ExtensionContext context) {
postgreSqlContainer.stop();
postgreSqlContainer.close();
postgres.stop();
postgres.close();
}

@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
var type = parameterContext.getParameter().getParameterizedType();
return List.of(PostgresqlStoreSetupExtension.class, Connection.class, QueryExecutor.class, PostgresqlLocalInstance.class).contains(type);
return List.of(PostgresqlStoreSetupExtension.class, Connection.class, QueryExecutor.class).contains(type);
}

@Override
Expand All @@ -131,17 +87,32 @@ public Object resolveParameter(ParameterContext parameterContext, ExtensionConte
return getConnection();
} else if (type.equals(QueryExecutor.class)) {
return queryExecutor;
} else if (type.equals(PostgresqlLocalInstance.class)) {
return postgres;
}
return null;
}

public Config getDatasourceConfig() {
return ConfigFactory.fromMap(getDatasourceConfiguration());
public String getDatasourceName() {
return datasourceName;
}

public Connection getConnection() {
try {
return dataSourceRegistry.resolve(datasourceName).getConnection();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

public int runQuery(String query) {
return transactionContext.execute(() -> queryExecutor.execute(getConnection(), query));
}

public TransactionContext getTransactionContext() {
return transactionContext;
}

public Map<String, String> getDatasourceConfiguration() {
return postgres.createDefaultDatasourceConfiguration(postgreSqlContainer.getDatabaseName());
public DataSourceRegistry getDataSourceRegistry() {
return dataSourceRegistry;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;

import java.io.IOException;

@ComponentTest
@ExtendWith(PostgresqlStoreSetupExtension.class)
public class SqlEndpointDataReferenceEntryIndexTest extends EndpointDataReferenceEntryIndexTestBase {
Expand All @@ -39,7 +37,7 @@ public class SqlEndpointDataReferenceEntryIndexTest extends EndpointDataReferenc
private SqlEndpointDataReferenceEntryIndex entryIndex;

@BeforeEach
void setUp(PostgresqlStoreSetupExtension extension, QueryExecutor queryExecutor) throws IOException {
void setUp(PostgresqlStoreSetupExtension extension, QueryExecutor queryExecutor) {

entryIndex = new SqlEndpointDataReferenceEntryIndex(extension.getDataSourceRegistry(), extension.getDatasourceName(),
extension.getTransactionContext(), new ObjectMapper(), statements, queryExecutor);
Expand Down
Loading

0 comments on commit 3cc9f25

Please sign in to comment.