>) em.createNativeQuery(
- """
- SELECT ha.uuid, ha.type, ha.identifier FROM hs_hosting.asset ha
- JOIN hs_hosting.asset_legacy_id li ON li.uuid=ha.uuid
- WHERE li.legacy_id is null AND CAST(ha.type AS text)=:type
- ORDER BY li.legacy_id
- """,
- List.class)
+ """
+ select ha.uuid, ha.type, ha.identifier from hs_hosting.asset ha
+ join hs_hosting.asset_legacy_id li on li.uuid=ha.uuid
+ where li.legacy_id is null and cast(ha.type as text)=:type
+ order by li.legacy_id
+ """,
+ List.class)
.setParameter("type", type.name())
.getResultList()).stream()
.map(row -> row.stream().map(Object::toString).collect(joining(", ")))
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java
index c3111c01..49ecc5f8 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/ImportOfficeData.java
@@ -4,11 +4,14 @@ import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
+import java.io.File;
+
/*
* This 'test' includes the complete legacy 'office' data import.
*
@@ -50,7 +53,8 @@ import org.springframework.test.context.ActiveProfiles;
"spring.datasource.url=${HSADMINNG_POSTGRES_JDBC_URL:jdbc:tc:postgresql:15.5-bookworm:///importOfficeDataTC}",
"spring.datasource.username=${HSADMINNG_POSTGRES_ADMIN_USERNAME:ADMIN}",
"spring.datasource.password=${HSADMINNG_POSTGRES_ADMIN_PASSWORD:password}",
- "hsadminng.superuser=${HSADMINNG_SUPERUSER:superuser-alex@hostsharing.net}"
+ "hsadminng.superuser=${HSADMINNG_SUPERUSER:import-superuser@hostsharing.net}",
+ "spring.liquibase.contexts=only-office,without-test-data"
})
@ActiveProfiles("without-test-data")
@DirtiesContext
@@ -58,4 +62,13 @@ import org.springframework.test.context.ActiveProfiles;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@ExtendWith(OrderedDependedTestsExtension.class)
public class ImportOfficeData extends BaseOfficeDataImport {
+
+ @Value("${spring.datasource.url}")
+ private String jdbcUrl;
+
+ @Test
+ @Order(9999)
+ public void dumpOfficeData() {
+ PostgresTestcontainer.dump(jdbcUrl, new File("build/db/released-only-office-schema-with-import-test-data.sql"));
+ }
}
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/migration/LiquibaseCompatibilityIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/migration/LiquibaseCompatibilityIntegrationTest.java
index 64841f6e..9e8830f7 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/migration/LiquibaseCompatibilityIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/migration/LiquibaseCompatibilityIntegrationTest.java
@@ -1,33 +1,17 @@
package net.hostsharing.hsadminng.hs.migration;
-import liquibase.Liquibase;
-import lombok.SneakyThrows;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;
-import org.testcontainers.containers.JdbcDatabaseContainer;
-import org.testcontainers.jdbc.ContainerDatabaseDriver;
-import jakarta.persistence.EntityManager;
-import jakarta.persistence.PersistenceContext;
-import javax.sql.DataSource;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.InputStreamReader;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.commons.io.FileUtils.readFileToString;
-import static org.apache.commons.io.FileUtils.write;
-import static org.apache.commons.io.FileUtils.writeStringToFile;
-import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
// BLOG: Liquibase-migration-test (not before the reference-SQL-dump-generation is simplified)
@@ -40,9 +24,9 @@ import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TE
* The test works as follows:
*
*
- * - the database is initialized by `db/prod-only-office-schema-with-test-data.sql` from the test-resources
+ * - the database is initialized by `db/released-only-office-schema-with-test-data.sql` from the test-resources
* - the current Liquibase-migrations (only-office but with-test-data) are performed
- * - a new dump is written to `db/prod-only-office-schema-with-test-data.sql` in the build-directory
+ * - a new dump is written to `db/released-only-office-schema-with-test-data.sql` in the build-directory
* - an extra Liquibase-changeset (liquibase-migration-test) is applied
* - it's asserted that the extra changeset got applied
*
@@ -58,123 +42,31 @@ import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TE
@DirtiesContext
@ActiveProfiles("liquibase-migration-test")
@Import(LiquibaseConfig.class)
-@Sql(value = "/db/prod-only-office-schema-with-test-data.sql", executionPhase = BEFORE_TEST_CLASS)
+@Sql(value = "/db/released-only-office-schema-with-test-data.sql", executionPhase = BEFORE_TEST_CLASS) // release-schema
public class LiquibaseCompatibilityIntegrationTest {
private static final String EXPECTED_CHANGESET_ONLY_AFTER_NEW_MIGRATION = "hs-global-liquibase-migration-test";
+ private static final int EXPECTED_LIQUIBASE_CHANGELOGS_IN_PROD_SCHEMA_DUMP = 287;
+
+ @Value("${spring.datasource.url}")
+ private String jdbcUrl;
@Autowired
- private DataSource dataSource;
-
- @Autowired
- private Liquibase liquibase;
-
- @PersistenceContext
- private EntityManager em;
+ private LiquibaseMigration liquibase;
@Test
void migrationWorksBasedOnAPreviouslyPopulatedSchema() {
// check the initial status from the @Sql-annotation
- final var initialChangeSetCount = assertProdReferenceStatusAfterRestore();
+ final var initialChangeSetCount = liquibase.assertReferenceStatusAfterRestore(
+ EXPECTED_LIQUIBASE_CHANGELOGS_IN_PROD_SCHEMA_DUMP, EXPECTED_CHANGESET_ONLY_AFTER_NEW_MIGRATION);
// run the current migrations and dump the result to the build-directory
- runLiquibaseMigrationsWithContexts("only-office", "with-test-data");
- dumpTo(new File("build/db/prod-only-office-schema-with-test-data.sql"));
+ liquibase.runWithContexts("only-office", "with-test-data");
+ PostgresTestcontainer.dump(jdbcUrl, new File("build/db/released-only-office-schema-with-test-data.sql"));
// then add another migration and assert if it was applied
- runLiquibaseMigrationsWithContexts("liquibase-migration-test");
- assertThatCurrentMigrationsGotApplied(initialChangeSetCount);
- }
-
- private int assertProdReferenceStatusAfterRestore() {
- final var schemas = singleColumnSqlQuery("SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname='public'");
- assertThat(schemas).containsExactly("databasechangelog", "databasechangeloglock");
-
- final var liquibaseScripts1 = singleColumnSqlQuery("SELECT * FROM public.databasechangelog");
- assertThat(liquibaseScripts1).hasSizeGreaterThan(285);
- assertThat(liquibaseScripts1).doesNotContain(EXPECTED_CHANGESET_ONLY_AFTER_NEW_MIGRATION);
- final var initialChangeSetCount = liquibaseScripts1.size();
- return initialChangeSetCount;
- }
-
- private void assertThatCurrentMigrationsGotApplied(final int initialChangeSetCount) {
- final var liquibaseScripts = singleColumnSqlQuery("SELECT id FROM public.databasechangelog");
- assertThat(liquibaseScripts).hasSizeGreaterThan(initialChangeSetCount);
- assertThat(liquibaseScripts).contains(EXPECTED_CHANGESET_ONLY_AFTER_NEW_MIGRATION);
- }
-
- @SneakyThrows
- private void dumpTo(final File targetFileName) {
- makeDir(targetFileName.getParentFile());
-
- final var jdbcDatabaseContainer = getJdbcDatabaseContainer();
-
- final var sqlDumpFile = new File(targetFileName.getParent(), "." + targetFileName.getName());
- final var pb = new ProcessBuilder(
- "pg_dump", "--column-inserts", "--disable-dollar-quoting",
- "--host=" + jdbcDatabaseContainer.getHost(),
- "--port=" + jdbcDatabaseContainer.getFirstMappedPort(),
- "--username=" + jdbcDatabaseContainer.getUsername() ,
- "--dbname=" + jdbcDatabaseContainer.getDatabaseName(),
- "--file=" + sqlDumpFile.getCanonicalPath()
- );
- pb.environment().put("PGPASSWORD", jdbcDatabaseContainer.getPassword());
-
- final var process = pb.start();
- int exitCode = process.waitFor();
- final var stderr = new BufferedReader(new InputStreamReader(process.getErrorStream()))
- .lines().collect(Collectors.joining("\n"));
- assertThat(exitCode).describedAs(stderr).isEqualTo(0);
-
- final var header = """
- -- =================================================================================
- -- Generated reference-SQL-dump (hopefully of latest prod-release).
- -- See: net.hostsharing.hsadminng.hs.migration.LiquibaseCompatibilityIntegrationTest
- -- ---------------------------------------------------------------------------------
-
- --
- -- Explicit pre-initialization because we cannot use `pg_dump --create ...`
- -- because the database is already created by Testcontainers.
- --
-
- CREATE ROLE postgres;
- CREATE ROLE admin;
- CREATE ROLE restricted;
-
- """;
- writeStringToFile(targetFileName, header, UTF_8, false); // false = overwrite
-
- write(targetFileName, readFileToString(sqlDumpFile, UTF_8), UTF_8, true);
-
- assertThat(sqlDumpFile.delete()).describedAs(sqlDumpFile + " cannot be deleted");
- }
-
- private void makeDir(final File dir) {
- assertThat(!dir.exists() || dir.isDirectory()).describedAs(dir + " does exist, but is not a directory").isTrue();
- assertThat(dir.isDirectory() || dir.mkdirs()).describedAs(dir + " cannot be created").isTrue();
- }
-
- @SneakyThrows
- private void runLiquibaseMigrationsWithContexts(final String... contexts) {
- liquibase.update(
- new liquibase.Contexts(contexts),
- new liquibase.LabelExpression());
- }
-
- private List singleColumnSqlQuery(final String sql) {
- //noinspection unchecked
- final var rows = (List