From 2d2192ca17443c0b3d275d1ea65b807e2c2df75d Mon Sep 17 00:00:00 2001 From: Arnold Galovics Date: Fri, 18 Mar 2022 11:35:27 +0100 Subject: [PATCH] FINERACT-1508: Liquibase test extension for Cucumber + Windows path shortening enabled for Cucumber --- build.gradle | 1 + .../infrastructure/core/config/JPAConfig.java | 6 +- .../src/main/resources/application.properties | 1 + .../core/LiquibaseStepDefinitions.java | 151 ++++++++++++------ .../resources/application-test.properties | 1 + .../infrastructure.core.feature | 42 ++++- 6 files changed, 142 insertions(+), 60 deletions(-) diff --git a/build.gradle b/build.gradle index fbbeb6c68..d7abfc604 100644 --- a/build.gradle +++ b/build.gradle @@ -641,6 +641,7 @@ configure(project.fineractJavaProjects) { cucumber { tags = 'not @ignore' main = 'io.cucumber.core.cli.Main' + shorten = "argfile" } // Configuration for spotbugs plugin diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java index 366b37b71..841dea99d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/JPAConfig.java @@ -32,6 +32,7 @@ import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilde import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -52,6 +53,7 @@ import org.springframework.transaction.support.TransactionTemplate; @Configuration @EnableJpaAuditing @EnableJpaRepositories(basePackages = "org.apache.fineract.**.domain") +@EnableConfigurationProperties(JpaProperties.class) public class JPAConfig extends JpaBaseConfiguration { private final DatabaseTypeResolver databaseTypeResolver; @@ -69,8 +71,8 @@ public class JPAConfig extends JpaBaseConfiguration { public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder factoryBuilder) { Map vendorProperties = getVendorProperties(); customizeVendorProperties(vendorProperties); - return factoryBuilder.dataSource(getDataSource()).packages(getPackagesToScan()).properties(vendorProperties) - .persistenceUnit("jpa-pu").packages("org.apache.fineract").jta(false).build(); + return factoryBuilder.dataSource(getDataSource()).properties(vendorProperties).persistenceUnit("jpa-pu") + .packages("org.apache.fineract").jta(false).build(); } @Override diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties index c880e0c57..8d25774aa 100644 --- a/fineract-provider/src/main/resources/application.properties +++ b/fineract-provider/src/main/resources/application.properties @@ -92,6 +92,7 @@ spring.datasource.hikari.dataSourceProperties['maintainTimeStats']=${FINERACT_HI # TODO FINERACT-890: com.mysql.cj.log.Slf4JLogger spring.datasource.hikari.dataSourceProperties['logSlowQueries']=${FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES:true} spring.datasource.hikari.dataSourceProperties['dumpQueriesOnException']=${FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION:true} +spring.jpa.open-in-view=false # Liquibase configuration spring.liquibase.enabled=true diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java index dfaf0e31e..32b5394fa 100644 --- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/LiquibaseStepDefinitions.java @@ -18,8 +18,13 @@ */ package org.apache.fineract.infrastructure.core; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -48,81 +53,121 @@ public class LiquibaseStepDefinitions implements En { private ExtendedSpringLiquibase initialTenantLiquibase; private ExtendedSpringLiquibase tenantLiquibase; private FineractPlatformTenant defaultTenant; - private DataSource defaultTenantDataSource; + private DataSource tenantStoreDataSource; private TenantDatabaseUpgradeService tenantDatabaseUpgradeService; - private List allTenants; - private SchemaUpgradeNeededException result; + private List allTenants; + private SchemaUpgradeNeededException executionException; + private DataSource defaultTenantDataSource; public LiquibaseStepDefinitions() { Given("Liquibase is disabled with a default tenant", () -> { - tenantDataSourceFactory = mock(TenantDataSourceFactory.class); - tenantDetailsService = mock(TenantDetailsService.class); - databaseStateVerifier = mock(TenantDatabaseStateVerifier.class); - fineractProperties = mock(FineractProperties.class); - - liquibaseFactory = mock(ExtendedSpringLiquibaseFactory.class); - - defaultTenant = mock(FineractPlatformTenant.class); - - allTenants = List.of(defaultTenant); - - defaultTenantDataSource = mock(DataSource.class); - - initialTenantLiquibase = mock(ExtendedSpringLiquibase.class); - tenantLiquibase = mock(ExtendedSpringLiquibase.class); - initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class); - tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class); - - given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(true); - given(fineractProperties.getTenant()).willReturn(new FineractProperties.FineractTenantProperties()); - given(liquibaseFactory.create(defaultTenantDataSource, "tenant_store_db", "initial_switch")) - .willReturn(initialTenantStoreLiquibase); - given(liquibaseFactory.create(defaultTenantDataSource, "tenant_store_db")).willReturn(tenantStoreLiquibase); - - given(tenantDetailsService.findAllTenants()).willReturn(allTenants); - given(tenantDataSourceFactory.create(defaultTenant)).willReturn(defaultTenantDataSource); - given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db", "initial_switch")).willReturn(initialTenantLiquibase); - given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db")).willReturn(tenantLiquibase); - - tenantDatabaseUpgradeService = new TenantDatabaseUpgradeService(tenantDetailsService, defaultTenantDataSource, - fineractProperties, databaseStateVerifier, liquibaseFactory, tenantDataSourceFactory); + initializeLiquibase(false); + }); + Given("Liquibase is enabled with a default tenant", () -> { + initializeLiquibase(true); }); Given("Liquibase runs the very first time for the tenant store", () -> { - given(databaseStateVerifier.isFirstLiquibaseMigration(defaultTenantDataSource)).willReturn(true); + given(databaseStateVerifier.isFirstLiquibaseMigration(tenantStoreDataSource)).willReturn(true); }); - Given("A previously Flyway migrated tenant store database", () -> { - given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(true); + Given("A previously Flyway migrated tenant store database on the latest version", () -> { + given(databaseStateVerifier.isFlywayPresent(tenantStoreDataSource)).willReturn(true); + given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(tenantStoreDataSource)).willReturn(true); }); - Given("A previously Flyway migrated tenant store database on an earlier version than 1.6", () -> { - given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(false); + Given("A previously Flyway migrated tenant store database on an earlier version", () -> { + given(databaseStateVerifier.isFlywayPresent(tenantStoreDataSource)).willReturn(true); + given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(tenantStoreDataSource)).willReturn(false); }); Given("Liquibase runs the very first time for the default tenant", () -> { given(databaseStateVerifier.isFirstLiquibaseMigration(defaultTenantDataSource)).willReturn(true); }); - Given("A previously Flyway migrated default tenant database", () -> { + Given("A previously Flyway migrated default tenant database on the latest version", () -> { given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(true); + given(databaseStateVerifier.isTenantOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(true); }); - Given("A previously Flyway migrated default tenant database on the 1.6 version", () -> { - given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(true); + Given("A previously Flyway migrated default tenant database on an earlier version", () -> { + given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(true); + given(databaseStateVerifier.isTenantOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(false); }); When("The database migration process is executed", () -> { - // TODO: @galovics will not throw an exception if disabled = true... but if Liquibase is enabled then "Then" - // section (as layed out in original tests) will fail - // this.result = assertThrows(SchemaUpgradeNeededException.class, () -> - // tenantDatabaseUpgradeService.afterPropertiesSet()); + try { + tenantDatabaseUpgradeService.afterPropertiesSet(); + } catch (SchemaUpgradeNeededException e) { + executionException = e; + } + }); - tenantDatabaseUpgradeService.afterPropertiesSet(); + Then("The database migration did not do anything", () -> { + verify(databaseStateVerifier).isLiquibaseDisabled(); + verifyNoMoreInteractions(databaseStateVerifier); + verifyNoInteractions(tenantDetailsService, tenantStoreDataSource, fineractProperties, liquibaseFactory, + tenantDataSourceFactory); }); Then("The tenant store upgrade fails with a schema upgrade needed", () -> { - // TODO: @galovics verifications work dependent on Liquibase enabled or not... for what should we test? - // assertThat(result).isNotNull(); - // verify(liquibaseFactory).create(eq(defaultTenantDataSource), any()); - + assertThat(executionException).isNotNull(); + verify(liquibaseFactory).create(eq(tenantStoreDataSource), any()); verifyNoMoreInteractions(liquibaseFactory); - verifyNoInteractions(initialTenantStoreLiquibase, tenantStoreLiquibase, initialTenantLiquibase, tenantLiquibase, - defaultTenantDataSource); + verifyNoInteractions(initialTenantStoreLiquibase, tenantStoreLiquibase, initialTenantLiquibase, tenantLiquibase); + }); + + Then("The default tenant upgrade fails with a schema upgrade needed", () -> { + assertThat(executionException).isNotNull(); + verify(liquibaseFactory, times(2)).create(eq(tenantStoreDataSource), any()); + verify(liquibaseFactory).create(eq(defaultTenantDataSource), any()); + verifyNoMoreInteractions(liquibaseFactory); + verify(initialTenantStoreLiquibase).changeLogSync(); + verify(tenantStoreLiquibase).afterPropertiesSet(); + verifyNoInteractions(initialTenantLiquibase, tenantLiquibase); + }); + + Then("The tenant store and the default tenant gets upgraded from scratch", () -> { + verify(initialTenantStoreLiquibase).afterPropertiesSet(); + verify(tenantStoreLiquibase).afterPropertiesSet(); + verify(initialTenantLiquibase).afterPropertiesSet(); + verify(tenantLiquibase).afterPropertiesSet(); + }); + + Then("The tenant store and the default tenant gets synced and then upgraded", () -> { + verify(initialTenantStoreLiquibase).changeLogSync(); + verify(tenantStoreLiquibase).afterPropertiesSet(); + verify(initialTenantLiquibase).changeLogSync(); + verify(tenantLiquibase).afterPropertiesSet(); }); } + + private void initializeLiquibase(boolean liquibaseEnabled) { + tenantDataSourceFactory = mock(TenantDataSourceFactory.class); + tenantDetailsService = mock(TenantDetailsService.class); + databaseStateVerifier = mock(TenantDatabaseStateVerifier.class); + fineractProperties = mock(FineractProperties.class); + + liquibaseFactory = mock(ExtendedSpringLiquibaseFactory.class); + + defaultTenant = mock(FineractPlatformTenant.class); + + allTenants = List.of(defaultTenant); + + tenantStoreDataSource = mock(DataSource.class); + + initialTenantLiquibase = mock(ExtendedSpringLiquibase.class); + tenantLiquibase = mock(ExtendedSpringLiquibase.class); + initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class); + tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class); + + defaultTenantDataSource = mock(DataSource.class); + + given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(!liquibaseEnabled); + given(fineractProperties.getTenant()).willReturn(new FineractProperties.FineractTenantProperties()); + given(liquibaseFactory.create(tenantStoreDataSource, "tenant_store_db", "initial_switch")).willReturn(initialTenantStoreLiquibase); + given(liquibaseFactory.create(tenantStoreDataSource, "tenant_store_db")).willReturn(tenantStoreLiquibase); + + given(tenantDetailsService.findAllTenants()).willReturn(allTenants); + given(tenantDataSourceFactory.create(defaultTenant)).willReturn(defaultTenantDataSource); + given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db", "initial_switch")).willReturn(initialTenantLiquibase); + given(liquibaseFactory.create(defaultTenantDataSource, "tenant_db")).willReturn(tenantLiquibase); + + tenantDatabaseUpgradeService = new TenantDatabaseUpgradeService(tenantDetailsService, tenantStoreDataSource, fineractProperties, + databaseStateVerifier, liquibaseFactory, tenantDataSourceFactory); + } } diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties index b77894796..c714f1384 100644 --- a/fineract-provider/src/test/resources/application-test.properties +++ b/fineract-provider/src/test/resources/application-test.properties @@ -77,3 +77,4 @@ spring.datasource.hikari.dataSourceProperties['elideSetAutoCommits']=true spring.datasource.hikari.dataSourceProperties['maintainTimeStats']=false spring.datasource.hikari.dataSourceProperties['logSlowQueries']=true spring.datasource.hikari.dataSourceProperties['dumpQueriesOnException']=true +spring.jpa.open-in-view=false diff --git a/fineract-provider/src/test/resources/features/infrastructure/infrastructure.core.feature b/fineract-provider/src/test/resources/features/infrastructure/infrastructure.core.feature index 7352ad8ac..a98edda3c 100644 --- a/fineract-provider/src/test/resources/features/infrastructure/infrastructure.core.feature +++ b/fineract-provider/src/test/resources/features/infrastructure/infrastructure.core.feature @@ -1,17 +1,49 @@ Feature: Core Infrastructure @infrastructure - Scenario: Verify that tenant migration service is properly executed + Scenario: Verify that schema migration is not executed when set to disabled Given Liquibase is disabled with a default tenant + When The database migration process is executed + Then The database migration did not do anything + + @infrastructure + Scenario: Verify that schema migration works from scratch + Given Liquibase is enabled with a default tenant Given Liquibase runs the very first time for the tenant store - Given A previously Flyway migrated tenant store database - Given A previously Flyway migrated tenant store database on an earlier version than 1.6 Given Liquibase runs the very first time for the default tenant - Given A previously Flyway migrated default tenant database - Given A previously Flyway migrated default tenant database on the 1.6 version + When The database migration process is executed + Then The tenant store and the default tenant gets upgraded from scratch + + @infrastructure + Scenario: Verify that schema migration works with the latest Flyway migrated schemas + Given Liquibase is enabled with a default tenant + Given Liquibase runs the very first time for the tenant store + Given A previously Flyway migrated tenant store database on the latest version + Given Liquibase runs the very first time for the default tenant + Given A previously Flyway migrated default tenant database on the latest version + When The database migration process is executed + Then The tenant store and the default tenant gets synced and then upgraded + + @infrastructure + Scenario: Verify that schema migration fails when the tenant store is not on the latest Flyway migrated schemas + Given Liquibase is enabled with a default tenant + Given Liquibase runs the very first time for the tenant store + Given A previously Flyway migrated tenant store database on an earlier version + Given Liquibase runs the very first time for the default tenant + Given A previously Flyway migrated default tenant database on the latest version When The database migration process is executed Then The tenant store upgrade fails with a schema upgrade needed + @infrastructure + Scenario: Verify that schema migration fails when the default tenant is not on the latest Flyway migrated schemas + Given Liquibase is enabled with a default tenant + Given Liquibase runs the very first time for the tenant store + Given A previously Flyway migrated tenant store database on the latest version + Given Liquibase runs the very first time for the default tenant + Given A previously Flyway migrated default tenant database on an earlier version + When The database migration process is executed + Then The default tenant upgrade fails with a schema upgrade needed + @infrastructure Scenario Outline: Verify empty multi exceptions Given A multi exception with exceptions and