package org.corfudb.infrastructure; import org.assertj.core.api.Assertions; import org.corfudb.AbstractCorfuTest; import org.corfudb.runtime.exceptions.LayoutModificationException; import org.corfudb.runtime.view.Layout; import org.junit.Test; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Created by zlokhandwala on 10/26/16. */ public class LayoutWorkflowManagerTest extends AbstractCorfuTest { final int SERVER_ENTRY_3 = 3; final int SERVER_ENTRY_4 = 4; /** * Tests the Layout Workflow manager by removing nodes. * * @throws LayoutModificationException Throws error if all layout, sequencer or * logunit nodes removed. Invalid removal. */ @Test public void checkRemovalOfNodes() throws LayoutModificationException, CloneNotSupportedException { Layout originalLayout = new TestLayoutBuilder() .setEpoch(1L) .addLayoutServer(SERVERS.PORT_0) .addLayoutServer(SERVERS.PORT_1) .addLayoutServer(SERVERS.PORT_2) .addLayoutServer(SERVERS.PORT_3) .addLayoutServer(SERVERS.PORT_4) .addSequencer(SERVERS.PORT_0) .addSequencer(SERVERS.PORT_1) .addSequencer(SERVERS.PORT_2) .buildSegment() .buildStripe() .addLogUnit(SERVERS.PORT_0) .addLogUnit(SERVERS.PORT_2) .addToSegment() .buildStripe() .addLogUnit(SERVERS.PORT_1) .addLogUnit(SERVERS.PORT_3) .addLogUnit(SERVERS.PORT_4) .addToSegment() .addToLayout() .build(); List<String> allNodes = new ArrayList<>(); allNodes.add(TestLayoutBuilder.getEndpoint(SERVERS.PORT_0)); allNodes.add(TestLayoutBuilder.getEndpoint(SERVERS.PORT_1)); allNodes.add(TestLayoutBuilder.getEndpoint(SERVERS.PORT_2)); allNodes.add(TestLayoutBuilder.getEndpoint(SERVERS.PORT_3)); allNodes.add(TestLayoutBuilder.getEndpoint(SERVERS.PORT_4)); Set<String> failedNodes = new HashSet<String>(); LayoutWorkflowManager layoutWorkflowManager = new LayoutWorkflowManager(originalLayout); //Preparing failed nodes set. failedNodes.addAll(allNodes); /* * Invalid Removals */ // Deleting all Layout Servers assertThatThrownBy(() -> layoutWorkflowManager.removeLayoutServers(failedNodes).build() ).isInstanceOf(LayoutModificationException.class); //Deleting all Sequencer Servers assertThatThrownBy(() -> layoutWorkflowManager.removeSequencerServers(failedNodes).build() ).isInstanceOf(LayoutModificationException.class); //Deleting all Log unit Servers assertThatThrownBy(() -> layoutWorkflowManager.removeLogunitServers(failedNodes).build() ).isInstanceOf(LayoutModificationException.class); // Deleting all nodes in one stripe failedNodes.clear(); failedNodes.add(allNodes.get(0)); failedNodes.add(allNodes.get(2)); assertThatThrownBy(() -> layoutWorkflowManager.removeLogunitServers(failedNodes).build() ).isInstanceOf(LayoutModificationException.class); /* * Valid Removal */ // Deleting SERVERS.PORT_0 and SERVERS.PORT_4 // Preparing new layout Layout expectedLayout = new TestLayoutBuilder() .setEpoch(1L) .addLayoutServer(SERVERS.PORT_1) .addLayoutServer(SERVERS.PORT_2) .addLayoutServer(SERVERS.PORT_3) .addSequencer(SERVERS.PORT_1) .addSequencer(SERVERS.PORT_2) .buildSegment() .buildStripe() .addLogUnit(SERVERS.PORT_2) .addToSegment() .buildStripe() .addLogUnit(SERVERS.PORT_1) .addLogUnit(SERVERS.PORT_3) .addToSegment() .addToLayout() .build(); failedNodes.clear(); failedNodes.add(allNodes.get(0)); failedNodes.add(allNodes.get(SERVER_ENTRY_4)); Layout actualLayout = layoutWorkflowManager.removeLayoutServers(failedNodes) .removeLogunitServers(failedNodes) .removeSequencerServers(failedNodes) .build(); Assertions.assertThat(actualLayout).isEqualTo(expectedLayout); /* * Deleting individual nodes */ expectedLayout = new TestLayoutBuilder() .setEpoch(1L) .addLayoutServer(SERVERS.PORT_3) .addSequencer(SERVERS.PORT_2) .buildSegment() .buildStripe() .addLogUnit(SERVERS.PORT_2) .addToSegment() .buildStripe() .addLogUnit(SERVERS.PORT_3) .addToSegment() .addToLayout() .build(); // Remove SERVERS.PORT_1 & SERVERS.PORT_2 from layout server layoutWorkflowManager.removeLayoutServer(allNodes.get(1)); layoutWorkflowManager.removeLayoutServer(allNodes.get(2)); // No effect on removing removed node layoutWorkflowManager.removeLayoutServer(allNodes.get(2)); // Remove SERVERS.PORT_3 from layout server should throw error. assertThatThrownBy(() -> layoutWorkflowManager.removeLayoutServer(allNodes.get(SERVER_ENTRY_3)) ).isInstanceOf(LayoutModificationException.class); // Remove SERVERS.PORT_1 from sequencers layoutWorkflowManager.removeSequencerServer(allNodes.get(1)); // No effect on removing removed node layoutWorkflowManager.removeSequencerServer(allNodes.get(1)); // Remove SERVERS.PORT_2 from sequencer server should throw error. assertThatThrownBy(() -> layoutWorkflowManager.removeSequencerServer(allNodes.get(2)) ).isInstanceOf(LayoutModificationException.class); // Remove SERVERS.PORT_1 from logunits layoutWorkflowManager.removeLogunitServer(allNodes.get(1)); // No effect on removing removed node layoutWorkflowManager.removeLogunitServer(allNodes.get(1)); // Remove SERVERS.PORT_2 from logunit server should throw error. assertThatThrownBy(() -> layoutWorkflowManager.removeLogunitServer(allNodes.get(2)) ).isInstanceOf(LayoutModificationException.class); assertThat(layoutWorkflowManager.build()).isEqualTo(expectedLayout); } }