From 2da5ddbba7e76d9c29ea5d97e1248a53ae875f72 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Tue, 15 Mar 2022 22:49:23 +0100
Subject: [PATCH] #663 - migrator: added config for integration tests

---
 .gitignore                                    |   1 +
 BudgetMasterDatabaseMigrator/pom.xml          |   6 ++
 .../MigrateDefaultDatabaseTest.java           |  36 +++++++
 .../databasemigrator/MigratorTestBase.java    |  90 ++++++++++++++++++
 .../default_database_after_first_start.mv.db  | Bin 0 -> 94208 bytes
 BudgetMasterServer/pom.xml                    |  28 ------
 pom.xml                                       |  32 +++++++
 7 files changed, 165 insertions(+), 28 deletions(-)
 create mode 100644 BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigrateDefaultDatabaseTest.java
 create mode 100644 BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigratorTestBase.java
 create mode 100644 BudgetMasterDatabaseMigrator/src/test/resources/default_database_after_first_start.mv.db

diff --git a/.gitignore b/.gitignore
index cdff0bf46..90fe81dc6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ certs/
 *.p12
 
 *.db
+!BudgetMasterDatabaseMigrator/src/test/resources/*.mv.db
 *.iml
 
 */build/[0-9]*.[0-9]*.[0-9]*
diff --git a/BudgetMasterDatabaseMigrator/pom.xml b/BudgetMasterDatabaseMigrator/pom.xml
index 9e084b805..9603d82a9 100644
--- a/BudgetMasterDatabaseMigrator/pom.xml
+++ b/BudgetMasterDatabaseMigrator/pom.xml
@@ -25,6 +25,12 @@
             <artifactId>spring-boot-starter-data-jpa</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.batch</groupId>
+            <artifactId>spring-batch-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>com.h2database</groupId>
             <artifactId>h2</artifactId>
diff --git a/BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigrateDefaultDatabaseTest.java b/BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigrateDefaultDatabaseTest.java
new file mode 100644
index 000000000..246d47a96
--- /dev/null
+++ b/BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigrateDefaultDatabaseTest.java
@@ -0,0 +1,36 @@
+package de.deadlocker8.budgetmaster.databasemigrator;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepExecution;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class MigrateDefaultDatabaseTest extends MigratorTestBase
+{
+	@Test
+	void test_jobMigrate() throws Exception
+	{
+		final JobExecution jobExecution = jobLauncherTestUtils.launchJob(DEFAULT_JOB_PARAMETERS);
+
+		assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED);
+	}
+
+	@Test
+	void test_stepMigrateImages_noImages()
+	{
+		final JobExecution jobExecution = jobLauncherTestUtils.launchStep("Migrate images", DEFAULT_JOB_PARAMETERS);
+		final List<StepExecution> stepExecutions = new ArrayList<>(jobExecution.getStepExecutions());
+
+		assertThat(jobExecution.getExitStatus()).isEqualTo(ExitStatus.COMPLETED);
+
+		assertThat(stepExecutions).hasSize(1);
+		final StepExecution stepExecution = stepExecutions.get(0);
+		assertThat(stepExecution.getReadCount()).isZero();
+		assertThat(stepExecution.getCommitCount()).isOne();
+	}
+}
\ No newline at end of file
diff --git a/BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigratorTestBase.java b/BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigratorTestBase.java
new file mode 100644
index 000000000..abf8383ef
--- /dev/null
+++ b/BudgetMasterDatabaseMigrator/src/test/java/de/deadlocker8/budgetmaster/databasemigrator/MigratorTestBase.java
@@ -0,0 +1,90 @@
+package de.deadlocker8.budgetmaster.databasemigrator;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.test.JobLauncherTestUtils;
+import org.springframework.batch.test.JobRepositoryTestUtils;
+import org.springframework.batch.test.context.SpringBatchTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
+import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.io.Resource;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import javax.sql.DataSource;
+import java.io.IOException;
+
+
+@SpringBatchTest
+@SpringBootTest
+@ExtendWith(SpringExtension.class)
+@Testcontainers
+@Import(MigratorTestBase.TestDatabaseConfiguration.class)
+@ActiveProfiles("test")
+@EnableAutoConfiguration
+@ContextConfiguration(classes = {BatchConfiguration.class})
+@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
+public abstract class MigratorTestBase
+{
+	protected static final JobParameters DEFAULT_JOB_PARAMETERS = new JobParametersBuilder().toJobParameters();
+
+	@Autowired
+	protected JobLauncherTestUtils jobLauncherTestUtils;
+
+	@Autowired
+	protected JobRepositoryTestUtils jobRepositoryTestUtils;
+
+	@AfterEach
+	public void afterEach()
+	{
+		jobRepositoryTestUtils.removeJobExecutions();
+	}
+
+	@Container
+	static PostgreSQLContainer<?> postgresDB = new PostgreSQLContainer<>("postgres:14.2")
+			.withDatabaseName("budgetmaster-tests-db")
+			.withUsername("budgetmaster")
+			.withPassword("BudgetMaster");
+
+	@TestConfiguration
+	static class TestDatabaseConfiguration
+	{
+		@Value("classpath:default_database_after_first_start.mv.db")
+		private Resource databaseResource;
+
+		@Bean
+		@Primary
+		public DataSource dataSource() throws IOException
+		{
+			final String folderName = databaseResource.getFile().getAbsolutePath().replace(".mv.db", "");
+			String jdbcString = "jdbc:h2:/" + folderName + ";DB_CLOSE_ON_EXIT=TRUE";
+			return DataSourceBuilder.create().username("sa").password("").url(jdbcString).driverClassName("org.h2.Driver").build();
+		}
+	}
+
+	@DynamicPropertySource
+	static void properties(DynamicPropertyRegistry registry)
+	{
+		registry.add("spring.seconddatasource.url", postgresDB::getJdbcUrl);
+		registry.add("spring.seconddatasource.username", postgresDB::getUsername);
+		registry.add("spring.seconddatasource.password", postgresDB::getPassword);
+	}
+}
diff --git a/BudgetMasterDatabaseMigrator/src/test/resources/default_database_after_first_start.mv.db b/BudgetMasterDatabaseMigrator/src/test/resources/default_database_after_first_start.mv.db
new file mode 100644
index 0000000000000000000000000000000000000000..36ca61ae144e56adb8d0d616095a9c96a576d8df
GIT binary patch
literal 94208
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
Lkf^RRX^OZ2fy`U3

literal 0
HcmV?d00001

diff --git a/BudgetMasterServer/pom.xml b/BudgetMasterServer/pom.xml
index 42eb9c36d..982d787d3 100644
--- a/BudgetMasterServer/pom.xml
+++ b/BudgetMasterServer/pom.xml
@@ -34,14 +34,12 @@
         <mousetrap.version>1.6.5</mousetrap.version>
         <codemirror.version>5.62.2</codemirror.version>
         <selenium.version>4.1.2</selenium.version>
-        <assertj-core.version>3.22.0</assertj-core.version>
         <jgit.version>6.0.0.202111291000-r</jgit.version>
         <natorder.version>1.1.2</natorder.version>
         <itextpdf.version>5.5.13.2</itextpdf.version>
         <vanilla-picker.version>2.12.1</vanilla-picker.version>
         <jacoco-maven-plugin.version>0.8.7</jacoco-maven-plugin.version>
         <dependency-check-maven.version>6.5.3</dependency-check-maven.version>
-        <testcontainer.version>1.16.3</testcontainer.version>
 
         <project.outputDirectory>build/${project.version}</project.outputDirectory>
         <project.artifactName>${project.artifactId}-v${project.version}</project.artifactName>
@@ -63,12 +61,6 @@
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
 
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
-        </dependency>
-
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-jpa</artifactId>
@@ -197,31 +189,11 @@
             <scope>test</scope>
         </dependency>
 
-        <dependency>
-            <groupId>org.assertj</groupId>
-            <artifactId>assertj-core</artifactId>
-            <version>${assertj-core.version}</version>
-            <scope>test</scope>
-        </dependency>
-
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-inline</artifactId>
             <scope>test</scope>
         </dependency>
-
-        <dependency>
-            <groupId>org.testcontainers</groupId>
-            <artifactId>junit-jupiter</artifactId>
-            <version>${testcontainer.version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.testcontainers</groupId>
-            <artifactId>postgresql</artifactId>
-            <version>${testcontainer.version}</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
 
     <build>
diff --git a/pom.xml b/pom.xml
index 109be0af2..b6c34edd4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,8 +54,40 @@
         <maven.build.timestamp.format>dd.MM.yy</maven.build.timestamp.format>
         <app.versionCode>38</app.versionCode>
         <app.author>Robert Goldmann</app.author>
+
+        <testcontainer.version>1.16.3</testcontainer.version>
+        <assertj-core.version>3.22.0</assertj-core.version>
     </properties>
 
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-core</artifactId>
+            <version>${assertj-core.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.testcontainers</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>${testcontainer.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
     <distributionManagement>
         <repository>
             <id>release</id>
-- 
GitLab