Files
FT546-WCS/ruoyi-wcs-shadow/src/test/java/com/ruoyi/shadow/config/ShadowDataSourceIsolationTest.java

149 lines
5.9 KiB
Java

package com.ruoyi.shadow.config;
import com.ruoyi.shadow.startup.ShadowDatabaseIdentity;
import com.zaxxer.hikari.HikariDataSource;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
import java.sql.Connection;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.springframework.transaction.support.TransactionTemplate;
class ShadowDataSourceIsolationTest {
@Test
void sourcePoolIsReadOnlyBoundedAndFailsFast() {
ShadowProperties properties = properties();
ShadowSourceConfiguration configuration =
new ShadowSourceConfiguration();
HikariDataSource source = (HikariDataSource)
configuration.shadowSourceDataSource(properties);
try {
assertTrue(source.isReadOnly());
assertEquals(2, source.getMaximumPoolSize());
assertEquals(0, source.getMinimumIdle());
assertEquals(2_000L, source.getConnectionTimeout());
assertEquals("SET TRANSACTION ISOLATION LEVEL READ COMMITTED",
source.getConnectionInitSql());
JdbcTemplate jdbc = configuration.shadowSourceJdbc(source);
assertEquals(3, jdbc.getQueryTimeout());
DataSourceTransactionManager tx =
configuration.shadowSourceTx(source);
assertTrue(tx.isEnforceReadOnly());
} finally {
source.close();
}
}
@Test
void sourceAndEvidenceUseDifferentPoolsAndTransactionManagers() {
ShadowProperties properties = properties();
ShadowSourceConfiguration sourceConfiguration =
new ShadowSourceConfiguration();
ShadowEvidenceConfiguration evidenceConfiguration =
new ShadowEvidenceConfiguration();
HikariDataSource source = (HikariDataSource)
sourceConfiguration.shadowSourceDataSource(properties);
HikariDataSource evidence = (HikariDataSource)
evidenceConfiguration.shadowEvidenceDataSource(properties);
try {
assertNotSame(source, evidence);
assertTrue(source.isReadOnly());
assertFalse(evidence.isReadOnly());
assertNotSame(sourceConfiguration.shadowSourceTx(source),
evidenceConfiguration.shadowEvidenceTx(evidence));
} finally {
source.close();
evidence.close();
}
}
@Test
void sourceReadOnlyTransactionDoesNotEmitUnsupportedSqlServerSyntax()
throws Exception {
DataSource source = mock(DataSource.class);
Connection connection = mock(Connection.class);
when(source.getConnection()).thenReturn(connection);
when(connection.getAutoCommit()).thenReturn(true);
DataSourceTransactionManager tx =
new ShadowSourceConfiguration().shadowSourceTx(source);
TransactionTemplate transaction = new TransactionTemplate(tx);
transaction.setReadOnly(true);
transaction.execute(status -> null);
verify(connection).setReadOnly(true);
verify(connection, never()).createStatement();
}
@Test
void sourceAndEvidenceCannotResolveToTheSamePhysicalDatabase() {
ShadowDatabaseIdentity source = ShadowDatabaseIdentity.fromJdbcUrl(
"jdbc:sqlserver://prod-db:1433;databaseName=FT546-wcs",
"ft546_shadow_ro");
ShadowDatabaseIdentity evidence = ShadowDatabaseIdentity.fromJdbcUrl(
"jdbc:sqlserver://PROD-DB:1433;databaseName=ft546-WCS",
"ft546_shadow_evidence");
IllegalStateException failure = assertThrows(
IllegalStateException.class,
() -> ShadowDatabaseIdentity.requirePhysicallyDistinct(
source, evidence));
assertEquals("SOURCE_AND_EVIDENCE_DATABASE_MUST_DIFFER",
failure.getMessage());
}
@Test
void distinctDatabasesOnTheSameServerAreAccepted() {
ShadowDatabaseIdentity source = ShadowDatabaseIdentity.fromJdbcUrl(
"jdbc:sqlserver://prod-db:1433;databaseName=FT546-wcs",
"ft546_shadow_ro");
ShadowDatabaseIdentity evidence = ShadowDatabaseIdentity.fromJdbcUrl(
"jdbc:sqlserver://prod-db:1433;databaseName=FT546-shadow",
"ft546_shadow_evidence");
ShadowDatabaseIdentity.requirePhysicallyDistinct(source, evidence);
}
@Test
void jdbcIdentityRequiresAnExplicitServerName() {
IllegalStateException failure = assertThrows(
IllegalStateException.class,
() -> ShadowDatabaseIdentity.fromJdbcUrl(
"jdbc:sqlserver://;databaseName=FT546-wcs",
"ft546_shadow_ro"));
assertEquals("JDBC_SERVER_NAME_REQUIRED", failure.getMessage());
}
private static ShadowProperties properties() {
ShadowProperties properties = new ShadowProperties();
properties.getSource().setJdbcUrl(
"jdbc:h2:mem:source;DB_CLOSE_DELAY=-1");
properties.getSource().setUsername("source_user");
properties.getSource().setPassword("source_password");
properties.getEvidence().setJdbcUrl(
"jdbc:h2:mem:evidence;DB_CLOSE_DELAY=-1");
properties.getEvidence().setUsername("evidence_user");
properties.getEvidence().setPassword("evidence_password");
return properties;
}
}