FINERACT-1498: Switching from Flyway to Liqubase migrations

This commit is contained in:
Arnold Galovics
2022-02-19 22:55:32 +01:00
committed by Aleksandar Vidakovic
parent 746c589a6e
commit 45bed0a05a
34 changed files with 30137 additions and 189 deletions
@@ -18,10 +18,14 @@
*/
package org.apache.fineract.infrastructure.configuration.spring;
import static org.mockito.Mockito.mock;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.service.TenantDatabaseUpgradeService;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.migration.TenantDataSourceFactory;
import org.apache.fineract.infrastructure.core.service.migration.TenantDatabaseUpgradeService;
import org.apache.fineract.infrastructure.jobs.service.JobRegisterService;
import org.mockito.Mockito;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -38,16 +42,27 @@ import org.springframework.security.crypto.password.PasswordEncoder;
@EnableConfigurationProperties({ FineractProperties.class })
public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicationConfiguration {
@Bean
public TenantDataSourceFactory tenantDataSourceFactory() {
return new TenantDataSourceFactory(null) {
@Override
public DataSource create(FineractPlatformTenant tenant) {
return mock(DataSource.class);
}
};
}
/**
* Override TenantDatabaseUpgradeService binding, because the real one has a @PostConstruct upgradeAllTenants()
* which accesses the database on start-up.
*/
@Bean
public TenantDatabaseUpgradeService tenantDatabaseUpgradeService() {
return new TenantDatabaseUpgradeService(null, null, null, null) {
return new TenantDatabaseUpgradeService(null, null, null, null, null, null) {
@Override
public void upgradeAllTenants() {
public void afterPropertiesSet() {
// NOOP
}
};
@@ -59,7 +74,7 @@ public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicat
*/
@Bean
public JobRegisterService jobRegisterServiceImpl() {
JobRegisterService mockJobRegisterService = Mockito.mock(JobRegisterService.class);
JobRegisterService mockJobRegisterService = mock(JobRegisterService.class);
return mockJobRegisterService;
}
@@ -68,7 +83,7 @@ public class TestsWithoutDatabaseAndNoJobsConfiguration extends AbstractApplicat
*/
@Bean
public DataSource hikariTenantDataSource() {
DataSource mockDataSource = Mockito.mock(DataSource.class, Mockito.RETURNS_MOCKS);
DataSource mockDataSource = mock(DataSource.class, Mockito.RETURNS_MOCKS);
return mockDataSource;
}
@@ -0,0 +1,219 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.service.migration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
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;
import com.zaxxer.hikari.HikariDataSource;
import java.util.List;
import javax.sql.DataSource;
import org.apache.fineract.infrastructure.core.config.FineractProperties;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.security.service.TenantDetailsService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class TenantDatabaseUpgradeServiceTest {
@Mock
private TenantDetailsService tenantDetailsService;
@Mock
private HikariDataSource tenantDataSource;
@Mock
private FineractProperties fineractProperties;
@Mock
private TenantDatabaseStateVerifier databaseStateVerifier;
@Mock
private ExtendedSpringLiquibaseFactory liquibaseFactory;
@Mock
private TenantDataSourceFactory tenantDataSourceFactory;
private TenantDatabaseUpgradeService underTest;
@BeforeEach
public void setUp() {
underTest = new TenantDatabaseUpgradeService(tenantDetailsService, tenantDataSource, fineractProperties, databaseStateVerifier,
liquibaseFactory, tenantDataSourceFactory);
}
@Test
public void testAfterPropertiesSetDoesNotDoAnythingWhenLiquibaseIsDisabled() throws Exception {
// given
given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(true);
// when
underTest.afterPropertiesSet();
// then
verify(databaseStateVerifier).isLiquibaseDisabled();
verifyNoMoreInteractions(databaseStateVerifier);
verifyNoInteractions(tenantDetailsService, tenantDataSource, fineractProperties, liquibaseFactory, tenantDataSourceFactory);
}
@Test
public void testAfterPropertiesSetGetsLiquibaseAppliedWhenStartingFromScratch() throws Exception {
// given
ExtendedSpringLiquibase initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(false);
given(databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(tenantDataSource)).willReturn(false);
given(fineractProperties.getTenant()).willReturn(new FineractProperties.FineractTenantProperties());
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db", "initial_switch")).willReturn(initialTenantStoreLiquibase);
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db")).willReturn(tenantStoreLiquibase);
ExtendedSpringLiquibase initialTenantLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantLiquibase = mock(ExtendedSpringLiquibase.class);
FineractPlatformTenant defaultTenant = mock(FineractPlatformTenant.class);
List<FineractPlatformTenant> allTenants = List.of(defaultTenant);
DataSource defaultTenantDataSource = mock(DataSource.class);
given(databaseStateVerifier.isFirstLiquibaseMigration(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(false);
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);
// when
underTest.afterPropertiesSet();
// then
verify(initialTenantStoreLiquibase).afterPropertiesSet();
verify(tenantStoreLiquibase).afterPropertiesSet();
verify(initialTenantLiquibase).afterPropertiesSet();
verify(tenantLiquibase).afterPropertiesSet();
}
@Test
public void testAfterPropertiesSetSyncsTheInitialChangeLogAndAppliesRemainingChangesWhenFlywayIsOnLatestVersion() throws Exception {
// given
ExtendedSpringLiquibase initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(false);
given(databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(tenantDataSource)).willReturn(true);
given(fineractProperties.getTenant()).willReturn(new FineractProperties.FineractTenantProperties());
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db", "initial_switch")).willReturn(initialTenantStoreLiquibase);
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db")).willReturn(tenantStoreLiquibase);
ExtendedSpringLiquibase initialTenantLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantLiquibase = mock(ExtendedSpringLiquibase.class);
FineractPlatformTenant defaultTenant = mock(FineractPlatformTenant.class);
List<FineractPlatformTenant> allTenants = List.of(defaultTenant);
DataSource defaultTenantDataSource = mock(DataSource.class);
given(databaseStateVerifier.isFirstLiquibaseMigration(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isTenantOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(true);
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);
// when
underTest.afterPropertiesSet();
// then
verify(initialTenantStoreLiquibase).changeLogSync();
verify(tenantStoreLiquibase).afterPropertiesSet();
verify(initialTenantLiquibase).changeLogSync();
verify(tenantLiquibase).afterPropertiesSet();
}
@Test
public void testAfterPropertiesSetFailsWhenTenantStoreFlywayIsNotOnLatestVersion() throws Exception {
// given
ExtendedSpringLiquibase initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(false);
given(databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(tenantDataSource)).willReturn(false);
given(fineractProperties.getTenant()).willReturn(new FineractProperties.FineractTenantProperties());
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db", "initial_switch")).willReturn(initialTenantStoreLiquibase);
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db")).willReturn(tenantStoreLiquibase);
ExtendedSpringLiquibase initialTenantLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantLiquibase = mock(ExtendedSpringLiquibase.class);
FineractPlatformTenant defaultTenant = mock(FineractPlatformTenant.class);
List<FineractPlatformTenant> allTenants = List.of(defaultTenant);
DataSource defaultTenantDataSource = mock(DataSource.class);
given(databaseStateVerifier.isFirstLiquibaseMigration(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isTenantOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(true);
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);
// when
SchemaUpgradeNeededException result = assertThrows(SchemaUpgradeNeededException.class, () -> underTest.afterPropertiesSet());
// then
assertThat(result).isNotNull();
verify(liquibaseFactory).create(eq(tenantDataSource), any());
verifyNoMoreInteractions(liquibaseFactory);
verifyNoInteractions(initialTenantStoreLiquibase, tenantStoreLiquibase, initialTenantLiquibase, tenantLiquibase);
}
@Test
public void testAfterPropertiesSetFailsWhenTenantFlywayIsNotOnLatestVersion() throws Exception {
// given
ExtendedSpringLiquibase initialTenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantStoreLiquibase = mock(ExtendedSpringLiquibase.class);
given(databaseStateVerifier.isLiquibaseDisabled()).willReturn(false);
given(databaseStateVerifier.isFirstLiquibaseMigration(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(tenantDataSource)).willReturn(true);
given(databaseStateVerifier.isTenantStoreOnLatestUpgradableVersion(tenantDataSource)).willReturn(true);
given(fineractProperties.getTenant()).willReturn(new FineractProperties.FineractTenantProperties());
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db", "initial_switch")).willReturn(initialTenantStoreLiquibase);
given(liquibaseFactory.create(tenantDataSource, "tenant_store_db")).willReturn(tenantStoreLiquibase);
ExtendedSpringLiquibase initialTenantLiquibase = mock(ExtendedSpringLiquibase.class);
ExtendedSpringLiquibase tenantLiquibase = mock(ExtendedSpringLiquibase.class);
FineractPlatformTenant defaultTenant = mock(FineractPlatformTenant.class);
List<FineractPlatformTenant> allTenants = List.of(defaultTenant);
DataSource defaultTenantDataSource = mock(DataSource.class);
given(databaseStateVerifier.isFirstLiquibaseMigration(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isFlywayPresent(defaultTenantDataSource)).willReturn(true);
given(databaseStateVerifier.isTenantOnLatestUpgradableVersion(defaultTenantDataSource)).willReturn(false);
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);
// when
SchemaUpgradeNeededException result = assertThrows(SchemaUpgradeNeededException.class, () -> underTest.afterPropertiesSet());
// then
assertThat(result).isNotNull();
verify(liquibaseFactory, times(2)).create(eq(tenantDataSource), any());
verify(liquibaseFactory).create(eq(defaultTenantDataSource), any());
verifyNoMoreInteractions(liquibaseFactory);
verify(initialTenantStoreLiquibase).changeLogSync();
verify(tenantStoreLiquibase).afterPropertiesSet();
verifyNoInteractions(initialTenantLiquibase, tenantLiquibase);
}
}