/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.mdsal.singleton.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.LOCAL_OWNERSHIP_GRANTED; import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.LOCAL_OWNERSHIP_LOST_NEW_OWNER; import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.REMOTE_OWNERSHIP_CHANGED; import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipStateChange.REMOTE_OWNERSHIP_LOST_NO_OWNER; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; import org.opendaylight.mdsal.singleton.api.ClusterSingletonService; /** * Synchronous test suite. */ @RunWith(MockitoJUnitRunner.StrictStubs.class) public class SyncEOSClusterSingletonServiceProviderTest extends AbstractEOSClusterSingletonServiceProviderTest { /** * Test GoldPath for takeLeadership with ownership result MASTER {@link ClusterSingletonService}. * * @throws Exception if the condition does not meet */ @Test public void takeDoubleLeadershipClusterSingletonServiceTest() throws Exception { final var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, REMOTE_OWNERSHIP_CHANGED, false); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEosEntityListReg, never()).close(); verify(mockEntityCandReg, never()).close(); verify(mockDoubleEntityCandReg).close(); } /** * Test checks unexpected change for MASTER-TO-SLAVE double Candidate role change. * * @throws Exception if the condition does not meet */ @Test public void unexpectedLostLeadershipDoubleCandidateTest() throws Exception { final var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, REMOTE_OWNERSHIP_CHANGED, false); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg, never()).close(); verify(mockDoubleEntityCandReg, never()).close(); reg.close(); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg, atLeastOnce()).close(); verify(mockDoubleEntityCandReg).close(); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); verify(mockEntityCandReg).close(); verify(mockEosDoubleEntityListReg, never()).close(); } /** * Test checks inJeopardy Cluster Node state for Master Instance. * * @throws Exception if the condition does not meet */ @Test public void inJeopardyMasterTest() throws Exception { final var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, REMOTE_OWNERSHIP_CHANGED, false); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, REMOTE_OWNERSHIP_LOST_NO_OWNER, true); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg, never()).close(); verify(mockDoubleEntityCandReg, never()).close(); } /** * Test checks close processing for {@link ServiceRegistration}. * * @throws Exception if the condition does not meet */ @Test public void closeClusterSingletonServiceRegistrationMasterTest() throws Exception { final var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); reg.close(); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg).close(); verify(mockDoubleEntityCandReg).close(); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); } /** * Test checks close processing for {@link ServiceRegistration}. * * @throws Exception if the condition does not meet */ @Test public void closeClusterSingletonServiceRegistrationMasterCloseWithNotificationTimesTest() throws Exception { final var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); reg.close(); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg, atLeastOnce()).close(); verify(mockDoubleEntityCandReg).close(); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); } /** * Test checks close processing for {@link ServiceRegistration}. * * @throws Exception if the condition does not meet */ @Test public void closeClusterSingletonServiceRegistrationMasterCloseCoupleTimesTest() throws Exception { final var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); reg.close(); reg.close(); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg).close(); verify(mockDoubleEntityCandReg).close(); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); verify(mockEosDoubleEntityListReg, never()).close(); } /** * Verify that closing a group does not prevent next incarnation of it to be registered and the next incarnation * will become active once the old incarnation finishes cleaning up. */ @Test public void testTwoIncarnations() throws Exception { var reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService); assertNotNull(reg); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService.getServiceState()); verify(mockEos).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos).registerCandidate(DOUBLE_ENTITY); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService.getServiceState()); // Close, triggers unregistration, but we will not continue with it. reg.close(); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); verify(mockEntityCandReg).close(); verify(mockDoubleEntityCandReg).close(); assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); // Instantiate the next incarnation reg = clusterSingletonServiceProvider.registerClusterSingletonService(clusterSingletonService2); verify(mockEos).registerCandidate(ENTITY); assertEquals(TestClusterSingletonServiceState.INITIALIZED, clusterSingletonService2.getServiceState()); // Drive the old incarnation to closure, resetting mocks as needed clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); verify(mockEosDoubleEntityListReg, never()).close(); // Reset mocks for reuse. The next change should see the previous group terminate and the next incarnation // to start coming up clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_LOST_NEW_OWNER, false); verify(mockEos, times(2)).registerCandidate(ENTITY); clusterSingletonServiceProvider.ownershipChanged(ENTITY, LOCAL_OWNERSHIP_GRANTED, false); verify(mockEos, times(2)).registerCandidate(DOUBLE_ENTITY); clusterSingletonServiceProvider.ownershipChanged(DOUBLE_ENTITY, LOCAL_OWNERSHIP_GRANTED, false); assertEquals(TestClusterSingletonServiceState.STARTED, clusterSingletonService2.getServiceState()); // Check for potential service mixup assertEquals(TestClusterSingletonServiceState.DESTROYED, clusterSingletonService.getServiceState()); verify(mockEosEntityListReg, never()).close(); verify(mockEosDoubleEntityListReg, never()).close(); } }