From 60508bd7495f026221d83887bf9fb4b0bf065ffc Mon Sep 17 00:00:00 2001 From: Jozef Bacigal Date: Tue, 1 Aug 2017 12:50:56 +0200 Subject: [PATCH] Change return type of events - remove callback from onDevicePrepared - added ListenableFuture as return type for events - added many tests - small fixes found on test run Change-Id: Id18bd669589e11a8526bdb77d70ef73df737039c Signed-off-by: Jozef Bacigal --- .../ContextChainMastershipWatcher.java | 1 + .../lifecycle/OwnershipChangeListener.java | 7 +- .../ReconciliationFrameworkRegistrar.java | 2 +- .../ReconciliationFrameworkEvent.java | 16 +- .../impl/device/DeviceContextImpl.java | 2 +- .../lifecycle/ContextChainHolderImpl.java | 28 +-- .../impl/lifecycle/ContextChainImpl.java | 5 +- .../MastershipChangeServiceManagerImpl.java | 11 +- .../mastership/MastershipServiceDelegate.java | 2 - ...econciliationFrameworkServiceDelegate.java | 16 +- .../lifecycle/ContextChainHolderImplTest.java | 170 ++++++++++++++++-- ...astershipChangeServiceManagerImplTest.java | 22 ++- 12 files changed, 209 insertions(+), 73 deletions(-) diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainMastershipWatcher.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainMastershipWatcher.java index 909a09f1fc..912d21948f 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainMastershipWatcher.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ContextChainMastershipWatcher.java @@ -9,6 +9,7 @@ package org.opendaylight.openflowplugin.api.openflow.lifecycle; import javax.annotation.Nonnull; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeException; /** * Watcher if able to start mastership for device. diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/OwnershipChangeListener.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/OwnershipChangeListener.java index fc659ac5b1..7c0fb0a676 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/OwnershipChangeListener.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/OwnershipChangeListener.java @@ -7,8 +7,9 @@ */ package org.opendaylight.openflowplugin.api.openflow.lifecycle; -import com.google.common.util.concurrent.FutureCallback; import javax.annotation.Nonnull; + +import com.google.common.util.concurrent.ListenableFuture; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState; @@ -45,9 +46,9 @@ public interface OwnershipChangeListener extends ReconciliationFrameworkRegistra * @see #becomeMaster(DeviceInfo) * @see #isReconciliationFrameworkRegistered() * @param deviceInfo connected switch identification - * @param callback future callback to be able handle device after reconciliation + * @return future to be able handle device after reconciliation */ - void becomeMasterBeforeSubmittedDS(@Nonnull DeviceInfo deviceInfo, @Nonnull FutureCallback callback); + ListenableFuture becomeMasterBeforeSubmittedDS(@Nonnull DeviceInfo deviceInfo); /** * Set the device mastership checker. diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ReconciliationFrameworkRegistrar.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ReconciliationFrameworkRegistrar.java index 70684b33fc..d1b7508fe9 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ReconciliationFrameworkRegistrar.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/lifecycle/ReconciliationFrameworkRegistrar.java @@ -13,7 +13,7 @@ import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; public interface ReconciliationFrameworkRegistrar { /** * Check if reconciliation framework is registered. - * If not the event {@link OwnershipChangeListener#becomeMasterBeforeSubmittedDS(DeviceInfo, FutureCallback)} + * If not the event {@link OwnershipChangeListener#becomeMasterBeforeSubmittedDS(DeviceInfo)} * will not be triggered. * @return true if there exists any reconciliation framework registration */ diff --git a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/mastership/ReconciliationFrameworkEvent.java b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/mastership/ReconciliationFrameworkEvent.java index 3af361cafa..197e07c695 100644 --- a/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/mastership/ReconciliationFrameworkEvent.java +++ b/openflowplugin-api/src/main/java/org/opendaylight/openflowplugin/api/openflow/mastership/ReconciliationFrameworkEvent.java @@ -7,7 +7,7 @@ */ package org.opendaylight.openflowplugin.api.openflow.mastership; -import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; import javax.annotation.Nonnull; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.lifecycle.OwnershipChangeListener; @@ -16,12 +16,13 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow /** * Service provide one event designed for reconciliation framework. *
    - *
  • {@link #onDevicePrepared(DeviceInfo, FutureCallback)} + *
  • {@link #onDeviceDisconnected(DeviceInfo)} * is called when device is being mastered by controller but not yet submitted into data store. * This method is being called only if the {@link OwnershipChangeListener#isReconciliationFrameworkRegistered()} * is set to {@link Boolean#TRUE}
  • + *
  • {@link #onDevicePrepared(DeviceInfo)} + * is called when device is disconnected or controller loses control of the switch
  • *
- * Other event are defined in {@link MastershipChangeService} *

* This event onDevicePrepared should be used only for reconciliation framework and application can't do anything with * node before the device is not stored in to data store. @@ -32,20 +33,21 @@ public interface ReconciliationFrameworkEvent extends AutoCloseable { /** * Event when device is ready as a master but not yet submitted in data store. This event is evoked by - * {@link OwnershipChangeListener#becomeMasterBeforeSubmittedDS(DeviceInfo, FutureCallback)} + * {@link OwnershipChangeListener#becomeMasterBeforeSubmittedDS(DeviceInfo)} * @param deviceInfo connected switch identification - * @param callback callback need to be attached to reconciliation result future + * @return result state if the device can continue with connecting or should be disconnected */ - void onDevicePrepared(@Nonnull DeviceInfo deviceInfo, @Nonnull FutureCallback callback); + ListenableFuture onDevicePrepared(@Nonnull DeviceInfo deviceInfo); /** * This event occurs after device is disconnected or being slaved. * Event is similar to the {@link MastershipChangeService#onLoseOwnership(DeviceInfo)}. This event is used by * reconciliation framework that the framework don't need to register {@link MastershipChangeService} * @param deviceInfo connected switch identification + * @return future * @see MastershipChangeService */ - void onDeviceDisconnected(@Nonnull DeviceInfo deviceInfo); + ListenableFuture onDeviceDisconnected(@Nonnull DeviceInfo deviceInfo); } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java index f614dc8ef5..45f5dc231f 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/device/DeviceContextImpl.java @@ -782,7 +782,7 @@ public class DeviceContextImpl implements DeviceContext, ExtensionConverterProvi ContextChainMastershipState.MASTER_ON_DEVICE ); if (LOG.isDebugEnabled()) { - LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo.getLOGValue()); + LOG.debug("Role MASTER was successfully set on device, node {}", deviceInfo); } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java index 25ce05e866..f521e97152 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImpl.java @@ -9,6 +9,8 @@ package org.opendaylight.openflowplugin.impl.lifecycle; import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; import io.netty.util.HashedWheelTimer; import java.util.Collections; import java.util.HashMap; @@ -64,7 +66,6 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker private final Map contextChainMap = Collections.synchronizedMap(new HashMap<>()); private final EntityOwnershipListenerRegistration eosListenerRegistration; - private final HashedWheelTimer timer; private final ClusterSingletonServiceProvider singletonServiceProvider; private final ItemScheduler scheduler; private final ExecutorService executorService; @@ -78,7 +79,6 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker final ClusterSingletonServiceProvider singletonServiceProvider, final EntityOwnershipService entityOwnershipService, final OwnershipChangeListener ownershipChangeListener) { - this.timer = timer; this.singletonServiceProvider = singletonServiceProvider; this.executorService = executorService; this.ownershipChangeListener = ownershipChangeListener; @@ -108,7 +108,7 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker } @VisibleForTesting - ContextChain createContextChain(final ConnectionContext connectionContext) { + void createContextChain(final ConnectionContext connectionContext) { final DeviceInfo deviceInfo = connectionContext.getDeviceInfo(); final DeviceContext deviceContext = deviceManager.createContext(connectionContext); @@ -143,7 +143,6 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker CHECK_ROLE_MASTER_TIMEOUT / 1000L); contextChain.registerServices(singletonServiceProvider); - return contextChain; } @Override @@ -169,8 +168,7 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker } LOG.debug("No context chain found for device: {}, creating new.", deviceInfo); - final ContextChain newContextChain = createContextChain(connectionContext); - LOG.debug("Successfully created context chain with identifier: {}", newContextChain.getIdentifier()); + createContextChain(connectionContext); return ConnectionStatus.MAY_CONTINUE; } @@ -201,9 +199,10 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker } else { contextChain.isMastered(mastershipState); if (contextChain.isPrepared()) { - ownershipChangeListener.becomeMasterBeforeSubmittedDS( - deviceInfo, - reconciliationFrameworkCallback(deviceInfo, contextChain)); + Futures.addCallback( + ownershipChangeListener.becomeMasterBeforeSubmittedDS(deviceInfo), + reconciliationFrameworkCallback(deviceInfo, contextChain), + MoreExecutors.directExecutor()); } } } else if (contextChain.isMastered(mastershipState)) { @@ -248,7 +247,9 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker @Override public void close() throws Exception { scheduler.close(); - contextChainMap.keySet().forEach(this::destroyContextChain); + Map copyOfChains = new HashMap<>(contextChainMap); + copyOfChains.keySet().forEach(this::destroyContextChain); + copyOfChains.clear(); contextChainMap.clear(); eosListenerRegistration.close(); } @@ -275,7 +276,7 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker deviceManager .removeDeviceFromOperationalDS(nodeInstanceIdentifier) .checkedGet(REMOVE_DEVICE_FROM_DS_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (TimeoutException | TransactionCommitFailedException e) { + } catch (TimeoutException | TransactionCommitFailedException | NullPointerException e) { LOG.info("Not able to remove device {} from operational DS. Probably removed by another cluster node.", nodeId); } @@ -284,7 +285,6 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker private synchronized void destroyContextChain(final DeviceInfo deviceInfo) { scheduler.remove(deviceInfo); - ownershipChangeListener.becomeSlaveOrDisconnect(deviceInfo); Optional.ofNullable(contextChainMap.get(deviceInfo)).ifPresent(contextChain -> { deviceManager.sendNodeRemovedNotification(deviceInfo.getNodeInstanceIdentifier()); @@ -346,12 +346,14 @@ public class ContextChainHolderImpl implements ContextChainHolder, MasterChecker if (ResultState.DONOTHING == result) { LOG.info("Device {} connection is enabled by reconciliation framework.", deviceInfo); if (!contextChain.continueInitializationAfterReconciliation()) { + LOG.warn("Initialization submit after reconciliation failed for device {}", deviceInfo); destroyContextChain(deviceInfo); } else { ownershipChangeListener.becomeMaster(deviceInfo); + deviceManager.sendNodeAddedNotification(deviceInfo.getNodeInstanceIdentifier()); } } else { - LOG.warn("Reconciliation framework failure."); + LOG.warn("Reconciliation framework failure for device {}", deviceInfo); destroyContextChain(deviceInfo); } } diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java index 1069f5b1be..153945c307 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainImpl.java @@ -232,12 +232,13 @@ public class ContextChainImpl implements ContextChain { @Override public boolean continueInitializationAfterReconciliation() { - return isMastered(ContextChainMastershipState.INITIAL_SUBMIT) && contexts.stream() + return contexts.stream() .filter(StatisticsContext.class::isInstance) .map(StatisticsContext.class::cast) .findAny() .map(StatisticsContext::initialSubmitAfterReconciliation) - .orElse(false); + .orElse(false) && + isMastered(ContextChainMastershipState.INITIAL_SUBMIT); } @Override diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImpl.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImpl.java index 4f51430a1c..1ca1786790 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImpl.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImpl.java @@ -8,7 +8,7 @@ package org.opendaylight.openflowplugin.impl.mastership; import com.google.common.annotations.VisibleForTesting; -import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; import java.util.ArrayList; import java.util.List; import javax.annotation.Nonnull; @@ -21,8 +21,6 @@ import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeS import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkEvent; import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public final class MastershipChangeServiceManagerImpl implements MastershipChangeServiceManager { @@ -72,11 +70,8 @@ public final class MastershipChangeServiceManagerImpl implements MastershipChang } @Override - public void becomeMasterBeforeSubmittedDS(@Nonnull DeviceInfo deviceInfo, - @Nonnull FutureCallback callback) { - if (rfService != null) { - rfService.onDevicePrepared(deviceInfo, callback); - } + public ListenableFuture becomeMasterBeforeSubmittedDS(@Nonnull DeviceInfo deviceInfo) { + return rfService == null ? null : rfService.onDevicePrepared(deviceInfo); } @Override diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipServiceDelegate.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipServiceDelegate.java index 7a56f94081..b0df40eefd 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipServiceDelegate.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/MastershipServiceDelegate.java @@ -11,8 +11,6 @@ import javax.annotation.Nonnull; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeRegistration; import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeService; -import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager; -import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/ReconciliationFrameworkServiceDelegate.java b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/ReconciliationFrameworkServiceDelegate.java index fe05c29840..71b047ee41 100644 --- a/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/ReconciliationFrameworkServiceDelegate.java +++ b/openflowplugin-impl/src/main/java/org/opendaylight/openflowplugin/impl/mastership/ReconciliationFrameworkServiceDelegate.java @@ -7,12 +7,12 @@ */ package org.opendaylight.openflowplugin.impl.mastership; -import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.ListenableFuture; +import javax.annotation.Nonnull; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; -import org.opendaylight.openflowplugin.api.openflow.mastership.*; +import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkEvent; +import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState; - -import javax.annotation.Nonnull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,13 +38,13 @@ public class ReconciliationFrameworkServiceDelegate implements ReconciliationFra } @Override - public void onDevicePrepared(@Nonnull DeviceInfo deviceInfo, @Nonnull FutureCallback callback) { - this.service.onDevicePrepared(deviceInfo, callback); + public ListenableFuture onDevicePrepared(@Nonnull DeviceInfo deviceInfo) { + return this.service.onDevicePrepared(deviceInfo); } @Override - public void onDeviceDisconnected(@Nonnull DeviceInfo deviceInfo) { - this.service.onDeviceDisconnected(deviceInfo); + public ListenableFuture onDeviceDisconnected(@Nonnull DeviceInfo deviceInfo) { + return this.service.onDeviceDisconnected(deviceInfo); } @Override diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImplTest.java index 59957a230b..dfe08e01cc 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImplTest.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/lifecycle/ContextChainHolderImplTest.java @@ -17,24 +17,35 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; +import org.opendaylight.controller.md.sal.common.api.clustering.Entity; +import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration; import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceProvider; import org.opendaylight.mdsal.singleton.common.api.ClusterSingletonServiceRegistration; import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext; +import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionStatus; import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager; +import org.opendaylight.openflowplugin.api.openflow.lifecycle.ContextChainMastershipState; import org.opendaylight.openflowplugin.api.openflow.lifecycle.OwnershipChangeListener; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager; +import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkEvent; +import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration; import org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext; import org.opendaylight.openflowplugin.api.openflow.rpc.RpcManager; import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsContext; import org.opendaylight.openflowplugin.api.openflow.statistics.StatisticsManager; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflow.provider.config.rev160510.OpenflowProviderConfig; +import org.opendaylight.openflowplugin.impl.mastership.MastershipChangeServiceManagerImpl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FeaturesReply; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState; @RunWith(MockitoJUnitRunner.class) public class ContextChainHolderImplTest { + private static final String ENTITY_TEST = "EntityTest"; + private static final String OPENFLOW_TEST = "openflow:test"; @Mock private HashedWheelTimer timer; @Mock @@ -65,8 +76,15 @@ public class ContextChainHolderImplTest { private EntityOwnershipListenerRegistration entityOwnershipListenerRegistration; @Mock private OwnershipChangeListener ownershipChangeListener; + @Mock + private ReconciliationFrameworkEvent reconciliationFrameworkEvent; + @Mock + private FeaturesReply featuresReply; private ContextChainHolderImpl contextChainHolder; + private ReconciliationFrameworkRegistration registration; + private MastershipChangeServiceManager manager = new MastershipChangeServiceManagerImpl(); + private final Short AUXILIARY_ID = 0; @Before public void setUp() throws Exception { @@ -87,14 +105,17 @@ public class ContextChainHolderImplTest { .thenReturn(clusterSingletonServiceRegistration); Mockito.when(entityOwnershipService.registerListener(Mockito.any(), Mockito.any())) .thenReturn(entityOwnershipListenerRegistration); - Mockito.when(ownershipChangeListener.isReconciliationFrameworkRegistered()).thenReturn(false); + Mockito.when(connectionContext.getFeatures()).thenReturn(featuresReply); + Mockito.when(featuresReply.getAuxiliaryId()).thenReturn(AUXILIARY_ID); + + registration = manager.reconciliationFrameworkRegistration(reconciliationFrameworkEvent); contextChainHolder = new ContextChainHolderImpl( timer, executorService, singletonServicesProvider, entityOwnershipService, - ownershipChangeListener + manager ); contextChainHolder.addManager(statisticsManager); contextChainHolder.addManager(rpcManager); @@ -114,44 +135,161 @@ public class ContextChainHolderImplTest { Mockito.verify(statisticsManager).createContext(Mockito.any(DeviceContext.class)); } - @Test - public void destroyContextChain() throws Exception { + @Test + public void reconciliationFrameworkFailure() throws Exception { + Mockito.when(reconciliationFrameworkEvent.onDevicePrepared(deviceInfo)).thenReturn(Futures.immediateFailedFuture(new Throwable("test"))); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + Mockito.verify(reconciliationFrameworkEvent).onDeviceDisconnected(deviceInfo); } @Test - public void pairConnection() throws Exception { - + public void reconciliationFrameworkDisconnect() throws Exception { + Mockito.when(reconciliationFrameworkEvent.onDevicePrepared(deviceInfo)).thenReturn(Futures.immediateFuture(ResultState.DISCONNECT)); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + Mockito.verify(reconciliationFrameworkEvent).onDeviceDisconnected(deviceInfo); } @Test - public void deviceConnected() throws Exception { - + public void reconciliationFrameworkSuccess() throws Exception { + contextChainHolder.createContextChain(connectionContext); + Mockito.when(reconciliationFrameworkEvent.onDevicePrepared(deviceInfo)).thenReturn(Futures.immediateFuture(ResultState.DONOTHING)); + Mockito.when(statisticsContext.initialSubmitAfterReconciliation()).thenReturn(true); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + Mockito.verify(reconciliationFrameworkEvent).onDevicePrepared(deviceInfo); } @Test - public void onNotAbleToStartMastership() throws Exception { - + public void reconciliationFrameworkSuccessButNotSubmit() throws Exception { + contextChainHolder.createContextChain(connectionContext); + Mockito.when(reconciliationFrameworkEvent.onDevicePrepared(deviceInfo)).thenReturn(Futures.immediateFuture(ResultState.DONOTHING)); + Mockito.when(statisticsContext.initialSubmitAfterReconciliation()).thenReturn(false); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + Mockito.verify(reconciliationFrameworkEvent).onDeviceDisconnected(deviceInfo); } @Test - public void onMasterRoleAcquired() throws Exception { - + public void deviceMastered() throws Exception { + registration.close(); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + Assert.assertFalse(contextChainHolder.isAnyDeviceMastered()); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + Assert.assertFalse(contextChainHolder.isAnyDeviceMastered()); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + Assert.assertFalse(contextChainHolder.isAnyDeviceMastered()); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + Assert.assertFalse(contextChainHolder.isAnyDeviceMastered()); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_SUBMIT); + Assert.assertTrue(contextChainHolder.isAnyDeviceMastered()); + Assert.assertTrue(contextChainHolder.listOfMasteredDevices().size() == 1); } @Test - public void onSlaveRoleAcquired() throws Exception { + public void deviceConnected() throws Exception { + registration.close(); + Assert.assertTrue(contextChainHolder.deviceConnected(connectionContext) + == ConnectionStatus.MAY_CONTINUE); + Short AUXILIARY_ID_1 = 1; + Mockito.when(featuresReply.getAuxiliaryId()).thenReturn(AUXILIARY_ID_1); + Assert.assertTrue(contextChainHolder.deviceConnected(connectionContext) + == ConnectionStatus.MAY_CONTINUE); + Mockito.when(featuresReply.getAuxiliaryId()).thenReturn(AUXILIARY_ID); + Assert.assertTrue(contextChainHolder.deviceConnected(connectionContext) + == ConnectionStatus.ALREADY_CONNECTED); + } + @Test + public void notToAbleMastership() throws Exception { + registration.close(); + contextChainHolder.deviceConnected(connectionContext); + contextChainHolder.onNotAbleToStartMastership(deviceInfo, "Test reason", true); + Mockito.verify(deviceContext).close(); + Mockito.verify(statisticsContext).close(); + Mockito.verify(rpcContext).close(); } @Test - public void onSlaveRoleNotAcquired() throws Exception { + public void notAbleToSetSlave() throws Exception { + registration.close(); + contextChainHolder.deviceConnected(connectionContext); + contextChainHolder.onSlaveRoleNotAcquired(deviceInfo); + Mockito.verify(deviceContext).close(); + Mockito.verify(statisticsContext).close(); + Mockito.verify(rpcContext).close(); + } + @Test + public void deviceDisconnected() throws Exception { + registration.close(); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onDeviceDisconnected(connectionContext); + Mockito.verify(deviceContext).close(); + Mockito.verify(statisticsContext).close(); + Mockito.verify(rpcContext).close(); } @Test - public void onDeviceDisconnected() throws Exception { + public void onClose() throws Exception { + registration.close(); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.close(); + Mockito.verify(deviceContext).close(); + Mockito.verify(statisticsContext).close(); + Mockito.verify(rpcContext).close(); + } + @Test + public void ownershipChanged() throws Exception { + registration.close(); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_SUBMIT); + EntityOwnershipChange ownershipChange = new EntityOwnershipChange( + new Entity(ENTITY_TEST, OPENFLOW_TEST), + true, + false, + false + ); + contextChainHolder.ownershipChanged(ownershipChange); + Mockito.verify(deviceManager).removeDeviceFromOperationalDS(Mockito.any()); } + @Test + public void ownershipChangedButHasOwner() throws Exception { + registration.close(); + contextChainHolder.createContextChain(connectionContext); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_FLOW_REGISTRY_FILL); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_GATHERING); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.RPC_REGISTRATION); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.MASTER_ON_DEVICE); + contextChainHolder.onMasterRoleAcquired(deviceInfo, ContextChainMastershipState.INITIAL_SUBMIT); + EntityOwnershipChange ownershipChange = new EntityOwnershipChange( + new Entity(ENTITY_TEST, OPENFLOW_TEST), + true, + false, + true + ); + contextChainHolder.ownershipChanged(ownershipChange); + Mockito.verify(deviceManager,Mockito.never()).removeDeviceFromOperationalDS(Mockito.any()); + } } \ No newline at end of file diff --git a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImplTest.java b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImplTest.java index 2e0eaf4384..6b3a996a3c 100644 --- a/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImplTest.java +++ b/openflowplugin-impl/src/test/java/org/opendaylight/openflowplugin/impl/mastership/MastershipChangeServiceManagerImplTest.java @@ -7,7 +7,8 @@ */ package org.opendaylight.openflowplugin.impl.mastership; -import com.google.common.util.concurrent.FutureCallback; +import java.util.ArrayList; +import java.util.List; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -17,13 +18,12 @@ import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.opendaylight.openflowplugin.api.openflow.device.DeviceInfo; import org.opendaylight.openflowplugin.api.openflow.lifecycle.MasterChecker; -import org.opendaylight.openflowplugin.api.openflow.mastership.*; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.openflowplugin.rf.state.rev170713.ResultState; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.*; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeException; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeRegistration; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeService; +import org.opendaylight.openflowplugin.api.openflow.mastership.MastershipChangeServiceManager; +import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkEvent; +import org.opendaylight.openflowplugin.api.openflow.mastership.ReconciliationFrameworkRegistration; @RunWith(MockitoJUnitRunner.class) public class MastershipChangeServiceManagerImplTest { @@ -35,8 +35,6 @@ public class MastershipChangeServiceManagerImplTest { @Mock private DeviceInfo deviceInfo; @Mock - private FutureCallback resultStateFutureCallback; - @Mock private MasterChecker masterChecker; @Mock private ReconciliationFrameworkEvent event; @@ -105,8 +103,8 @@ public class MastershipChangeServiceManagerImplTest { @Test public void becomeMasterBeforeDS() throws Exception { - manager.becomeMasterBeforeSubmittedDS(deviceInfo, resultStateFutureCallback); - Mockito.verify(event).onDevicePrepared(deviceInfo, resultStateFutureCallback); + manager.becomeMasterBeforeSubmittedDS(deviceInfo); + Mockito.verify(event).onDevicePrepared(deviceInfo); } @Test -- 2.36.6