package org.corfudb.runtime.view;
import org.corfudb.infrastructure.TestLayoutBuilder;
import org.corfudb.runtime.CorfuRuntime;
import org.corfudb.runtime.clients.TestRule;
import org.corfudb.runtime.exceptions.QuorumUnreachableException;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
/**
* Tests sealing scenarios.
*
* Created by zlokhandwala on 3/7/17.
*/
public class LayoutSealTest extends AbstractViewTest {
/**
* Gets a layout with 5 Servers:
* PORT_0, PORT_1, PORT_2, PORT_3, PORT_4
* Sets the replication view as specified.
*
* @param replicationMode Replication view to set all segments in the layout with.
* @return Built layout with a connected runtime.
*/
public Layout getLayout(Layout.ReplicationMode replicationMode) {
addServer(SERVERS.PORT_0);
addServer(SERVERS.PORT_1);
addServer(SERVERS.PORT_2);
addServer(SERVERS.PORT_3);
addServer(SERVERS.PORT_4);
Layout l = new TestLayoutBuilder()
.setEpoch(1)
.addLayoutServer(SERVERS.PORT_0)
.addLayoutServer(SERVERS.PORT_1)
.addLayoutServer(SERVERS.PORT_2)
.addSequencer(SERVERS.PORT_0)
.buildSegment()
.setReplicationMode(replicationMode)
.buildStripe()
.addLogUnit(SERVERS.PORT_0)
.addLogUnit(SERVERS.PORT_1)
.addLogUnit(SERVERS.PORT_2)
.addToSegment()
.buildStripe()
.addLogUnit(SERVERS.PORT_3)
.addLogUnit(SERVERS.PORT_4)
.addToSegment()
.addToLayout()
.build();
bootstrapAllServers(l);
CorfuRuntime corfuRuntime = getRuntime(l).connect();
l.setRuntime(corfuRuntime);
setAggressiveTimeouts(l);
return l;
}
/**
* Sets aggressive timeouts for all test routers.
*/
public void setAggressiveTimeouts(Layout layout) {
// Setting aggressive timeouts
List<Integer> serverPorts = new ArrayList<>();
serverPorts.add(SERVERS.PORT_0);
serverPorts.add(SERVERS.PORT_1);
serverPorts.add(SERVERS.PORT_2);
serverPorts.add(SERVERS.PORT_3);
serverPorts.add(SERVERS.PORT_4);
List<String> routerEndpoints = new ArrayList<> ();
routerEndpoints.add(SERVERS.ENDPOINT_0);
routerEndpoints.add(SERVERS.ENDPOINT_1);
routerEndpoints.add(SERVERS.ENDPOINT_2);
routerEndpoints.add(SERVERS.ENDPOINT_3);
routerEndpoints.add(SERVERS.ENDPOINT_4);
serverPorts.forEach(serverPort -> {
routerEndpoints.forEach(routerEndpoint -> {
layout.getRuntime().getRouter(routerEndpoint).setTimeoutConnect(PARAMETERS.TIMEOUT_VERY_SHORT.toMillis());
layout.getRuntime().getRouter(routerEndpoint).setTimeoutResponse(PARAMETERS.TIMEOUT_VERY_SHORT.toMillis());
layout.getRuntime().getRouter(routerEndpoint).setTimeoutRetry(PARAMETERS.TIMEOUT_VERY_SHORT.toMillis());
});
});
}
/**
* Asserts the Layout Servers Epochs.
* Params: Expected epoch values
*/
public void assertLayoutEpochs(long epochLayoutServer0, long epochLayoutServer1, long epochLayoutServer2) {
assertThat(getLayoutServer(SERVERS.PORT_0).getServerContext().getServerEpoch()).isEqualTo(epochLayoutServer0);
assertThat(getLayoutServer(SERVERS.PORT_1).getServerContext().getServerEpoch()).isEqualTo(epochLayoutServer1);
assertThat(getLayoutServer(SERVERS.PORT_2).getServerContext().getServerEpoch()).isEqualTo(epochLayoutServer2);
}
/**
* Asserts the Server Router's epochs
* Params: Expected epoch values
*/
public void assertServerRouterEpochs(long epochServerRouter0, long epochServerRouter1, long epochServerRouter2, long epochServerRouter3, long epochServerRouter4) {
assertThat(getLayoutServer(SERVERS.PORT_0).getServerContext().getServerEpoch()).isEqualTo(epochServerRouter0);
assertThat(getLayoutServer(SERVERS.PORT_1).getServerContext().getServerEpoch()).isEqualTo(epochServerRouter1);
assertThat(getLayoutServer(SERVERS.PORT_2).getServerContext().getServerEpoch()).isEqualTo(epochServerRouter2);
assertThat(getLayoutServer(SERVERS.PORT_3).getServerContext().getServerEpoch()).isEqualTo(epochServerRouter3);
assertThat(getLayoutServer(SERVERS.PORT_4).getServerContext().getServerEpoch()).isEqualTo(epochServerRouter4);
}
/**
* Scenario: 5 Servers.
* All working normally and attempted to seal.
* Seal passes.
*/
@Test
public void successfulChainSeal() {
Layout l = getLayout(Layout.ReplicationMode.CHAIN_REPLICATION);
l.setEpoch(l.getEpoch() + 1);
try {
l.moveServersToEpoch();
} catch (QuorumUnreachableException e) {
e.printStackTrace();
}
assertLayoutEpochs(2, 2, 2);
assertServerRouterEpochs(2, 2, 2, 2, 2);
}
/**
* Scenario: 5 Servers.
* ENDPOINT_1, ENDPOINT_3 and ENDPOINT_3 failed and attempted to seal.
* LayoutServers quorum is possible, - Seal passes
* Stripe 1: 1 failed, 2 responses. - Seal passes
* Stripe 2: 2 failed, 0 responses. - Seal failed
* Seal failed
*/
@Test
public void failingChainSeal() {
Layout l = getLayout(Layout.ReplicationMode.CHAIN_REPLICATION);
addClientRule(l.getRuntime(), SERVERS.ENDPOINT_1, new TestRule().drop().always());
addClientRule(l.getRuntime(), SERVERS.ENDPOINT_3, new TestRule().drop().always());
addClientRule(l.getRuntime(), SERVERS.ENDPOINT_4, new TestRule().drop().always());
l.setEpoch(l.getEpoch() + 1);
assertThatThrownBy(() -> l.moveServersToEpoch()).isInstanceOf(QuorumUnreachableException.class);
assertLayoutEpochs(2, 1, 2);
assertServerRouterEpochs(2, 1, 2, 1, 1);
}
/**
* Scenario: 5 Servers.
* All working normally and attempted to seal.
* Seal passes.
*/
@Test
public void successfulQuorumSeal() {
Layout l = getLayout(Layout.ReplicationMode.QUORUM_REPLICATION);
l.setEpoch(l.getEpoch() + 1);
try {
l.moveServersToEpoch();
} catch (QuorumUnreachableException e) {
e.printStackTrace();
}
assertLayoutEpochs(2, 2, 2);
assertServerRouterEpochs(2, 2, 2, 2, 2);
}
/**
* Scenario: 5 Servers.
* ENDPOINT_3 failed and attempted to seal.
* LayoutServers quorum is possible, - Seal passes
* Stripe 1: 0 failed, 3 responses. - Seal passes
* Stripe 2: 1 failed, 1 response. - Seal failed (Quorum not possible)
* Seal failed
*/
@Test
public void failingQuorumSeal() {
Layout l = getLayout(Layout.ReplicationMode.QUORUM_REPLICATION);
addClientRule(l.getRuntime(), SERVERS.ENDPOINT_3, new TestRule().drop().always());
l.setEpoch(l.getEpoch() + 1);
assertThatThrownBy(() -> l.moveServersToEpoch()).isInstanceOf(QuorumUnreachableException.class);
assertLayoutEpochs(2, 2, 2);
assertServerRouterEpochs(2, 2, 2, 1, 2);
}
}