X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=applications%2Fforwardingrules-sync%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fopenflowplugin%2Fapplications%2Ffrsync%2Fimpl%2FSimplifiedOperationalListenerTest.java;h=fec3204045cd2edf87db43133dfae0e9e038181c;hb=b4f4b4b702e2ccd8a7c62fd2a5c184c5b1cbe665;hp=4be870f5e8bd48dc6225ac7639b523b803787146;hpb=85a27decf79695a8a0a2dcd21325dc5336398860;p=openflowplugin.git diff --git a/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListenerTest.java b/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListenerTest.java index 4be870f5e8..fec3204045 100644 --- a/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListenerTest.java +++ b/applications/forwardingrules-sync/src/test/java/org/opendaylight/openflowplugin/applications/frsync/impl/SimplifiedOperationalListenerTest.java @@ -1,20 +1,24 @@ /** * 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 + * 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.openflowplugin.applications.frsync.impl; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Collections; - +import java.util.List; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; @@ -29,54 +33,82 @@ import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeCa import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeDao; import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeOdlDao; import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeSnapshotDao; +import org.opendaylight.openflowplugin.applications.frsync.impl.clustering.DeviceMastershipManager; +import org.opendaylight.openflowplugin.applications.frsync.util.ReconciliationRegistry; +import org.opendaylight.openflowplugin.applications.frsync.util.SyncupEntry; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableStatisticsGatheringStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.snapshot.gathering.status.grouping.SnapshotGatheringStatusEnd; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; - -import com.google.common.base.Optional; -import com.google.common.util.concurrent.AsyncFunction; -import com.google.common.util.concurrent.Futures; /** * Test for {@link SimplifiedOperationalListener}. */ -@SuppressWarnings("deprecation") @RunWith(MockitoJUnitRunner.class) public class SimplifiedOperationalListenerTest { - public static final NodeId NODE_ID = new NodeId("testNode"); + private static final NodeId NODE_ID = new NodeId("testNode"); + private InstanceIdentifier fcNodePath; + private SimplifiedOperationalListener nodeListenerOperational; + private final LogicalDatastoreType configDS = LogicalDatastoreType.CONFIGURATION; + private final LogicalDatastoreType operationalDS = LogicalDatastoreType.OPERATIONAL; + private final SimpleDateFormat simpleDateFormat = + new SimpleDateFormat(SimplifiedOperationalListener.DATE_AND_TIME_FORMAT); + @Mock private SyncReactor reactor; @Mock - private DataBroker db; + private ReadOnlyTransaction roTx; @Mock private DataTreeModification dataTreeModification; @Mock - private ReadOnlyTransaction roTx; - @Mock private DataObjectModification operationalModification; + @Mock + private FlowCapableNode configNode; + @Mock + private Node operationalNode; + @Mock + private FlowCapableNode fcOperationalNode; + @Mock + private FlowCapableStatisticsGatheringStatus statisticsGatheringStatus; + @Mock + private SnapshotGatheringStatusEnd snapshotGatheringStatusEnd; + @Mock + private ReconciliationRegistry reconciliationRegistry; + @Mock + private DeviceMastershipManager deviceMastershipManager; + @Mock + private List nodeConnector; + @Mock + private Node operationalNodeEmpty; - private InstanceIdentifier nodePath; - private InstanceIdentifier fcNodePath; - private SimplifiedOperationalListener nodeListenerOperational; - - @SuppressWarnings("deprecation") @Before public void setUp() throws Exception { - final FlowCapableNodeSnapshotDao configSnaphot = new FlowCapableNodeSnapshotDao(); - final FlowCapableNodeSnapshotDao operationalSnaphot = new FlowCapableNodeSnapshotDao(); - final FlowCapableNodeDao configDao = new FlowCapableNodeCachedDao(configSnaphot, + final DataBroker db = Mockito.mock(DataBroker.class); + final FlowCapableNodeSnapshotDao configSnapshot = new FlowCapableNodeSnapshotDao(); + final FlowCapableNodeSnapshotDao operationalSnapshot = new FlowCapableNodeSnapshotDao(); + final FlowCapableNodeDao configDao = new FlowCapableNodeCachedDao(configSnapshot, new FlowCapableNodeOdlDao(db, LogicalDatastoreType.CONFIGURATION)); - - nodeListenerOperational = new SimplifiedOperationalListener(reactor, operationalSnaphot, configDao); - nodePath = InstanceIdentifier.create(Nodes.class) - .child(Node.class, new NodeKey(NODE_ID)); + nodeListenerOperational = new SimplifiedOperationalListener(reactor, operationalSnapshot, configDao, + reconciliationRegistry, deviceMastershipManager); + InstanceIdentifier nodePath = InstanceIdentifier.create(Nodes.class).child(Node.class, + new NodeKey(NODE_ID)); fcNodePath = nodePath.augmentation(FlowCapableNode.class); + + final DataTreeIdentifier dataTreeIdentifier = + new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, nodePath); + + Mockito.when(db.newReadOnlyTransaction()).thenReturn(roTx); + Mockito.when(operationalNode.getId()).thenReturn(NODE_ID); + Mockito.when(dataTreeModification.getRootPath()).thenReturn(dataTreeIdentifier); + Mockito.when(dataTreeModification.getRootNode()).thenReturn(operationalModification); + Mockito.when(operationalNode.augmentation(FlowCapableNode.class)).thenReturn(fcOperationalNode); } @Test @@ -85,29 +117,180 @@ public class SimplifiedOperationalListenerTest { } @Test - public void testOnDataTreeChanged() throws Exception { - final FlowCapableNode configTree = Mockito.mock(FlowCapableNode.class); - final Node mockOperationalNode = Mockito.mock(Node.class); - final FlowCapableNode mockOperationalFlowCapableNode = Mockito.mock(FlowCapableNode.class); - Mockito.when(mockOperationalNode.getAugmentation(FlowCapableNode.class)) - .thenReturn(mockOperationalFlowCapableNode); - Mockito.when(mockOperationalNode.getId()).thenReturn(NODE_ID); + public void testOnDataTreeChangedAddPhysical() { + operationalAdd(); + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + Mockito.verify(deviceMastershipManager).onDeviceConnected(NODE_ID); + Mockito.verifyZeroInteractions(reactor); + } - final DataTreeIdentifier dataTreeIdentifier = - new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, nodePath); + @Test + public void testOnDataTreeChangedDeletePhysical() throws Exception { + Mockito.when(operationalModification.getDataBefore()).thenReturn(operationalNode); + Mockito.when(operationalModification.getDataAfter()).thenReturn(null); - Mockito.when(dataTreeModification.getRootPath()).thenReturn(dataTreeIdentifier); - Mockito.when(dataTreeModification.getRootNode()).thenReturn(operationalModification); - Mockito.when(operationalModification.getDataAfter()).thenReturn(mockOperationalNode); - Mockito.when(db.newReadOnlyTransaction()).thenReturn(roTx); - Mockito.doReturn(Futures.immediateCheckedFuture(Optional.of(configTree))).when( - roTx).read(LogicalDatastoreType.CONFIGURATION, fcNodePath); - Mockito.when(reactor.syncup(Matchers.>any(),Matchers.any(),Matchers.any())) - .thenReturn(Futures.immediateFuture(Boolean.TRUE)); + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verify(deviceMastershipManager).onDeviceDisconnected(NODE_ID); + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedDeleteLogical() { + Mockito.when(operationalModification.getDataBefore()).thenReturn(operationalNode); + Mockito.when(operationalNode.getNodeConnector()).thenReturn(nodeConnector); + Mockito.when(operationalNodeEmpty.getId()).thenReturn(NODE_ID); + Mockito.when(operationalModification.getDataAfter()).thenReturn(operationalNodeEmpty); + Mockito.when(operationalNodeEmpty.getNodeConnector()).thenReturn(null); nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); - Mockito.verify(reactor).syncup(fcNodePath, configTree, mockOperationalFlowCapableNode); + Mockito.verify(deviceMastershipManager).onDeviceDisconnected(NODE_ID); + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedReconcileNotRegistered() { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(false); + operationalUpdate(); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedReconcileButStaticsGatheringNotStarted() { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalUpdate(); + Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class)).thenReturn(null); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedReconcileButStaticsGatheringNotFinished() { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalUpdate(); + Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class)) + .thenReturn(statisticsGatheringStatus); + Mockito.when(statisticsGatheringStatus.getSnapshotGatheringStatusEnd()).thenReturn(null); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedReconcileButStaticsGatheringNotSuccessful() { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalUpdate(); + Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class)) + .thenReturn(statisticsGatheringStatus); + Mockito.when(statisticsGatheringStatus.getSnapshotGatheringStatusEnd()).thenReturn(snapshotGatheringStatusEnd); + Mockito.when(snapshotGatheringStatusEnd.isSucceeded()).thenReturn(false); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedReconcileAndFreshOperationalNotPresent() throws ParseException { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalUpdate(); + prepareFreshOperational(false); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verifyZeroInteractions(reactor); + } + + @Test + public void testOnDataTreeChangedReconcileAndFreshOperationalPresent() throws Exception { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalUpdate(); + prepareFreshOperational(true); + final SyncupEntry syncupEntry = loadConfigDSAndPrepareSyncupEntry( + configNode, configDS, fcOperationalNode, operationalDS); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verify(reactor).syncup(fcNodePath, syncupEntry); + Mockito.verify(roTx).close(); + } + + + @Test + public void testOnDataTreeChangedReconcileAndFreshOperationalNotPresentButAdd() throws ParseException { + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalAdd(); + prepareFreshOperational(false); + final SyncupEntry syncupEntry = loadConfigDSAndPrepareSyncupEntry( + configNode, configDS, fcOperationalNode, operationalDS); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verify(reactor).syncup(fcNodePath, syncupEntry); + Mockito.verify(roTx).close(); + } + + @Test + public void testOnDataTreeChangedReconcileAndConfigNotPresent() throws Exception { + // Related to bug 5920 -> https://bugs.opendaylight.org/show_bug.cgi?id=5920 + Mockito.when(reconciliationRegistry.isRegistered(NODE_ID)).thenReturn(true); + operationalUpdate(); + prepareFreshOperational(true); + + Mockito.when(roTx.read(LogicalDatastoreType.CONFIGURATION, fcNodePath)) + .thenReturn(Futures.immediateCheckedFuture(Optional.absent())); + + nodeListenerOperational.onDataTreeChanged(Collections.singleton(dataTreeModification)); + + Mockito.verify(reconciliationRegistry).unregisterIfRegistered(NODE_ID); + Mockito.verifyZeroInteractions(reactor); Mockito.verify(roTx).close(); } + + private void prepareFreshOperational(final boolean afterRegistration) throws ParseException { + Mockito.when(operationalNode.augmentation(FlowCapableStatisticsGatheringStatus.class)) + .thenReturn(statisticsGatheringStatus); + Mockito.when(statisticsGatheringStatus.getSnapshotGatheringStatusEnd()).thenReturn(snapshotGatheringStatusEnd); + Mockito.when(snapshotGatheringStatusEnd.isSucceeded()).thenReturn(true); + Mockito.when(snapshotGatheringStatusEnd.getEnd()).thenReturn(Mockito.mock(DateAndTime.class)); + final String timestampBefore = "0000-12-12T01:01:01.000-07:00"; + final String timestampAfter = "9999-12-12T01:01:01.000-07:00"; + if (afterRegistration) { + Mockito.when(snapshotGatheringStatusEnd.getEnd().getValue()).thenReturn(timestampAfter); + Mockito.when(reconciliationRegistry.getRegistrationTimestamp(NODE_ID)) + .thenReturn(simpleDateFormat.parse(timestampBefore)); + } else { + Mockito.when(snapshotGatheringStatusEnd.getEnd().getValue()).thenReturn(timestampBefore); + Mockito.when(reconciliationRegistry.getRegistrationTimestamp(NODE_ID)) + .thenReturn(simpleDateFormat.parse(timestampAfter)); + } + } + + private void operationalAdd() { + Mockito.when(operationalModification.getDataBefore()).thenReturn(null); + Mockito.when(operationalModification.getDataAfter()).thenReturn(operationalNode); + } + + private void operationalUpdate() { + Mockito.when(operationalModification.getDataBefore()).thenReturn(operationalNode); + Mockito.when(operationalModification.getDataAfter()).thenReturn(operationalNode); + } + + private SyncupEntry loadConfigDSAndPrepareSyncupEntry(final FlowCapableNode after, + final LogicalDatastoreType dsTypeAfter, final FlowCapableNode before, + final LogicalDatastoreType dsTypeBefore) { + Mockito.when(roTx.read(LogicalDatastoreType.CONFIGURATION, fcNodePath)) + .thenReturn(Futures.immediateCheckedFuture(Optional.of(configNode))); + final SyncupEntry syncupEntry = new SyncupEntry(after, dsTypeAfter, before, dsTypeBefore); + Mockito.when(reactor.syncup(ArgumentMatchers.>any(), + Mockito.eq(syncupEntry))).thenReturn(Futures.immediateFuture(Boolean.TRUE)); + return syncupEntry; + } }