From 2802d3b75bd420458e1c184fd2f19158f2004e16 Mon Sep 17 00:00:00 2001 From: Antonio Fornie Date: Thu, 21 Aug 2014 03:31:02 -0500 Subject: [PATCH] Refactor and test NetworkHelper#sendCommandsToRouterWithNoAnswers --- .../spring-server-core-managers-context.xml | 3 - .../network/router/NetworkHelperImpl.java | 18 +- .../network/router/RouterControlHelper.java | 2 +- ...VpcVirtualNetworkApplianceManagerImpl.java | 8 +- .../topology/AdvancedNetworkTopology.java | 1 + .../topology/BasicNetworkTopology.java | 1 + .../network/router/NetworkHelperImplTest.java | 156 ++++++++++++++++++ .../router/RouterControlHelperTest.java | 105 ++++++++++++ 8 files changed, 274 insertions(+), 20 deletions(-) create mode 100644 server/test/com/cloud/network/router/NetworkHelperImplTest.java create mode 100644 server/test/com/cloud/network/router/RouterControlHelperTest.java diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index 2b46ca3197b..7a9044b7d1d 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -206,9 +206,6 @@ - - diff --git a/server/src/com/cloud/network/router/NetworkHelperImpl.java b/server/src/com/cloud/network/router/NetworkHelperImpl.java index ece0c0f1c13..689ef3b2a1a 100644 --- a/server/src/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/com/cloud/network/router/NetworkHelperImpl.java @@ -195,22 +195,16 @@ public class NetworkHelperImpl implements NetworkHelper { throw new AgentUnavailableException("Unable to send commands to virtual router ", router.getHostId(), e); } - if (answers == null) { - return false; - } - - if (answers.length != cmds.size()) { + if (answers == null || answers.length != cmds.size()) { return false; } // FIXME: Have to return state for individual command in the future boolean result = true; - if (answers.length > 0) { - for (final Answer answer : answers) { - if (!answer.getResult()) { - result = false; - break; - } + for (final Answer answer : answers) { + if (!answer.getResult()) { + result = false; + break; } } return result; @@ -253,7 +247,7 @@ public class NetworkHelperImpl implements NetworkHelper { final int connRouterPR = getRealPriority(connectedRouter); final int disconnRouterPR = getRealPriority(disconnectedRouter); if (connRouterPR < disconnRouterPR) { - //connRouterPR < disconnRouterPR, they won't equal at anytime + //connRouterPR < disconnRouterPR, they won't equal at any time if (!connectedRouter.getIsPriorityBumpUp()) { final BumpUpPriorityCommand command = new BumpUpPriorityCommand(); command.setAccessDetail(NetworkElementCommand.ROUTER_IP, getRouterControlIp(connectedRouter.getId())); diff --git a/server/src/com/cloud/network/router/RouterControlHelper.java b/server/src/com/cloud/network/router/RouterControlHelper.java index 583bd582c0a..68fd6e333ad 100644 --- a/server/src/com/cloud/network/router/RouterControlHelper.java +++ b/server/src/com/cloud/network/router/RouterControlHelper.java @@ -35,7 +35,7 @@ public class RouterControlHelper { private static final Logger logger = Logger.getLogger(RouterControlHelper.class); @Inject - private final DomainRouterDao routerDao = null; + private DomainRouterDao routerDao; @Inject private NetworkDao networkDao; diff --git a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java index 17616999afc..da1447a075a 100644 --- a/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VpcVirtualNetworkApplianceManagerImpl.java @@ -135,7 +135,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian private EntityManager _entityMgr; @Inject - private NicProfileHelper vpcHelper; + private NicProfileHelper nicProfileHelper; @Override public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -323,7 +323,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian int i = 0; for (final PublicIpAddress ipAddr : ipAddrList) { - boolean add = (ipAddr.getState() == IpAddress.State.Releasing ? false : true); + boolean add = ipAddr.getState() == IpAddress.State.Releasing ? false : true; String macAddress = vlanMacAddress.get(BroadcastDomainType.getValue(BroadcastDomainType.fromString(ipAddr.getVlanTag()))); @@ -431,7 +431,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian public boolean finalizeCommandsOnStart(final Commands cmds, final VirtualMachineProfile profile) { DomainRouterVO router = _routerDao.findById(profile.getId()); - boolean isVpc = (router.getVpcId() != null); + boolean isVpc = router.getVpcId() != null; if (!isVpc) { return super.finalizeCommandsOnStart(cmds, profile); } @@ -621,7 +621,7 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian if (router.getVpcId() != null) { if (_networkModel.isProviderSupportServiceInNetwork(guestNetworkId, Service.NetworkACL, Provider.VPCVirtualRouter)) { List networkACLs = _networkACLMgr.listNetworkACLItems(guestNetworkId); - if ((networkACLs != null) && !networkACLs.isEmpty()) { + if (networkACLs != null && !networkACLs.isEmpty()) { s_logger.debug("Found " + networkACLs.size() + " network ACLs to apply as a part of VPC VR " + router + " start for guest network id=" + guestNetworkId); createNetworkACLsCommands(networkACLs, router, cmds, guestNetworkId, false); diff --git a/server/src/org/apache/cloudstack/network/topology/AdvancedNetworkTopology.java b/server/src/org/apache/cloudstack/network/topology/AdvancedNetworkTopology.java index 8b2a5a6ad31..892a81adc41 100644 --- a/server/src/org/apache/cloudstack/network/topology/AdvancedNetworkTopology.java +++ b/server/src/org/apache/cloudstack/network/topology/AdvancedNetworkTopology.java @@ -285,6 +285,7 @@ public class AdvancedNetworkTopology extends BasicNetworkTopology { } if (!connectedRouters.isEmpty()) { + // Shouldn't we include this check inside the method? if (!isZoneBasic && !disconnectedRouters.isEmpty() && disconnectedRouters.get(0).getIsRedundantRouter()) { // These disconnected redundant virtual routers are out of sync // now, stop them for synchronization diff --git a/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java b/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java index 0873d9aee65..ec52911c33c 100644 --- a/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java +++ b/server/src/org/apache/cloudstack/network/topology/BasicNetworkTopology.java @@ -412,6 +412,7 @@ public class BasicNetworkTopology implements NetworkTopology { } if (!connectedRouters.isEmpty()) { + // Shouldn't we include this check inside the method? if (!isZoneBasic && !disconnectedRouters.isEmpty() && disconnectedRouters.get(0).getIsRedundantRouter()) { // These disconnected redundant virtual routers are out of sync // now, stop them for synchronization diff --git a/server/test/com/cloud/network/router/NetworkHelperImplTest.java b/server/test/com/cloud/network/router/NetworkHelperImplTest.java new file mode 100644 index 00000000000..04c5067494b --- /dev/null +++ b/server/test/com/cloud/network/router/NetworkHelperImplTest.java @@ -0,0 +1,156 @@ +package com.cloud.network.router; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.manager.Commands; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.utils.exception.CloudRuntimeException; + + +@RunWith(MockitoJUnitRunner.class) +public class NetworkHelperImplTest { + + private static final long HOST_ID = 10L; + + @Mock + protected AgentManager agentManager; + + @InjectMocks + protected NetworkHelperImpl nwHelper = new NetworkHelperImpl(); + + @Test(expected=CloudRuntimeException.class) + public void testSendCommandsToRouterWrongRouterVersion() + throws AgentUnavailableException, OperationTimedoutException { + // Prepare + NetworkHelperImpl nwHelperUT = spy(this.nwHelper); + VirtualRouter vr = mock(VirtualRouter.class); + doReturn(false).when(nwHelperUT).checkRouterVersion(vr); + + // Execute + nwHelperUT.sendCommandsToRouter(vr, null); + + // Assert + verify(this.agentManager, times(0)).send((Long) Matchers.anyObject(), (Command) Matchers.anyObject()); + } + + @Test + public void testSendCommandsToRouter() + throws AgentUnavailableException, OperationTimedoutException { + // Prepare + NetworkHelperImpl nwHelperUT = spy(this.nwHelper); + VirtualRouter vr = mock(VirtualRouter.class); + when(vr.getHostId()).thenReturn(HOST_ID); + doReturn(true).when(nwHelperUT).checkRouterVersion(vr); + + Commands commands = mock(Commands.class); + when(commands.size()).thenReturn(3); + Answer answer1 = mock(Answer.class); + Answer answer2 = mock(Answer.class); + Answer answer3 = mock(Answer.class); + // In the second iteration it should match and return, without invoking the third + Answer[] answers = {answer1, answer2, answer3}; + when(answer1.getResult()).thenReturn(true); + when(answer2.getResult()).thenReturn(false); + when(answer3.getResult()).thenReturn(false); + when(this.agentManager.send(HOST_ID, commands)).thenReturn(answers); + + // Execute + final boolean result = nwHelperUT.sendCommandsToRouter(vr, commands); + + // Assert + verify(this.agentManager, times(1)).send(HOST_ID, commands); + verify(answer1, times(1)).getResult(); + verify(answer2, times(1)).getResult(); + verify(answer3, times(0)).getResult(); + assertFalse(result); + } + + /** + * The only way result can be true is if each and every command receive a true result + * + * @throws AgentUnavailableException + * @throws OperationTimedoutException + */ + @Test + public void testSendCommandsToRouterWithTrueResult() + throws AgentUnavailableException, OperationTimedoutException { + // Prepare + NetworkHelperImpl nwHelperUT = spy(this.nwHelper); + VirtualRouter vr = mock(VirtualRouter.class); + when(vr.getHostId()).thenReturn(HOST_ID); + doReturn(true).when(nwHelperUT).checkRouterVersion(vr); + + Commands commands = mock(Commands.class); + when(commands.size()).thenReturn(3); + Answer answer1 = mock(Answer.class); + Answer answer2 = mock(Answer.class); + Answer answer3 = mock(Answer.class); + // In the second iteration it should match and return, without invoking the third + Answer[] answers = {answer1, answer2, answer3}; + when(answer1.getResult()).thenReturn(true); + when(answer2.getResult()).thenReturn(true); + when(answer3.getResult()).thenReturn(true); + when(this.agentManager.send(HOST_ID, commands)).thenReturn(answers); + + // Execute + final boolean result = nwHelperUT.sendCommandsToRouter(vr, commands); + + // Assert + verify(this.agentManager, times(1)).send(HOST_ID, commands); + verify(answer1, times(1)).getResult(); + verify(answer2, times(1)).getResult(); + verify(answer3, times(1)).getResult(); + assertTrue(result); + } + + /** + * If the number of answers is different to the number of commands the result is false + * + * @throws AgentUnavailableException + * @throws OperationTimedoutException + */ + @Test + public void testSendCommandsToRouterWithNoAnswers() + throws AgentUnavailableException, OperationTimedoutException { + // Prepare + NetworkHelperImpl nwHelperUT = spy(this.nwHelper); + VirtualRouter vr = mock(VirtualRouter.class); + when(vr.getHostId()).thenReturn(HOST_ID); + doReturn(true).when(nwHelperUT).checkRouterVersion(vr); + + Commands commands = mock(Commands.class); + when(commands.size()).thenReturn(3); + Answer answer1 = mock(Answer.class); + Answer answer2 = mock(Answer.class); + // In the second iteration it should match and return, without invoking the third + Answer[] answers = {answer1, answer2}; + when(this.agentManager.send(HOST_ID, commands)).thenReturn(answers); + + // Execute + final boolean result = nwHelperUT.sendCommandsToRouter(vr, commands); + + // Assert + verify(this.agentManager, times(1)).send(HOST_ID, commands); + verify(answer1, times(0)).getResult(); + assertFalse(result); + } + +} diff --git a/server/test/com/cloud/network/router/RouterControlHelperTest.java b/server/test/com/cloud/network/router/RouterControlHelperTest.java new file mode 100644 index 00000000000..46d0fb21b19 --- /dev/null +++ b/server/test/com/cloud/network/router/RouterControlHelperTest.java @@ -0,0 +1,105 @@ +package com.cloud.network.router; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import com.cloud.network.Networks.TrafficType; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.NicVO; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.NicDao; + +@RunWith(MockitoJUnitRunner.class) +public class RouterControlHelperTest { + + private static final String DIDN_T_GET_THE_EXPECTED_IP4_ADDRESS = "Didn't get the expected IP4 address"; + private static final String IP4_ADDRES1 = "IP4Addres1"; + private static final String IP4_ADDRES2 = "IP4Addres2"; + protected static final long ROUTER_ID = 1L; + protected static final long NW_ID_1 = 11L; + protected static final long NW_ID_2 = 12L; + protected static final long NW_ID_3 = 13L; + + @Mock + protected NicDao nicDao; + @Mock + protected NetworkDao nwDao; + @Mock + protected DomainRouterDao routerDao; + + @InjectMocks + protected RouterControlHelper routerControlHelper = new RouterControlHelper(); + + @Test + public void testGetRouterControlIp() { + // Prepare + List nics = new ArrayList<>(); + NicVO nic1 = mock(NicVO.class); + NicVO nic2 = mock(NicVO.class); + // Actually the third one will never be used, but we must assert that is not + NicVO nic3 = mock(NicVO.class); + when(nic1.getNetworkId()).thenReturn(NW_ID_1); + when(nic2.getNetworkId()).thenReturn(NW_ID_2); + when(nic2.getIp4Address()).thenReturn(IP4_ADDRES1); + when(nic3.getNetworkId()).thenReturn(NW_ID_3); + when(nic3.getIp4Address()).thenReturn(IP4_ADDRES2); + nics.add(nic1); + nics.add(nic2); + nics.add(nic3); + when(this.nicDao.listByVmId(ROUTER_ID)).thenReturn(nics); + + NetworkVO nw1 = mock(NetworkVO.class); + when(nw1.getTrafficType()).thenReturn(TrafficType.Public); + NetworkVO nw2 = mock(NetworkVO.class); + when(nw2.getTrafficType()).thenReturn(TrafficType.Control); + NetworkVO nw3 = mock(NetworkVO.class); + when(nw3.getTrafficType()).thenReturn(TrafficType.Control); + when(this.nwDao.findById(NW_ID_1)).thenReturn(nw1); + when(this.nwDao.findById(NW_ID_2)).thenReturn(nw2); + when(this.nwDao.findById(NW_ID_3)).thenReturn(nw3); + + // Execute + final String ip4address = this.routerControlHelper.getRouterControlIp(ROUTER_ID); + + // Assert + assertEquals(DIDN_T_GET_THE_EXPECTED_IP4_ADDRESS, IP4_ADDRES1, ip4address); + } + + @Test + public void testGetRouterControlIpWithRouterIp() { + // Prepare + List nics = new ArrayList<>(); + NicVO nic1 = mock(NicVO.class); + when(nic1.getNetworkId()).thenReturn(NW_ID_1); + when(nic1.getIp4Address()).thenReturn(null); + nics.add(nic1); + when(this.nicDao.listByVmId(ROUTER_ID)).thenReturn(nics); + + NetworkVO nw1 = mock(NetworkVO.class); + when(nw1.getTrafficType()).thenReturn(TrafficType.Public); + when(this.nwDao.findById(NW_ID_1)).thenReturn(nw1); + + DomainRouterVO router = mock(DomainRouterVO.class); + when(this.routerDao.findById(ROUTER_ID)).thenReturn(router); + when(router.getPrivateIpAddress()).thenReturn(IP4_ADDRES1); + + // Execute + final String ip4address = this.routerControlHelper.getRouterControlIp(ROUTER_ID); + + // Assert + assertEquals(DIDN_T_GET_THE_EXPECTED_IP4_ADDRESS, IP4_ADDRES1, ip4address); + } + +}