package kr.pe.kwonnam.replicationdatasource;
import kr.pe.kwonnam.replicationdatasource.LazyReplicationConnectionDataSourceProxy;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Transaction없이 {@link java.sql.Connection#setReadOnly(boolean)} 만으로 Replication 분기하는지 테스트.
* 아래의 JDBC 코드는 간략화한 것으로 올바르지 않으니 실전 환경에서는 따라하지 마시오.
*/
public class LazyReplicationConnectionDataSourceProxyConnectionIntegrationTest {
private static DataSource replicationDataSource;
@BeforeClass
public static void setUpClass() throws Exception {
DataSource writeDataSource = new EmbeddedDatabaseBuilder()
.setName("writeDb")
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("classpath:/writedb.sql").build();
DataSource readDataSource = new EmbeddedDatabaseBuilder()
.setName("readDb")
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScript("classpath:/readdb.sql").build();
replicationDataSource = new LazyReplicationConnectionDataSourceProxy(writeDataSource, readDataSource);
}
public String queryName(Connection connection, Integer id) throws Exception {
PreparedStatement statement = connection.prepareStatement("select * from users where id = ?");
statement.setInt(1, id);
ResultSet resultSet = statement.executeQuery();
resultSet.next();
String name = resultSet.getString("name");
resultSet.close();
statement.close();
return name;
}
@Test
public void fromRead() throws Exception {
Connection connection = replicationDataSource.getConnection();
connection.setReadOnly(true);
String name = queryName(connection, 1);
assertThat(name).isEqualTo("read_1");
connection.close();
}
@Test
public void fromWrite() throws Exception {
Connection connection = replicationDataSource.getConnection();
connection.setReadOnly(false);
String name = queryName(connection, 3);
assertThat(name).isEqualTo("write_3");
connection.close();
}
/**
* 하나의 Connection으로 readOnly true -> false 형태의 재사용은 불가한다.
* @throws Exception
*/
@Test
public void read_write_switch_fail() throws Exception {
Connection connection = replicationDataSource.getConnection();
connection.setReadOnly(false);
String readOnlyFalseName = queryName(connection, 1);
assertThat(readOnlyFalseName).isEqualTo("write_1");
connection.setReadOnly(true);
String readOnlyTrueName = queryName(connection, 2);
assertThat(readOnlyTrueName).as("If connection reused, readOnly configuration follows the first setReadOnly value.").isEqualTo("write_2");
connection.close();
}
}