test: add postgres migration tests

This commit is contained in:
dualfroz committed 2026-08-28 10:05:01 +02:00
1 parent f3e095a20e
commit 9002c912c0
1 file changed
+96
@@ -0,0 +1,96 @@
package com.slotline.migration;
import org.flywaydb.core.Flyway;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.PostgreSQLContainer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static org.assertj.core.api.Assertions.assertThat;
class PostgresMigrationTest {
@Test
void migrationsApplyAndPartialUniqueIndexKeepsOneActiveSlot() throws Exception {
Assumptions.assumeTrue(DockerClientFactory.instance().isDockerAvailable(),
"Docker is not available; skipping the PostgreSQL migration test");
try (PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")) {
postgres.start();
Flyway flyway = Flyway.configure()
.dataSource(postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword())
.locations("classpath:db/migration/postgresql")
.load();
flyway.migrate();
try (Connection connection = DriverManager.getConnection(
postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword())) {
long organizationId = single(connection, "SELECT id FROM organization WHERE slug = 'default'");
long userId = returningId(connection, "INSERT INTO app_user "
+ "(organization_id, username, password_hash, role, created_at) "
+ "VALUES (" + organizationId + ", 'pg-user', 'x', 'USER', now()) RETURNING id");
long resourceId = returningId(connection, "INSERT INTO resource "
+ "(organization_id, name, description, zone_id, buffer_minutes, created_at, version) "
+ "VALUES (" + organizationId + ", 'PG court', 'outdoor', 'UTC', 0, now(), 0) RETURNING id");
long firstReservationId = returningId(connection, activeReservationInsert(resourceId, organizationId,
userId));
boolean duplicateRejected = false;
try (Statement statement = connection.createStatement()) {
statement.execute(activeReservationInsert(resourceId, organizationId, userId));
} catch (SQLException uniqueViolation) {
duplicateRejected = true;
}
assertThat(duplicateRejected)
.as("partial unique index must reject a second ACTIVE reservation on the same slot")
.isTrue();
try (Statement statement = connection.createStatement()) {
statement.executeUpdate(
"UPDATE reservation SET status = 'CANCELLED' WHERE id = " + firstReservationId);
}
boolean rebookAllowed = true;
try (Statement statement = connection.createStatement()) {
statement.execute(activeReservationInsert(resourceId, organizationId, userId));
} catch (SQLException stillBlocked) {
rebookAllowed = false;
}
assertThat(rebookAllowed)
.as("once the slot is cancelled the same slot may be booked again")
.isTrue();
}
}
}
private String activeReservationInsert(long resourceId, long organizationId, long userId) {
return "INSERT INTO reservation "
+ "(resource_id, organization_id, user_id, start_time, end_time, status, created_at, version) "
+ "VALUES (" + resourceId + ", " + organizationId + ", " + userId + ", "
+ "TIMESTAMPTZ '2026-09-01 10:00:00+00', TIMESTAMPTZ '2026-09-01 11:00:00+00', "
+ "'ACTIVE', now(), 0)";
}
private long single(Connection connection, String sql) throws SQLException {
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(sql)) {
rows.next();
return rows.getLong(1);
}
}
private long returningId(Connection connection, String sql) throws SQLException {
try (Statement statement = connection.createStatement(); ResultSet rows = statement.executeQuery(sql)) {
rows.next();
return rows.getLong(1);
}
}
}