package org.ovirt.engine.core.bll.pm; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; 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.Before; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.businessentities.FencingPolicy; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.pm.FenceActionType; import org.ovirt.engine.core.common.businessentities.pm.FenceAgent; import org.ovirt.engine.core.common.businessentities.pm.FenceOperationResult; import org.ovirt.engine.core.common.businessentities.pm.FenceOperationResult.Status; import org.ovirt.engine.core.common.vdscommands.FenceVdsVDSCommandParameters; import org.ovirt.engine.core.common.vdscommands.VDSCommandType; import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector; import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogable; import org.ovirt.engine.core.di.InjectorRule; import org.ovirt.engine.core.utils.MockConfigRule; import org.ovirt.engine.core.vdsbroker.ResourceManager; @RunWith(MockitoJUnitRunner.class) public class FenceAgentExecutorTest { private static Guid FENCECD_HOST_ID = new Guid("11111111-1111-1111-1111-111111111111"); private static Guid PROXY_HOST_ID = new Guid("44444444-4444-4444-4444-444444444444"); private static Guid SECOND_PROXY_HOST_ID = new Guid("77777777-7777-7777-7777-777777777777"); private static Guid FENCE_AGENT_ID = new Guid("55555555-5555-5555-5555-555555555555"); @ClassRule public static InjectorRule injectorRule = new InjectorRule(); @ClassRule public static MockConfigRule configRule = new MockConfigRule(); @Mock private VDS vds; @Mock private FenceProxyLocator proxyLocator; @Mock private ResourceManager resourceManager; @Mock private FenceAgent realAgent; @Mock AuditLogDirector auditLogDirector; private FenceAgentExecutor executor; @Before public void setup() { mockVds(); executor = spy(new FenceAgentExecutor(vds, new FencingPolicy())); doReturn(resourceManager).when(executor).getResourceManager(); doReturn(proxyLocator).when(executor).getProxyLocator(); doReturn(auditLogDirector).when(executor).getAuditLogDirector(); doReturn(realAgent).when(executor).createRealAgent(any(FenceAgent.class), any(VDS.class)); } /** * Test that the return value is correct when fencing succeeds. */ @Test public void successfulFence() { FenceOperationResult fenceVdsResult = new FenceOperationResult(Status.SUCCESS); mockFenceVdsResult(fenceVdsResult, null); mockProxyHost(); FenceOperationResult result = executor.fence(FenceActionType.START, createAgent()); assertEquals(Status.SUCCESS, result.getStatus()); verifyAuditFenceExecutionStart(1); } /** * Test that fence attempt is retried with a different proxy host when first fence attempt fails */ @Test public void successfulFenceWithDifferentProxyRetry() { FenceOperationResult fenceVdsResult1 = new FenceOperationResult(Status.ERROR); FenceOperationResult fenceVdsResult2 = new FenceOperationResult(Status.SUCCESS); mockFenceVdsResult(fenceVdsResult1, fenceVdsResult2); mockProxyHost(true); FenceOperationResult result = executor.fence(FenceActionType.START, createAgent()); assertEquals(Status.SUCCESS, result.getStatus()); verifyAuditFenceExecutionStart(2); verifyAuditFenceExecutionFailure(1); } /** * Test that fence attempt is retried with the same proxy host when first fence attempt fails and no alternative * proxy is found */ @Test public void successfulFenceWithSameProxyRetry() { FenceOperationResult fenceVdsResult1 = new FenceOperationResult(Status.ERROR); FenceOperationResult fenceVdsResult2 = new FenceOperationResult(Status.SUCCESS); mockFenceVdsResult(fenceVdsResult1, fenceVdsResult2); mockProxyHost(false); FenceOperationResult result = executor.fence(FenceActionType.START, createAgent()); assertEquals(Status.SUCCESS, result.getStatus()); verifyAttemptToFindDifferentProxy(); verifyAuditFenceExecutionStart(2); verifyAuditFenceExecutionFailure(1); } /** * Test that the whole fence execution fails when the first fence attempt fails and the second attempt using * a different proxy host also fails * */ @Test public void failedFenceWithDifferentProxyRetry() { FenceOperationResult fenceVdsResult1 = new FenceOperationResult(Status.ERROR); FenceOperationResult fenceVdsResult2 = new FenceOperationResult(Status.ERROR); mockFenceVdsResult(fenceVdsResult1, fenceVdsResult2); mockProxyHost(true); FenceOperationResult result = executor.fence(FenceActionType.START, createAgent()); assertEquals(Status.ERROR, result.getStatus()); verifyAttemptToFindDifferentProxy(); verifyAuditFenceExecutionFailure(2); } /** * Test that the whole fence execution fails when the first fence attempt fails and the second attempt using * the same proxy host also fails */ @Test public void failedFenceWithSameProxyRetry() { FenceOperationResult fenceVdsResult1 = new FenceOperationResult(Status.ERROR); FenceOperationResult fenceVdsResult2 = new FenceOperationResult(Status.ERROR); mockFenceVdsResult(fenceVdsResult1, fenceVdsResult2); mockProxyHost(false); FenceOperationResult result = executor.fence(FenceActionType.START, createAgent()); assertEquals(Status.ERROR, result.getStatus()); verifyAttemptToFindDifferentProxy(); verifyAuditFenceExecutionFailure(2); } private void mockVds() { when(vds.getId()).thenReturn(FENCECD_HOST_ID); } private void mockProxyHost() { mockProxyHost(false); } private void mockProxyHost(boolean anotherProxyAvailable) { VDS proxyHost = new VDS(); proxyHost.setId(PROXY_HOST_ID); when(proxyLocator.findProxyHost(true)).thenReturn(proxyHost); if (anotherProxyAvailable) { VDS secondProxyHost = new VDS(); secondProxyHost.setId(SECOND_PROXY_HOST_ID); when(proxyLocator.findProxyHost(true, PROXY_HOST_ID)).thenReturn(secondProxyHost); } } private VDSReturnValue createVdsReturnValue(FenceOperationResult result) { VDSReturnValue retVal = new VDSReturnValue(); retVal.setSucceeded(result.getStatus() != Status.ERROR); retVal.setReturnValue(result); return retVal; } private void mockFenceVdsResult(FenceOperationResult result1, FenceOperationResult result2) { VDSReturnValue retVal1 = createVdsReturnValue(result1); VDSReturnValue retVal2 = result2 == null ? null : createVdsReturnValue(result2); when(resourceManager.runVdsCommand( eq(VDSCommandType.FenceVds), any(FenceVdsVDSCommandParameters.class))) .thenReturn(retVal1) .thenReturn(retVal2); } private FenceAgent createAgent() { FenceAgent agent = new FenceAgent(); agent.setId(FENCE_AGENT_ID); return agent; } private void verifyAttemptToFindDifferentProxy() { verify(proxyLocator).findProxyHost(true, PROXY_HOST_ID); } private void verifyAuditFenceExecutionStart(int expectedInvocations) { verify(auditLogDirector, times(expectedInvocations)).log( any(AuditLogable.class), eq(AuditLogType.FENCE_OPERATION_USING_AGENT_AND_PROXY_STARTED)); } private void verifyAuditFenceExecutionFailure(int expectedInvocations) { verify(auditLogDirector, times(expectedInvocations)).log( any(AuditLogable.class), eq(AuditLogType.FENCE_OPERATION_USING_AGENT_AND_PROXY_FAILED)); } }