/*
* Copyright (c) 2016, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.replication;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import org.postgresql.PGConnection;
import org.postgresql.PGProperty;
import org.postgresql.test.TestUtil;
import org.postgresql.test.util.rules.ServerVersionRule;
import org.postgresql.test.util.rules.annotation.HaveMinimalServerVersion;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
@HaveMinimalServerVersion("9.4")
public class ReplicationSlotTest {
@Rule
public ServerVersionRule versionRule = new ServerVersionRule();
private Connection sqlConnection;
private Connection replConnection;
private String slotName;
@Before
public void setUp() throws Exception {
sqlConnection = TestUtil.openDB();
replConnection = openReplicationConnection();
//DriverManager.setLogWriter(new PrintWriter(System.out));
}
@After
public void tearDown() throws Exception {
replConnection.close();
dropReplicationSlot();
slotName = null;
sqlConnection.close();
}
@Test(expected = IllegalArgumentException.class)
public void testNotAvailableCreatePhysicalSlotWithoutSlotName() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.physical()
.make();
fail("Replication slot name it required parameter and can't be null");
}
@Test
public void testCreatePhysicalSlot() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
slotName = "pgjdbc_test_create_physical_replication_slot";
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.physical()
.withSlotName(slotName)
.make();
boolean result = isPhysicalSlotExists(slotName);
assertThat(result, CoreMatchers.equalTo(true));
}
@Test
public void testDropPhysicalSlot() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
slotName = "pgjdbc_test_create_physical_replication_slot";
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.physical()
.withSlotName(slotName)
.make();
pgConnection
.getReplicationAPI()
.dropReplicationSlot(slotName);
boolean result = isPhysicalSlotExists(slotName);
slotName = null;
assertThat(result, CoreMatchers.equalTo(false));
}
@Test(expected = IllegalArgumentException.class)
public void testNotAvailableCreateLogicalSlotWithoutSlotName() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.logical()
.withOutputPlugin("test_decoding")
.make();
fail("Replication slot name it required parameter and can't be null");
}
@Test(expected = IllegalArgumentException.class)
public void testNotAvailableCreateLogicalSlotWithoutOutputPlugin() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.logical()
.withSlotName("pgjdbc_test_create_logical_replication_slot")
.make();
fail("output plugin required parameter for logical replication slot and can't be null");
}
@Test
public void testCreateLogicalSlot() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
slotName = "pgjdbc_test_create_logical_replication_slot";
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.logical()
.withSlotName(slotName)
.withOutputPlugin("test_decoding")
.make();
boolean result = isLogicalSlotExists(slotName);
assertThat(result, CoreMatchers.equalTo(true));
}
@Test
public void testDropLogicalSlot() throws Exception {
PGConnection pgConnection = (PGConnection) replConnection;
slotName = "pgjdbc_test_create_logical_replication_slot";
pgConnection
.getReplicationAPI()
.createReplicationSlot()
.logical()
.withSlotName(slotName)
.withOutputPlugin("test_decoding")
.make();
pgConnection
.getReplicationAPI()
.dropReplicationSlot(slotName);
boolean result = isLogicalSlotExists(slotName);
slotName = null;
assertThat(result, CoreMatchers.equalTo(false));
}
private boolean isPhysicalSlotExists(String slotName) throws SQLException {
boolean result;
Statement st = sqlConnection.createStatement();
ResultSet resultSet = st.executeQuery(
"select * from pg_replication_slots where slot_name = '" + slotName
+ "' and slot_type = 'physical'");
result = resultSet.next();
resultSet.close();
st.close();
return result;
}
private boolean isLogicalSlotExists(String slotName) throws SQLException {
boolean result;
Statement st = sqlConnection.createStatement();
ResultSet resultSet = st.executeQuery(
"select 1 from pg_replication_slots where slot_name = '" + slotName
+ "' and slot_type = 'logical'");
result = resultSet.next();
resultSet.close();
st.close();
return result;
}
private void dropReplicationSlot() throws Exception {
if (slotName != null) {
TestUtil.dropReplicationSlot(sqlConnection, slotName);
}
}
private Connection openReplicationConnection() throws Exception {
Properties properties = new Properties();
PGProperty.ASSUME_MIN_SERVER_VERSION.set(properties, "9.4");
PGProperty.REPLICATION.set(properties, "database");
//Only symple query protocol available for replication connection
PGProperty.PREFER_QUERY_MODE.set(properties, "simple");
return TestUtil.openDB(properties);
}
}