Readonly connection support
This commit is contained in:
committed by
Arnold Gálovics
parent
2a7d8b9496
commit
e9df96e387
@@ -539,18 +539,6 @@ configure(project.fineractJavaProjects) {
|
|||||||
excludeTestsMatching project.property('excludeTests')
|
excludeTestsMatching project.property('excludeTests')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database type used in the Test
|
|
||||||
systemProperty 'dbType', 'mariadb'
|
|
||||||
if (project.hasProperty('dbType')) {
|
|
||||||
if ('postgresql'.equalsIgnoreCase(dbType)) {
|
|
||||||
systemProperty 'dbType', 'postgresql'
|
|
||||||
} else if ('mysql'.equalsIgnoreCase(dbType)) {
|
|
||||||
systemProperty 'dbType', 'mysql'
|
|
||||||
} else {
|
|
||||||
throw new GradleException('Provided dbType is not supported')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testlogger {
|
testlogger {
|
||||||
|
|||||||
@@ -223,7 +223,6 @@ bootRun {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||||
implementation 'org.postgresql:postgresql:42.3.5'
|
implementation 'org.postgresql:postgresql:42.3.5'
|
||||||
implementation 'mysql:mysql-connector-java:8.0.29'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +288,6 @@ jib {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||||
implementation 'org.postgresql:postgresql:42.3.5'
|
implementation 'org.postgresql:postgresql:42.3.5'
|
||||||
implementation 'mysql:mysql-connector-java:8.0.29'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pluginExtensions {
|
pluginExtensions {
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ public class AdHocScheduledJobRunnerServiceImpl implements AdHocScheduledJobRunn
|
|||||||
run = Math.toIntExact(ChronoUnit.YEARS.between(start, end)) >= 1;
|
run = Math.toIntExact(ChronoUnit.YEARS.between(start, end)) >= 1;
|
||||||
break;
|
break;
|
||||||
case CUSTOM:
|
case CUSTOM:
|
||||||
next = start.plusDays((long) adhoc.getReportRunEvery());
|
next = start.plusDays((int) (long) adhoc.getReportRunEvery());
|
||||||
run = Math.toIntExact(ChronoUnit.DAYS.between(start, end)) >= adhoc.getReportRunEvery();
|
run = Math.toIntExact(ChronoUnit.DAYS.between(start, end)) >= adhoc.getReportRunEvery();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+21
-12
@@ -22,13 +22,12 @@ import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTen
|
|||||||
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
|
import static org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection.toProtocol;
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
||||||
import org.apache.fineract.infrastructure.security.constants.TenantConstants;
|
import org.apache.fineract.infrastructure.security.constants.TenantConstants;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -40,14 +39,24 @@ import org.springframework.stereotype.Component;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class DataSourcePerTenantServiceFactory {
|
public class DataSourcePerTenantServiceFactory {
|
||||||
|
|
||||||
private final HikariConfig hikariConfig;
|
private final HikariConfig hikariConfig;
|
||||||
private final FineractProperties fineractProperties;
|
private final FineractProperties fineractProperties;
|
||||||
private final ApplicationContext context;
|
private final ApplicationContext context;
|
||||||
|
private final DataSource tenantDataSource;
|
||||||
|
private final HikariDataSourceFactory hikariDataSourceFactory;
|
||||||
|
|
||||||
public DataSource createNewDataSourceFor(final DataSource tenantDataSource, final FineractPlatformTenantConnection tenantConnection) {
|
public DataSourcePerTenantServiceFactory(@Qualifier("hikariTenantDataSource") DataSource tenantDataSource, HikariConfig hikariConfig,
|
||||||
|
FineractProperties fineractProperties, ApplicationContext context, HikariDataSourceFactory hikariDataSourceFactory) {
|
||||||
|
this.hikariConfig = hikariConfig;
|
||||||
|
this.fineractProperties = fineractProperties;
|
||||||
|
this.context = context;
|
||||||
|
this.tenantDataSource = tenantDataSource;
|
||||||
|
this.hikariDataSourceFactory = hikariDataSourceFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataSource createNewDataSourceFor(final FineractPlatformTenantConnection tenantConnection) {
|
||||||
String protocol = toProtocol(tenantDataSource);
|
String protocol = toProtocol(tenantDataSource);
|
||||||
// Default properties for Writing
|
// Default properties for Writing
|
||||||
String schemaServer = tenantConnection.getSchemaServer();
|
String schemaServer = tenantConnection.getSchemaServer();
|
||||||
@@ -57,7 +66,7 @@ public class DataSourcePerTenantServiceFactory {
|
|||||||
String schemaPassword = tenantConnection.getSchemaPassword();
|
String schemaPassword = tenantConnection.getSchemaPassword();
|
||||||
String schemaConnectionParameters = tenantConnection.getSchemaConnectionParameters();
|
String schemaConnectionParameters = tenantConnection.getSchemaConnectionParameters();
|
||||||
// Properties to ReadOnly case
|
// Properties to ReadOnly case
|
||||||
if (this.fineractProperties.getMode().isReadOnlyMode()) {
|
if (fineractProperties.getMode().isReadOnlyMode()) {
|
||||||
schemaServer = getPropertyValue(tenantConnection.getReadOnlySchemaServer(), TenantConstants.PROPERTY_RO_SCHEMA_SERVER_NAME,
|
schemaServer = getPropertyValue(tenantConnection.getReadOnlySchemaServer(), TenantConstants.PROPERTY_RO_SCHEMA_SERVER_NAME,
|
||||||
schemaServer);
|
schemaServer);
|
||||||
schemaPort = getPropertyValue(tenantConnection.getReadOnlySchemaServerPort(), TenantConstants.PROPERTY_RO_SCHEMA_SERVER_PORT,
|
schemaPort = getPropertyValue(tenantConnection.getReadOnlySchemaServerPort(), TenantConstants.PROPERTY_RO_SCHEMA_SERVER_PORT,
|
||||||
@@ -75,16 +84,16 @@ public class DataSourcePerTenantServiceFactory {
|
|||||||
log.debug("{}", jdbcUrl);
|
log.debug("{}", jdbcUrl);
|
||||||
|
|
||||||
HikariConfig config = new HikariConfig();
|
HikariConfig config = new HikariConfig();
|
||||||
config.setReadOnly(this.fineractProperties.getMode().isReadOnlyMode());
|
config.setReadOnly(fineractProperties.getMode().isReadOnlyMode());
|
||||||
config.setDriverClassName(hikariConfig.getDriverClassName());
|
|
||||||
config.setPoolName(schemaName + "_pool");
|
|
||||||
config.setJdbcUrl(jdbcUrl);
|
config.setJdbcUrl(jdbcUrl);
|
||||||
|
config.setPoolName(schemaName + "_pool");
|
||||||
config.setUsername(schemaUsername);
|
config.setUsername(schemaUsername);
|
||||||
config.setPassword(schemaPassword);
|
config.setPassword(schemaPassword);
|
||||||
config.setMinimumIdle(tenantConnection.getInitialSize());
|
config.setMinimumIdle(tenantConnection.getInitialSize());
|
||||||
config.setMaximumPoolSize(tenantConnection.getMaxActive());
|
config.setMaximumPoolSize(tenantConnection.getMaxActive());
|
||||||
config.setConnectionTestQuery(hikariConfig.getConnectionTestQuery());
|
|
||||||
config.setValidationTimeout(tenantConnection.getValidationInterval());
|
config.setValidationTimeout(tenantConnection.getValidationInterval());
|
||||||
|
config.setDriverClassName(hikariConfig.getDriverClassName());
|
||||||
|
config.setConnectionTestQuery(hikariConfig.getConnectionTestQuery());
|
||||||
config.setAutoCommit(hikariConfig.isAutoCommit());
|
config.setAutoCommit(hikariConfig.isAutoCommit());
|
||||||
|
|
||||||
// https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management
|
// https://github.com/brettwooldridge/HikariCP/wiki/MBean-(JMX)-Monitoring-and-Management
|
||||||
@@ -96,7 +105,7 @@ public class DataSourcePerTenantServiceFactory {
|
|||||||
// for the all Tenants DB -->
|
// for the all Tenants DB -->
|
||||||
config.setDataSourceProperties(hikariConfig.getDataSourceProperties());
|
config.setDataSourceProperties(hikariConfig.getDataSourceProperties());
|
||||||
|
|
||||||
return new HikariDataSource(config);
|
return hikariDataSourceFactory.create(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPropertyValue(final String baseValue, final String propertyName, final String defaultValue) {
|
private String getPropertyValue(final String baseValue, final String propertyName, final String defaultValue) {
|
||||||
@@ -104,10 +113,10 @@ public class DataSourcePerTenantServiceFactory {
|
|||||||
if (null != baseValue) {
|
if (null != baseValue) {
|
||||||
return baseValue;
|
return baseValue;
|
||||||
}
|
}
|
||||||
if (this.context == null) {
|
if (context == null) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
return this.context.getEnvironment().getProperty(propertyName, defaultValue);
|
return context.getEnvironment().getProperty(propertyName, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class HikariDataSourceFactory {
|
||||||
|
|
||||||
|
public HikariDataSource create(HikariConfig config) {
|
||||||
|
return new HikariDataSource(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -64,7 +64,7 @@ public class TomcatJdbcDataSourcePerTenantService implements RoutingDataSourceSe
|
|||||||
if (possibleDS != null) {
|
if (possibleDS != null) {
|
||||||
tenantDataSource = possibleDS;
|
tenantDataSource = possibleDS;
|
||||||
} else {
|
} else {
|
||||||
tenantDataSource = dataSourcePerTenantServiceFactory.createNewDataSourceFor(this.tenantDataSource, tenantConnection);
|
tenantDataSource = dataSourcePerTenantServiceFactory.createNewDataSourceFor(tenantConnection);
|
||||||
this.tenantToDataSourceMap.put(tenantConnection.getConnectionId(), tenantDataSource);
|
this.tenantToDataSourceMap.put(tenantConnection.getConnectionId(), tenantDataSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-5
@@ -25,11 +25,6 @@
|
|||||||
<dropForeignKeyConstraint baseTableName="job_run_history" constraintName="scheduledjobsFK"/>
|
<dropForeignKeyConstraint baseTableName="job_run_history" constraintName="scheduledjobsFK"/>
|
||||||
</changeSet>
|
</changeSet>
|
||||||
<changeSet author="fineract" id="1">
|
<changeSet author="fineract" id="1">
|
||||||
<validCheckSum>8:18ed72e1958f7db9c1a0c983ac823ab3</validCheckSum> <!-- checksum withsout delete from history -->
|
|
||||||
<validCheckSum>8:b4a83f9764270372a384616acf066d7c</validCheckSum> <!-- checksum with delete from history -->
|
|
||||||
<sql>
|
|
||||||
DELETE FROM job_run_history WHERE job_id IN (SELECT id FROM job WHERE name IN ('Update loan Summary', 'Update Loan Paid In Advance'))
|
|
||||||
</sql>
|
|
||||||
<delete tableName="job">
|
<delete tableName="job">
|
||||||
<where>name='Update loan Summary'</where>
|
<where>name='Update loan Summary'</where>
|
||||||
</delete>
|
</delete>
|
||||||
|
|||||||
+233
@@ -0,0 +1,233 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Properties;
|
||||||
|
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.core.domain.FineractPlatformTenantConnection;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DataSourcePerTenantServiceFactory;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.HikariDataSourceFactory;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
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)
|
||||||
|
public class DataSourcePerTenantServiceFactoryTest {
|
||||||
|
|
||||||
|
public static final String MASTER_DB_SERVER = "localhost";
|
||||||
|
public static final String MASTER_DB_SERVER_PORT = "3306";
|
||||||
|
public static final String MASTER_DB_SCHEMA_NAME = "fineract_tenants";
|
||||||
|
public static final String MASTER_DB_USERNAME = "root";
|
||||||
|
public static final String MASTER_DB_PASSWORD = "password";
|
||||||
|
public static final String MASTER_DB_CONN_PARAMS = "something";
|
||||||
|
public static final String MASTER_DB_JDBC_URL = "jdbc:mariadb://" + MASTER_DB_SERVER + ":" + MASTER_DB_SERVER_PORT + "/"
|
||||||
|
+ MASTER_DB_SCHEMA_NAME + "?" + MASTER_DB_CONN_PARAMS;
|
||||||
|
|
||||||
|
public static final String READONLY_DB_SERVER = "localhost-readonly";
|
||||||
|
public static final String READONLY_DB_SERVER_PORT = "3306-readonly";
|
||||||
|
public static final String READONLY_DB_SCHEMA_NAME = "fineract_tenants-readonly";
|
||||||
|
public static final String READONLY_DB_USERNAME = "root-readonly";
|
||||||
|
public static final String READONLY_DB_PASSWORD = "password-readonly";
|
||||||
|
public static final String READONLY_DB_CONN_PARAMS = "something-readonly";
|
||||||
|
public static final String READONLY_DB_JDBC_URL = "jdbc:mariadb://" + READONLY_DB_SERVER + ":" + READONLY_DB_SERVER_PORT + "/"
|
||||||
|
+ READONLY_DB_SCHEMA_NAME + "?" + READONLY_DB_CONN_PARAMS;
|
||||||
|
|
||||||
|
public static final int MASTER_DB_INITIAL_SIZE = 1;
|
||||||
|
public static final int MASTER_DB_MAX_ACTIVE = 5;
|
||||||
|
public static final long MASTER_DB_VALIDATION_INTERVAL = 500L;
|
||||||
|
public static final long MASTER_DB_INIT_FAIL_TIMEOUT = 0L;
|
||||||
|
|
||||||
|
public static final String MASTER_DB_DRIVER_CLASS_NAME = "org.mariadb.jdbc.Driver";
|
||||||
|
public static final String MASTER_DB_CONN_TEST_QUERY = "SELECT 1";
|
||||||
|
public static final boolean MASTER_DB_AUTO_COMMIT_ENABLED = true;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private FineractProperties fineractProperties;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HikariConfig tenantHikariConfig;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private FineractPlatformTenant defaultTenant;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private FineractPlatformTenantConnection tenantConnection;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSource tenantDataSource;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HikariDataSourceFactory hikariDataSourceFactory;
|
||||||
|
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<HikariConfig> hikariConfigCaptor;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private DataSourcePerTenantServiceFactory underTest;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() throws SQLException {
|
||||||
|
Connection connection = mock(Connection.class);
|
||||||
|
given(tenantDataSource.getConnection()).willReturn(connection);
|
||||||
|
|
||||||
|
DatabaseMetaData databaseMetaData = mock(DatabaseMetaData.class);
|
||||||
|
given(connection.getMetaData()).willReturn(databaseMetaData);
|
||||||
|
|
||||||
|
given(databaseMetaData.getURL()).willReturn("jdbc:mariadb://localhost:3306/fineract_tenants");
|
||||||
|
|
||||||
|
given(tenantConnection.getSchemaServer()).willReturn(MASTER_DB_SERVER);
|
||||||
|
given(tenantConnection.getSchemaServerPort()).willReturn(MASTER_DB_SERVER_PORT);
|
||||||
|
given(tenantConnection.getSchemaName()).willReturn(MASTER_DB_SCHEMA_NAME);
|
||||||
|
given(tenantConnection.getSchemaUsername()).willReturn(MASTER_DB_USERNAME);
|
||||||
|
given(tenantConnection.getSchemaPassword()).willReturn(MASTER_DB_PASSWORD);
|
||||||
|
given(tenantConnection.getSchemaConnectionParameters()).willReturn(MASTER_DB_CONN_PARAMS);
|
||||||
|
|
||||||
|
given(tenantConnection.getReadOnlySchemaServer()).willReturn(READONLY_DB_SERVER);
|
||||||
|
given(tenantConnection.getReadOnlySchemaServerPort()).willReturn(READONLY_DB_SERVER_PORT);
|
||||||
|
given(tenantConnection.getReadOnlySchemaName()).willReturn(READONLY_DB_SCHEMA_NAME);
|
||||||
|
given(tenantConnection.getReadOnlySchemaUsername()).willReturn(READONLY_DB_USERNAME);
|
||||||
|
given(tenantConnection.getReadOnlySchemaPassword()).willReturn(READONLY_DB_PASSWORD);
|
||||||
|
given(tenantConnection.getReadOnlySchemaConnectionParameters()).willReturn(READONLY_DB_CONN_PARAMS);
|
||||||
|
|
||||||
|
given(defaultTenant.getConnection()).willReturn(tenantConnection);
|
||||||
|
given(tenantConnection.getInitialSize()).willReturn(MASTER_DB_INITIAL_SIZE);
|
||||||
|
given(tenantConnection.getMaxActive()).willReturn(MASTER_DB_MAX_ACTIVE);
|
||||||
|
given(tenantConnection.getValidationInterval()).willReturn(MASTER_DB_VALIDATION_INTERVAL);
|
||||||
|
|
||||||
|
given(tenantHikariConfig.getInitializationFailTimeout()).willReturn(MASTER_DB_INIT_FAIL_TIMEOUT);
|
||||||
|
given(tenantHikariConfig.getDriverClassName()).willReturn(MASTER_DB_DRIVER_CLASS_NAME);
|
||||||
|
given(tenantHikariConfig.getConnectionTestQuery()).willReturn(MASTER_DB_CONN_TEST_QUERY);
|
||||||
|
given(tenantHikariConfig.getDataSourceProperties()).willReturn(mock(Properties.class));
|
||||||
|
given(tenantHikariConfig.isAutoCommit()).willReturn(MASTER_DB_AUTO_COMMIT_ENABLED);
|
||||||
|
|
||||||
|
given(hikariDataSourceFactory.create(any())).willReturn(mock(HikariDataSource.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateNewDataSourceFor_ShouldUseNormalConfiguration_WhenInAllMode() {
|
||||||
|
// given
|
||||||
|
FineractProperties.FineractModeProperties modeProperties = createModeProps(MASTER_DB_AUTO_COMMIT_ENABLED,
|
||||||
|
MASTER_DB_AUTO_COMMIT_ENABLED, MASTER_DB_AUTO_COMMIT_ENABLED);
|
||||||
|
given(fineractProperties.getMode()).willReturn(modeProperties);
|
||||||
|
|
||||||
|
// when
|
||||||
|
DataSource dataSource = underTest.createNewDataSourceFor(defaultTenant.getConnection());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(dataSource);
|
||||||
|
verify(hikariDataSourceFactory).create(hikariConfigCaptor.capture());
|
||||||
|
HikariConfig hikariConfig = hikariConfigCaptor.getValue();
|
||||||
|
assertFalse(hikariConfig.isReadOnly());
|
||||||
|
assertEquals(MASTER_DB_JDBC_URL, hikariConfig.getJdbcUrl());
|
||||||
|
assertEquals(MASTER_DB_SCHEMA_NAME + "_pool", hikariConfig.getPoolName());
|
||||||
|
assertEquals(MASTER_DB_USERNAME, hikariConfig.getUsername());
|
||||||
|
assertEquals(MASTER_DB_PASSWORD, hikariConfig.getPassword());
|
||||||
|
assertEquals(MASTER_DB_INITIAL_SIZE, hikariConfig.getMinimumIdle());
|
||||||
|
assertEquals(MASTER_DB_MAX_ACTIVE, hikariConfig.getMaximumPoolSize());
|
||||||
|
assertEquals(MASTER_DB_VALIDATION_INTERVAL, hikariConfig.getValidationTimeout());
|
||||||
|
assertEquals(MASTER_DB_DRIVER_CLASS_NAME, hikariConfig.getDriverClassName());
|
||||||
|
assertEquals(MASTER_DB_CONN_TEST_QUERY, hikariConfig.getConnectionTestQuery());
|
||||||
|
assertEquals(MASTER_DB_AUTO_COMMIT_ENABLED, hikariConfig.isAutoCommit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateNewDataSourceFor_ShouldUseReadOnlyConfiguration_WhenInReadOnlyMode() {
|
||||||
|
// given
|
||||||
|
FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false);
|
||||||
|
given(fineractProperties.getMode()).willReturn(modeProperties);
|
||||||
|
|
||||||
|
// when
|
||||||
|
DataSource dataSource = underTest.createNewDataSourceFor(defaultTenant.getConnection());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(dataSource);
|
||||||
|
verify(hikariDataSourceFactory).create(hikariConfigCaptor.capture());
|
||||||
|
HikariConfig hikariConfig = hikariConfigCaptor.getValue();
|
||||||
|
assertTrue(hikariConfig.isReadOnly());
|
||||||
|
assertEquals(READONLY_DB_JDBC_URL, hikariConfig.getJdbcUrl());
|
||||||
|
assertEquals(READONLY_DB_SCHEMA_NAME + "_pool", hikariConfig.getPoolName());
|
||||||
|
assertEquals(READONLY_DB_USERNAME, hikariConfig.getUsername());
|
||||||
|
assertEquals(READONLY_DB_PASSWORD, hikariConfig.getPassword());
|
||||||
|
assertEquals(MASTER_DB_INITIAL_SIZE, hikariConfig.getMinimumIdle());
|
||||||
|
assertEquals(MASTER_DB_MAX_ACTIVE, hikariConfig.getMaximumPoolSize());
|
||||||
|
assertEquals(MASTER_DB_VALIDATION_INTERVAL, hikariConfig.getValidationTimeout());
|
||||||
|
assertEquals(MASTER_DB_DRIVER_CLASS_NAME, hikariConfig.getDriverClassName());
|
||||||
|
assertEquals(MASTER_DB_CONN_TEST_QUERY, hikariConfig.getConnectionTestQuery());
|
||||||
|
assertEquals(MASTER_DB_AUTO_COMMIT_ENABLED, hikariConfig.isAutoCommit());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCreateNewDataSourceFor_ShouldUseNormalConfiguration_WhenInBatchOnlyMode() {
|
||||||
|
// given
|
||||||
|
FineractProperties.FineractModeProperties modeProperties = createModeProps(false, false, true);
|
||||||
|
given(fineractProperties.getMode()).willReturn(modeProperties);
|
||||||
|
|
||||||
|
// when
|
||||||
|
DataSource dataSource = underTest.createNewDataSourceFor(defaultTenant.getConnection());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(dataSource);
|
||||||
|
verify(hikariDataSourceFactory).create(hikariConfigCaptor.capture());
|
||||||
|
HikariConfig hikariConfig = hikariConfigCaptor.getValue();
|
||||||
|
assertFalse(hikariConfig.isReadOnly());
|
||||||
|
assertEquals(MASTER_DB_JDBC_URL, hikariConfig.getJdbcUrl());
|
||||||
|
assertEquals(MASTER_DB_SCHEMA_NAME + "_pool", hikariConfig.getPoolName());
|
||||||
|
assertEquals(MASTER_DB_USERNAME, hikariConfig.getUsername());
|
||||||
|
assertEquals(MASTER_DB_PASSWORD, hikariConfig.getPassword());
|
||||||
|
assertEquals(MASTER_DB_INITIAL_SIZE, hikariConfig.getMinimumIdle());
|
||||||
|
assertEquals(MASTER_DB_MAX_ACTIVE, hikariConfig.getMaximumPoolSize());
|
||||||
|
assertEquals(MASTER_DB_VALIDATION_INTERVAL, hikariConfig.getValidationTimeout());
|
||||||
|
assertEquals(MASTER_DB_DRIVER_CLASS_NAME, hikariConfig.getDriverClassName());
|
||||||
|
assertEquals(MASTER_DB_CONN_TEST_QUERY, hikariConfig.getConnectionTestQuery());
|
||||||
|
assertEquals(MASTER_DB_AUTO_COMMIT_ENABLED, hikariConfig.isAutoCommit());
|
||||||
|
}
|
||||||
|
|
||||||
|
private FineractProperties.FineractModeProperties createModeProps(boolean readEnabled, boolean writeEnabled, boolean batchEnabled) {
|
||||||
|
FineractProperties.FineractModeProperties modeProperties = new FineractProperties.FineractModeProperties();
|
||||||
|
modeProperties.setReadEnabled(readEnabled);
|
||||||
|
modeProperties.setWriteEnabled(writeEnabled);
|
||||||
|
modeProperties.setBatchEnabled(batchEnabled);
|
||||||
|
return modeProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
-147
@@ -1,147 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
import com.zaxxer.hikari.HikariConfig;
|
|
||||||
import com.zaxxer.hikari.HikariDataSource;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DatabaseMetaData;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Properties;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
|
||||||
import org.apache.fineract.infrastructure.core.db.DatabaseConnectionProperties;
|
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenantConnection;
|
|
||||||
import org.apache.fineract.infrastructure.core.service.DataSourcePerTenantServiceFactory;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.mockito.InjectMocks;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
|
||||||
import org.mockito.junit.jupiter.MockitoSettings;
|
|
||||||
import org.mockito.quality.Strictness;
|
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
|
||||||
@TestPropertySource("classpath:application-test.properties")
|
|
||||||
public class TomcatJdbcDataSourcePerTenantServiceTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private FineractProperties fineractProperties;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private HikariConfig hikariConfig;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private Connection connection;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private FineractPlatformTenant defaultTenant;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private FineractPlatformTenantConnection tenantConnection;
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
private DataSourcePerTenantServiceFactory underTest;
|
|
||||||
|
|
||||||
private DataSource dataSource;
|
|
||||||
private DataSource tenantDataSource;
|
|
||||||
private DatabaseConnectionProperties databaseConnectionProperties;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() throws SQLException {
|
|
||||||
this.databaseConnectionProperties = DatabaseConnectionProperties.instance(System.getProperty("dbType"));
|
|
||||||
|
|
||||||
tenantDataSource = mock(HikariDataSource.class);
|
|
||||||
given(tenantDataSource.getConnection()).willReturn(connection);
|
|
||||||
given(connection.getMetaData()).willReturn(mock(DatabaseMetaData.class));
|
|
||||||
given(connection.getMetaData().getURL()).willReturn(databaseConnectionProperties.getJdbcUrl());
|
|
||||||
|
|
||||||
given(tenantConnection.getSchemaServer()).willReturn(databaseConnectionProperties.getSchemaServer());
|
|
||||||
given(tenantConnection.getSchemaServerPort()).willReturn(databaseConnectionProperties.getSchemaPort());
|
|
||||||
given(tenantConnection.getSchemaUsername()).willReturn(databaseConnectionProperties.getSchemaUsername());
|
|
||||||
given(tenantConnection.getSchemaPassword()).willReturn(databaseConnectionProperties.getSchemaPassword());
|
|
||||||
given(tenantConnection.getSchemaName()).willReturn(databaseConnectionProperties.getSchemaName());
|
|
||||||
|
|
||||||
given(defaultTenant.getConnection()).willReturn(tenantConnection);
|
|
||||||
given(defaultTenant.getConnection().getMaxActive()).willReturn(5);
|
|
||||||
given(defaultTenant.getConnection().getValidationInterval()).willReturn(500L);
|
|
||||||
|
|
||||||
given(hikariConfig.getInitializationFailTimeout()).willReturn(0L);
|
|
||||||
given(hikariConfig.getDriverClassName()).willReturn(databaseConnectionProperties.getDriverClassName());
|
|
||||||
given(hikariConfig.getConnectionTestQuery()).willReturn(databaseConnectionProperties.getConnectionTestQuery());
|
|
||||||
given(hikariConfig.getDataSourceProperties()).willReturn(mock(Properties.class));
|
|
||||||
given(hikariConfig.isAutoCommit()).willReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRetrieveDataSource_ShouldCreateDataSource_WhenFineractIsInAllMode() {
|
|
||||||
// given
|
|
||||||
FineractProperties.FineractModeProperties modeProperties = createModeProps(true, true, true);
|
|
||||||
given(fineractProperties.getMode()).willReturn(modeProperties);
|
|
||||||
|
|
||||||
// when
|
|
||||||
dataSource = underTest.createNewDataSourceFor(tenantDataSource, defaultTenant.getConnection());
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertNotNull(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRetrieveDataSource_ShouldCreateDataSource_WhenFineractIsInReadOnlyMode() {
|
|
||||||
// given
|
|
||||||
FineractProperties.FineractModeProperties modeProperties = createModeProps(true, false, false);
|
|
||||||
given(fineractProperties.getMode()).willReturn(modeProperties);
|
|
||||||
|
|
||||||
// when
|
|
||||||
dataSource = underTest.createNewDataSourceFor(tenantDataSource, defaultTenant.getConnection());
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertNotNull(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testRetrieveDataSource_ShouldCreateDataSource_WhenFineractIsInBatchMode() {
|
|
||||||
// given
|
|
||||||
FineractProperties.FineractModeProperties modeProperties = createModeProps(false, false, true);
|
|
||||||
given(fineractProperties.getMode()).willReturn(modeProperties);
|
|
||||||
|
|
||||||
// when
|
|
||||||
dataSource = underTest.createNewDataSourceFor(tenantDataSource, defaultTenant.getConnection());
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertNotNull(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
private FineractProperties.FineractModeProperties createModeProps(boolean readEnabled, boolean writeEnabled, boolean batchEnabled) {
|
|
||||||
FineractProperties.FineractModeProperties modeProperties = new FineractProperties.FineractModeProperties();
|
|
||||||
modeProperties.setReadEnabled(readEnabled);
|
|
||||||
modeProperties.setWriteEnabled(writeEnabled);
|
|
||||||
modeProperties.setBatchEnabled(batchEnabled);
|
|
||||||
return modeProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-111
@@ -1,111 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.db;
|
|
||||||
|
|
||||||
public class DatabaseConnectionProperties {
|
|
||||||
|
|
||||||
private String driverClassName;
|
|
||||||
private String jdbcUrl;
|
|
||||||
private String connectionTestQuery;
|
|
||||||
|
|
||||||
private String schemaServer;
|
|
||||||
private String schemaName;
|
|
||||||
private String schemaPort;
|
|
||||||
private String schemaUsername;
|
|
||||||
private String schemaPassword;
|
|
||||||
|
|
||||||
protected DatabaseConnectionProperties(final String driverClassName, final String jdbcUrl, final String schemaPort,
|
|
||||||
final String schemaPassword) {
|
|
||||||
this.driverClassName = driverClassName;
|
|
||||||
this.jdbcUrl = jdbcUrl;
|
|
||||||
this.schemaPort = schemaPort;
|
|
||||||
this.schemaPassword = schemaPassword;
|
|
||||||
|
|
||||||
this.schemaServer = "localhost";
|
|
||||||
this.schemaUsername = "root";
|
|
||||||
this.schemaName = "fineract_tenants";
|
|
||||||
this.connectionTestQuery = "SELECT 1";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DatabaseConnectionProperties instance(final String dbType) {
|
|
||||||
return new DatabaseConnectionProperties(getDbDriverClassName(dbType), buildJdbcUrl(dbType), getDbPort(dbType),
|
|
||||||
getDbPassword(dbType));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getDbDriverClassName(final String dbType) {
|
|
||||||
if (dbType.equals("mariadb")) {
|
|
||||||
return "org.mariadb.jdbc.Driver";
|
|
||||||
} else if (dbType.equals("mysql")) {
|
|
||||||
return "com.mysql.cj.jdbc.Driver";
|
|
||||||
} else {
|
|
||||||
return "org.postgresql.Driver";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String buildJdbcUrl(final String dbType) {
|
|
||||||
return "jdbc:" + dbType + "://localhost:" + getDbPort(dbType) + "/fineract_tenants";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getDbPort(final String dbType) {
|
|
||||||
if (dbType.equals("postgresql")) {
|
|
||||||
return "5432";
|
|
||||||
}
|
|
||||||
return "3306";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getDbPassword(final String dbType) {
|
|
||||||
if (dbType.equals("postgresql")) {
|
|
||||||
return "postgres";
|
|
||||||
}
|
|
||||||
return "mysql";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDriverClassName() {
|
|
||||||
return driverClassName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getJdbcUrl() {
|
|
||||||
return jdbcUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getConnectionTestQuery() {
|
|
||||||
return connectionTestQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSchemaServer() {
|
|
||||||
return schemaServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSchemaName() {
|
|
||||||
return schemaName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSchemaPort() {
|
|
||||||
return schemaPort;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSchemaUsername() {
|
|
||||||
return schemaUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSchemaPassword() {
|
|
||||||
return schemaPassword;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user