import java.util.List;
import java.util.concurrent.ExecutionException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
/**
P2pXconnect p2pXconnect = xconnectGroup.getP2pXconnects().getP2pXconnect().get(0);
L2vpnActivatorTestUtils.checkP2pXconnect(p2pXconnect,innerName);
- AttachmentCircuit attachmentCircuit = p2pXconnect.getAttachmentCircuits().getAttachmentCircuit().get(0);
- L2vpnActivatorTestUtils.checkAttachmentCircuit(attachmentCircuit,portNo2);
- attachmentCircuit = p2pXconnect.getAttachmentCircuits().getAttachmentCircuit().get(1);
- L2vpnActivatorTestUtils.checkAttachmentCircuit(attachmentCircuit,portNo1);
+ List<AttachmentCircuit> attachmentCircuits = p2pXconnect.getAttachmentCircuits().getAttachmentCircuit();
+ assertNotNull(attachmentCircuits);
+ assertEquals(2, attachmentCircuits.size());
+
+ attachmentCircuits.sort(
+ (AttachmentCircuit ac1, AttachmentCircuit ac2)
+ -> ac1.getName().getValue().compareTo(ac2.getName().getValue()));
+
+ L2vpnActivatorTestUtils.checkAttachmentCircuit(attachmentCircuits.get(0), portNo1);
+ L2vpnActivatorTestUtils.checkAttachmentCircuit(attachmentCircuits.get(1), portNo2);
} else {
fail("L2vpn was not found.");
}
<version>1.1.0-SNAPSHOT</version>
</dependency>
+ <!-- dependencies to use AbstractDataBrokerTest -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
<!-- Testing Dependencies -->
<dependency>
<groupId>junit</groupId>
--- /dev/null
+/*
+ * 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.unimgr.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.ActivationStatus;
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.ForwardingConstruct1;
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.ForwardingConstruct1Builder;
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.forwarding.constructs.forwarding.construct.UnimgrAttrsBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstruct;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstructBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Forwarding construct activation state tracking support.
+ *
+ * @author krzysztof.bijakowski@amartus.com
+ */
+public class ForwardingConstructActivationStateTracker {
+ private static final Logger LOG = LoggerFactory.getLogger(ForwardingConstructActivationStateTracker.class);
+
+ private DataBroker dataBroker;
+
+ private InstanceIdentifier<ForwardingConstruct> fcIid;
+
+ public ForwardingConstructActivationStateTracker(DataBroker dataBroker, InstanceIdentifier<ForwardingConstruct> fcIid) {
+ this.dataBroker = dataBroker;
+ this.fcIid = fcIid;
+ }
+
+ public boolean isActivatable() {
+ ReadOnlyTransaction tx = dataBroker.newReadOnlyTransaction();
+
+ try {
+ CheckedFuture<Optional<ForwardingConstruct>, ReadFailedException> result = tx.read(LogicalDatastoreType.OPERATIONAL, fcIid);
+ Optional<ForwardingConstruct> fcOptional = result.checkedGet();
+ return !fcOptional.isPresent();
+ } catch (ReadFailedException e) {
+ LOG.warn("Error during forwarding construct activation state checking", e);
+ }
+
+ return false;
+ }
+
+ public boolean isDeactivatable() {
+ return !isActivatable();
+ }
+
+ public void activated(ForwardingConstruct forwardingConstruct) {
+ writeActivationData(forwardingConstruct, ActivationStatus.ACTIVE);
+ }
+
+ public void activationFailed(ForwardingConstruct forwardingConstruct) {
+ writeActivationData(forwardingConstruct, ActivationStatus.FAILED);
+ }
+
+ public void deactivated() {
+ WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, fcIid);
+
+ try {
+ transaction.submit().checkedGet();
+ LOG.debug("Forwarding construct activation state information deleted successfully");
+ } catch (TransactionCommitFailedException e) {
+ LOG.warn("Error during forwarding construct activation state information deletion", e);
+ }
+ }
+
+ public void deactivationFailed() {
+ //TODO consider how this logic should work
+ }
+
+ @Override
+ public ForwardingConstructActivationStateTracker clone() throws CloneNotSupportedException {
+ return (ForwardingConstructActivationStateTracker) super.clone();
+ }
+
+ private void writeActivationData(ForwardingConstruct forwardingConstruct, ActivationStatus activationStatus) {
+ WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+
+ ForwardingConstruct1 augmentation = new ForwardingConstruct1Builder()
+ .setUnimgrAttrs(new UnimgrAttrsBuilder().setStatus(activationStatus).build())
+ .build();
+
+ ForwardingConstruct update = new ForwardingConstructBuilder(forwardingConstruct)
+ .addAugmentation(ForwardingConstruct1.class, augmentation)
+ .build();
+
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, fcIid, update);
+
+ try {
+ transaction.submit().checkedGet();
+ LOG.debug("Forwarding construct activation state information wrote successfully");
+ } catch (TransactionCommitFailedException e) {
+ LOG.warn("Error during writing forwarding construct activation state information", e);
+ }
+ }
+}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.opendaylight.unimgr.mef.nrp.impl.ActivationTransaction.Result;
+
/**
* @author bartosz.michalik@amartus.com
+ * @author krzysztof.bijakowski@amartus.com [modifications]
*/
public class ForwardingConstructActivatorService {
private static final Logger LOG = LoggerFactory.getLogger(ForwardingConstructActivatorService.class);
* Activate a MEF ForwardingConstruct.
* @param forwardingConstruct the new route to activate
*/
- public void activate(@Nonnull ForwardingConstruct forwardingConstruct) {
- Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
- if (tx.isPresent()) {
- tx.get().activate();
- } else {
- LOG.warn("No transaction for this activation request {}", forwardingConstruct);
+ public void activate(@Nonnull ForwardingConstruct forwardingConstruct, @Nonnull ForwardingConstructActivationStateTracker stateTracker) {
+ if(stateTracker.isActivatable()) {
+ Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
+ if (tx.isPresent()) {
+ Result result = tx.get().activate();
+
+ if(result.isSuccessful()) {
+ stateTracker.activated(forwardingConstruct);
+ LOG.info("Forwarding construct activated successfully, request = {} ", forwardingConstruct);
+ } else {
+ stateTracker.activationFailed(forwardingConstruct);
+ LOG.warn("Forwarding construct activation failed, reason = {}, request = {}", result.getMessage(), forwardingConstruct);
+ }
+ } else {
+ LOG.warn("No transaction for this activation request {}", forwardingConstruct);
+ }
}
}
* Deactivate a MEF ForwardingConstruct.
* @param forwardingConstruct the existing route to deactivate
*/
- public void deactivate(@Nonnull ForwardingConstruct forwardingConstruct) {
- Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
- if (tx.isPresent()) {
- tx.get().deactivate();
- } else {
- LOG.warn("No transaction for this activation request {}", forwardingConstruct);
+ public void deactivate(@Nonnull ForwardingConstruct forwardingConstruct, @Nonnull ForwardingConstructActivationStateTracker stateTracker) {
+ if(stateTracker.isDeactivatable()) {
+ Optional<ActivationTransaction> tx = prepareTransaction(forwardingConstruct);
+ if (tx.isPresent()) {
+ Result result = tx.get().deactivate();
+
+ if(result.isSuccessful()) {
+ stateTracker.deactivated();
+ LOG.info("Forwarding construct deactivated successfully, request = {}", forwardingConstruct);
+ } else {
+ stateTracker.deactivationFailed();
+ LOG.warn("Forwarding construct deactivation failed, reason = {}, request = {}", result.getMessage(), forwardingConstruct);
+ }
+ } else {
+ LOG.warn("No transaction for this deactivation request {}", forwardingConstruct);
+ }
}
}
import java.util.Collection;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.*;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverRepoService;
import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.ForwardingConstructs;
*/
public class ForwardingConstructChangeListener implements DataTreeChangeListener<ForwardingConstruct>, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(ForwardingConstructChangeListener.class);
+
private final ListenerRegistration<ForwardingConstructChangeListener> listener;
+
private final ForwardingConstructActivatorService routeActivator;
private final ActivationDriverRepoService activationRepoService;
+ private final DataBroker dataBroker;
+
public ForwardingConstructChangeListener(DataBroker dataBroker, ActivationDriverRepoService activationRepoService) {
+ this.dataBroker = dataBroker;
this.activationRepoService = activationRepoService;
routeActivator = new ForwardingConstructActivatorService(activationRepoService);
- final InstanceIdentifier<ForwardingConstruct> fwPath = getFwConstructsPath();
+ final InstanceIdentifier<ForwardingConstruct> fwPath = getFcPath();
final DataTreeIdentifier<ForwardingConstruct> dataTreeIid =
new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, fwPath);
listener = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
}
for (final DataTreeModification<ForwardingConstruct> change : collection) {
final DataObjectModification<ForwardingConstruct> root = change.getRootNode();
+
switch (root.getModificationType()) {
case SUBTREE_MODIFIED:
update(change);
protected void add(DataTreeModification<ForwardingConstruct> newDataObject) {
//TODO: Refine the logged addition
LOG.debug("FcRoute add event received {}", newDataObject);
- routeActivator.activate(newDataObject.getRootNode().getDataAfter());
-
+ routeActivator.activate(
+ getFcForActivation(newDataObject),
+ getFcActivationStateTracker(newDataObject)
+ );
}
protected void remove(DataTreeModification<ForwardingConstruct> removedDataObject) {
//TODO: Refine the logged removal
LOG.debug("FcRoute remove event received {}", removedDataObject);
- routeActivator.deactivate(removedDataObject.getRootNode().getDataBefore());
+ routeActivator.deactivate(
+ getFcForDeactivation(removedDataObject),
+ getFcActivationStateTracker(removedDataObject)
+ );
}
LOG.debug("FcRoute update event received {}", modifiedDataObject);
//TODO for the moment transactional nature of this action is ignored :P
- routeActivator.deactivate(modifiedDataObject.getRootNode().getDataBefore());
- routeActivator.activate(modifiedDataObject.getRootNode().getDataAfter());
+ ForwardingConstructActivationStateTracker stateTracker = getFcActivationStateTracker(modifiedDataObject);
+ routeActivator.deactivate(getFcForDeactivation(modifiedDataObject), stateTracker);
+ routeActivator.activate(getFcForActivation(modifiedDataObject), stateTracker);
}
@Override
listener.close();
}
-
- private InstanceIdentifier<ForwardingConstruct> getFwConstructsPath() {
+ private InstanceIdentifier<ForwardingConstruct> getFcPath() {
return InstanceIdentifier
.builder(ForwardingConstructs.class).child(ForwardingConstruct.class).build();
}
+
+ private InstanceIdentifier<ForwardingConstruct> getFcIid(DataTreeModification<ForwardingConstruct> fcModification) {
+ return fcModification.getRootPath().getRootIdentifier();
+ }
+
+ private ForwardingConstruct getFcForActivation(DataTreeModification<ForwardingConstruct> fcModification) {
+ return fcModification.getRootNode().getDataAfter();
+ }
+
+ private ForwardingConstruct getFcForDeactivation(DataTreeModification<ForwardingConstruct> fcModification) {
+ return fcModification.getRootNode().getDataBefore();
+ }
+
+
+ private ForwardingConstructActivationStateTracker getFcActivationStateTracker(
+ DataTreeModification<ForwardingConstruct> fcModification) {
+ return new ForwardingConstructActivationStateTracker(dataBroker, getFcIid(fcModification));
+ }
}
import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
import org.opendaylight.unimgr.mef.nrp.api.ActivationDriver;
import org.slf4j.Logger;
* Runs activation over multiple @ drivers.
*
* @author bartosz.michalik@amartus.com
+ * @author krzysztof.bijakowski@amartus.com [modifications]
*/
public class ActivationTransaction {
private static final Logger LOG = LoggerFactory.getLogger(ActivationTransaction.class);
- private List<ActivationDriver> drivers = new ArrayList<>();
+ private List<ActivationDriver> drivers = new ArrayList<>();
public void addDriver(ActivationDriver driver) {
drivers.add(driver);
/**
* Activate the contents of this transaction.
*/
- public void activate() {
+ public Result activate() {
sortDrivers();
try {
for (ActivationDriver d: drivers) {
}
commit();
LOG.info("Activate transaction successful");
+
+ return Result.success();
} catch (Exception e) {
//XXX add transaction identification ???
LOG.warn("Rolling back activate transaction ", e);
rollback();
+
+ return Result.fail(e.getMessage(), e);
}
}
/**
* Deactivate the contents of this transaction.
*/
- public void deactivate() {
+ public Result deactivate() {
sortDrivers();
try {
for (ActivationDriver d: drivers) {
}
LOG.info("Deactivate transaction successful");
commit();
+
+ return Result.success();
} catch (Exception e) {
//XXX add transaction identification ???
LOG.warn("Rolling back deactivate transaction ", e);
rollback();
+
+ return Result.fail(e.getMessage(), e);
}
}
drivers.sort((driverA, driverB) -> driverA.priority() - driverB.priority());
}
+ public static class Result {
+ private boolean successful;
+
+ private Optional<String> message;
+
+ private Optional<Throwable> cause;
+
+ private Result(boolean successful, Optional<String> message, Optional<Throwable> cause) {
+ this.successful = successful;
+ this.message = message;
+ this.cause = cause;
+ }
+
+ public Optional<Throwable> getCause() {
+ return cause;
+ }
+
+ public boolean isSuccessful() {
+ return successful;
+ }
+
+ public Optional<String> getMessage() {
+ return message;
+ }
+
+ public static Result success(){
+ return new Result(true, Optional.empty(), Optional.empty());
+ }
+
+ public static Result fail(String message, Throwable cause){
+ return new Result(false, Optional.of(message), Optional.of(cause));
+ }
+ }
+
}
*/
package org.opendaylight.unimgr.impl;
-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 java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Consumer;
-
+import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
import org.opendaylight.unimgr.mef.nrp.api.ActivationDriver;
import org.opendaylight.unimgr.mef.nrp.api.ActivationDriverBuilder;
import org.opendaylight.unimgr.mef.nrp.impl.ActivationDriverRepoServiceImpl;
import org.opendaylight.unimgr.utils.ActivationDriverMocks;
import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstruct;
-import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstructBuilder;
import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPort;
-import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPortBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+import static org.mockito.Mockito.*;
+import static org.opendaylight.unimgr.impl.ForwardingConstructTestUtils.fcSingleNode;
+import static org.opendaylight.unimgr.impl.ForwardingConstructTestUtils.fcTwoNodes;
class TestBusinessEx extends RuntimeException {
public TestBusinessEx() {
/**
* @author bartosz.michalik@amartus.com
+ * @author krzysztof.bijakowski@amartus.com [modifications]
*/
public class FcRouteActivatorServiceTest {
-
private static final TopologyId topoA = new TopologyId("a");
+
private static final TopologyId topoZ = new TopologyId("z");
+ private ForwardingConstructActivationStateTracker stateTracker;
+
public ForwardingConstructActivatorService createService(List<ActivationDriverBuilder> builders) {
return new ForwardingConstructActivatorService(new ActivationDriverRepoServiceImpl(builders));
}
+ @Before
+ public void setup() {
+ stateTracker = Mockito.mock(ForwardingConstructActivationStateTracker.class);
+ when(stateTracker.isActivatable()).thenReturn(true);
+ when(stateTracker.isDeactivatable()).thenReturn(true);
+ }
+
@Test
public void testActivateSingleNode() throws Exception {
-
//having
final ActivationDriver d1 = mock(ActivationDriver.class);
));
//when
- service.activate(singleNode());
+ service.activate(fcSingleNode(), stateTracker);
//then
verify(d1).activate();
verify(d1).commit();
+ verify(stateTracker).isActivatable();
+ verify(stateTracker).activated(Mockito.any());
}
@Test
));
//when
- service.activate(twoNodes());
+ service.activate(fcTwoNodes(), stateTracker);
//then
verify(d1, times(2)).activate();
verify(d1, times(2)).commit();
+ verify(stateTracker).isActivatable();
+ verify(stateTracker).activated(Mockito.any());
}
@Test
public void testActivateTwoNodesMultiVendor() throws Exception {
-
//having
final ActivationDriver d1 = mock(ActivationDriver.class);
final ActivationDriver d2 = mock(ActivationDriver.class);
));
//when
- service.activate(twoNodes());
-
+ service.activate(fcTwoNodes(), stateTracker);
//then
verify(d1).activate();
verify(d1).commit();
verify(d2).activate();
verify(d2).commit();
+ verify(stateTracker).isActivatable();
+ verify(stateTracker).activated(Mockito.any());
}
@Test
public void testActivateSingleNodeFailure() throws Exception {
-
//having
final ActivationDriver d1 = spy(new FailingActivationDriver(p -> { if(p.getTopology().equals(topoA)) throw new TestBusinessEx();}));
));
//when
- service.activate(singleNode());
+ service.activate(fcSingleNode(), stateTracker);
//then
verify(d1, times(1)).rollback();
+ verify(stateTracker).isActivatable();
+ verify(stateTracker).activationFailed(Mockito.any());
}
@Test
- public void testActivateMultiNodeFailure() throws Exception {
+ public void testActivateFcExists() throws Exception {
+ //having
+ ForwardingConstructActivationStateTracker stateTrackerFcExists = Mockito.mock(ForwardingConstructActivationStateTracker.class);
+ when(stateTrackerFcExists.isActivatable()).thenReturn(false);
+
+ final ActivationDriver d1 = mock(ActivationDriver.class);
+
+ ForwardingConstructActivatorService service = createService(Arrays.asList(
+ ActivationDriverMocks.prepareDriver((port1, port2) -> topoA.equals(port1.getTopology()) ? d1 : null),
+ ActivationDriverMocks.prepareDriver((port1, port2) -> null)
+ ));
+ //when
+ service.activate(fcSingleNode(), stateTrackerFcExists);
+
+ //then
+ verify(d1, never()).activate();
+ verify(d1, never()).commit();
+ verify(stateTrackerFcExists).isActivatable();
+ verify(stateTrackerFcExists, never()).activated(Mockito.any());
+ verify(stateTrackerFcExists, never()).activationFailed(Mockito.any());
+ }
+
+ @Test
+ public void testActivateMultiNodeFailure() throws Exception {
//having
final ActivationDriver d1 = spy(new FailingActivationDriver(p -> { if(p.getTopology().equals(topoA)) throw new TestBusinessEx();}));
));
//when
- service.activate(twoNodes());
+ service.activate(fcTwoNodes(), stateTracker);
//then
verify(d1, times(1)).activate();
verify(d1, times(2)).rollback();
+ verify(stateTracker).isActivatable();
+ verify(stateTracker).activationFailed(Mockito.any());
}
@Test
public void testDeactivateSingleNodeFailure() throws Exception {
-
//having
final ActivationDriver d1 = spy(new FailingActivationDriver(p -> { if(p.getTopology().equals(topoA)) throw new TestBusinessEx();}));
));
//when
- service.deactivate(singleNode());
+ service.deactivate(fcSingleNode(), stateTracker);
//then
verify(d1, times(1)).deactivate();
verify(d1, times(1)).rollback();
+ verify(stateTracker).isDeactivatable();
+ verify(stateTracker).deactivationFailed();
}
@Test
));
//when
- service.deactivate(twoNodes());
+ service.deactivate(fcTwoNodes(), stateTracker);
//then
verify(d1, times(2)).deactivate();
verify(d1, times(2)).commit();
+ verify(stateTracker).isDeactivatable();
+ verify(stateTracker).deactivated();
}
- private ForwardingConstruct singleNode() {
- return fc(
- port("a", "localhost", "80"),
- port("z", "localhost", "8080")
- );
- }
+ @Test
+ public void testDeactivateFcNotExists() throws Exception {
+ //having
+ ForwardingConstructActivationStateTracker stateTrackerFcNotExists = Mockito.mock(ForwardingConstructActivationStateTracker.class);
+ when(stateTrackerFcNotExists.isDeactivatable()).thenReturn(false);
- private ForwardingConstruct twoNodes() {
- return fc(
- port("a", "192.168.1.1", "80"),
- port("z", "192.168.1.2", "80")
- );
- }
+ final ActivationDriver d1 = mock(ActivationDriver.class);
- private ForwardingConstruct fc(FcPort... ports) {
- return new ForwardingConstructBuilder()
- .setFcPort(Arrays.asList(ports))
- .build();
- }
+ ForwardingConstructActivatorService service = createService(Collections.singletonList(
+ ActivationDriverMocks.prepareDriver(port -> d1)
+ ));
+
+ //when
+ service.deactivate(fcTwoNodes(), stateTrackerFcNotExists);
- FcPort port(String topo, String host, String port) {
- return new FcPortBuilder()
- .setTopology(new TopologyId(topo))
- .setNode(new NodeId(host))
- .setTp(new TpId(port))
- .build();
+ //then
+ verify(d1, never()).deactivate();
+ verify(d1, never()).commit();
+ verify(stateTrackerFcNotExists).isDeactivatable();
+ verify(stateTrackerFcNotExists, never()).deactivated();
+ verify(stateTrackerFcNotExists, never()).deactivationFailed();
}
private static class FailingActivationDriver implements ActivationDriver {
private final Consumer<FcPort> consumer;
+
private FcPort from;
FailingActivationDriver(Consumer<FcPort> portConsumer) {
--- /dev/null
+/*
+ * 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.unimgr.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.ActivationStatus;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstruct;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.unimgr.impl.ForwardingConstructTestUtils.fcIid;
+import static org.opendaylight.unimgr.impl.ForwardingConstructTestUtils.fcSingleNode;
+
+/**
+ * @author krzysztof.bijakowski@amartus.com
+ */
+public class ForwardingConstructActivationStateTrackerTest extends AbstractDataBrokerTest {
+
+ private InstanceIdentifier fcIid;
+
+ @Before
+ public void setUp() {
+ fcIid = fcIid();
+ }
+
+ @Test
+ public void testIsActivatablePositive() {
+ //given
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(mockDataBroker(false));
+
+ //when
+ boolean result = stateTracker.isActivatable();
+
+ //then
+ assertTrue(result);
+ }
+
+ @Test
+ public void testIsActivatableNegative() {
+ //given
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(mockDataBroker(true));
+
+ //when
+ boolean result = stateTracker.isActivatable();
+
+ //then
+ assertFalse(result);
+ }
+
+ @Test
+ public void testIsDeactivatablePositive() {
+ //given
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(mockDataBroker(true));
+
+ //when
+ boolean result = stateTracker.isDeactivatable();
+
+ //then
+ assertTrue(result);
+ }
+
+ @Test
+ public void testIsDeactivatableNegative() {
+ //given
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(mockDataBroker(false));
+
+ //when
+ boolean result = stateTracker.isDeactivatable();
+
+ //then
+ assertFalse(result);
+ }
+
+ @Test
+ public void testActivated() {
+ //given
+ DataBroker dataBroker = getDataBroker();
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(dataBroker);
+ ForwardingConstruct exceptedFc = fcSingleNode();
+
+ //when
+ stateTracker.activated(exceptedFc);
+
+ //then
+ ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
+ CheckedFuture<Optional<ForwardingConstruct>, ReadFailedException> result =
+ transaction.read(LogicalDatastoreType.OPERATIONAL, fcIid);
+ Optional<ForwardingConstruct> fcOptional = Optional.absent();
+
+ try {
+ fcOptional = result.checkedGet();
+ } catch (ReadFailedException e) {
+ fail("Error during test result verification - cannot read data : " + e.getMessage());
+ }
+
+ assertTrue(fcOptional.isPresent());
+ ForwardingConstruct actualFc = fcOptional.get();
+ ForwardingConstructTestUtils.assertEquals(exceptedFc, actualFc);
+ ForwardingConstructTestUtils.assertActivationState(actualFc, ActivationStatus.ACTIVE);
+ }
+
+ @Test
+ public void testActivationFailed() {
+ //given
+ DataBroker dataBroker = getDataBroker();
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(dataBroker);
+ ForwardingConstruct exceptedFc = fcSingleNode();
+
+ //when
+ stateTracker.activationFailed(exceptedFc);
+
+ //then
+ ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
+ CheckedFuture<Optional<ForwardingConstruct>, ReadFailedException> result =
+ transaction.read(LogicalDatastoreType.OPERATIONAL, fcIid);
+ Optional<ForwardingConstruct> fcOptional = Optional.absent();
+
+ try {
+ fcOptional = result.checkedGet();
+ } catch (ReadFailedException e) {
+ fail("Error during test result verification - cannot read data : " + e.getMessage());
+ }
+
+ assertTrue(fcOptional.isPresent());
+ ForwardingConstruct actualFc = fcOptional.get();
+ ForwardingConstructTestUtils.assertEquals(exceptedFc, actualFc);
+ ForwardingConstructTestUtils.assertActivationState(actualFc, ActivationStatus.FAILED);
+ }
+
+ @Test
+ public void testDeactivated() {
+ //given
+ DataBroker dataBroker = getDataBroker();
+ ForwardingConstructActivationStateTracker stateTracker = createStateTracker(dataBroker);
+ ForwardingConstruct fc = fcSingleNode();
+ stateTracker.activated(fc);
+
+ //when
+ stateTracker.deactivated();
+
+ //then
+ ReadOnlyTransaction transaction = dataBroker.newReadOnlyTransaction();
+ CheckedFuture<Optional<ForwardingConstruct>, ReadFailedException> result =
+ transaction.read(LogicalDatastoreType.OPERATIONAL, fcIid);
+ Optional<ForwardingConstruct> fcOptional = Optional.absent();
+
+ try {
+ fcOptional = result.checkedGet();
+ } catch (ReadFailedException e) {
+ fail("Error during test result verification - cannot read data : " + e.getMessage());
+ }
+
+ assertFalse(fcOptional.isPresent());
+ }
+
+ @Test
+ public void testDeactivationFailed() {
+ //TODO write test when implemented
+ }
+
+ private DataBroker mockDataBroker(boolean fcExists) {
+ DataBroker dataBroker = mock(DataBroker.class);
+ final ReadOnlyTransaction transaction = mock(ReadOnlyTransaction.class);
+ final CheckedFuture transactionResult = mock(CheckedFuture.class);
+ final ForwardingConstruct forwardingConstruct = Mockito.mock(ForwardingConstruct.class);
+ final Optional<ForwardingConstruct> optionalForwardingConstruct;
+
+ if(fcExists) {
+ optionalForwardingConstruct = Optional.of(forwardingConstruct);
+ } else {
+ optionalForwardingConstruct = Optional.absent();
+ }
+
+ try {
+ when(transactionResult.checkedGet()).thenReturn(optionalForwardingConstruct);
+ } catch (Exception e) {
+ fail("Cannot create mocks : " + e.getMessage());
+ }
+ when(transaction.read(Mockito.eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class)))
+ .thenReturn(transactionResult);
+ when(dataBroker.newReadOnlyTransaction()).thenReturn(transaction);
+
+ return dataBroker;
+ }
+
+ private ForwardingConstructActivationStateTracker createStateTracker(DataBroker dataBroker) {
+ return new ForwardingConstructActivationStateTracker(dataBroker, fcIid);
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.unimgr.impl;
+
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.ActivationStatus;
+import org.opendaylight.yang.gen.v1.urn.mef.unimgr.ext.rev160725.ForwardingConstruct1;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.ForwardingConstructs;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstruct;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstructBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.forwarding.constructs.ForwardingConstructKey;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPort;
+import org.opendaylight.yang.gen.v1.urn.onf.core.network.module.rev160630.g_forwardingconstruct.FcPortBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.junit.Assert;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author krzysztof.bijakowski@amartus.com
+ */
+class ForwardingConstructTestUtils {
+ private static final ForwardingConstructKey fcKey = new ForwardingConstructKey("fc");
+
+ static ForwardingConstructKey fcKey() {
+ return fcKey;
+ }
+
+ static InstanceIdentifier<ForwardingConstruct> fcIid() {
+ return InstanceIdentifier
+ .builder(ForwardingConstructs.class)
+ .child(ForwardingConstruct.class, fcKey)
+ .build();
+ }
+ static ForwardingConstruct fcSingleNode() {
+ return fc(
+ port("a", "localhost", "80"),
+ port("z", "localhost", "8080")
+ );
+ }
+
+ static ForwardingConstruct fcTwoNodes() {
+ return fc(
+ port("a", "192.168.1.1", "80"),
+ port("z", "192.168.1.2", "80")
+ );
+ }
+
+ static void assertEquals(ForwardingConstruct expectedFc, ForwardingConstruct actualFc) {
+ assertNotNull(expectedFc);
+ assertNotNull(actualFc);
+
+ assertNotNull(expectedFc.getFcPort());
+ assertNotNull(actualFc.getFcPort());
+
+ Set<FcPort> expectedFcPorts = new HashSet<>(expectedFc.getFcPort());
+ Set<FcPort> actualFcPorts = new HashSet<>(actualFc.getFcPort());
+
+ assertTrue(expectedFcPorts.size() == actualFcPorts.size());
+
+ for (FcPort expectedFcPort : expectedFcPorts) {
+ boolean equal = false;
+
+ for (FcPort actualFcPort : actualFcPorts) {
+ equal = compareFcPort(expectedFcPort, actualFcPort);
+
+ if(equal) {
+ break;
+ }
+ }
+
+ assertTrue(equal);
+ }
+ //TODO assertions for other parameters
+ }
+
+ static void assertActivationState(ForwardingConstruct fc, ActivationStatus expectedActivationStatus) {
+ assertNotNull(fc.getAugmentation(ForwardingConstruct1.class));
+ assertNotNull((fc.getAugmentation(ForwardingConstruct1.class).getUnimgrAttrs()));
+
+ ActivationStatus actualActivationStatus = fc.getAugmentation(ForwardingConstruct1.class).getUnimgrAttrs().getStatus();
+ assertNotNull(actualActivationStatus);
+
+ Assert.assertEquals(expectedActivationStatus, actualActivationStatus);
+ }
+
+ private static boolean compareFcPort(FcPort expectedFcPort, FcPort actualFcPort) {
+ assertNotNull(expectedFcPort);
+ assertNotNull(actualFcPort);
+
+ assertNotNull(expectedFcPort.getTopology());
+ assertNotNull(expectedFcPort.getTopology().getValue());
+ assertNotNull(actualFcPort.getTopology());
+ assertNotNull(actualFcPort.getTopology().getValue());
+
+ assertNotNull(expectedFcPort.getNode());
+ assertNotNull(expectedFcPort.getNode().getValue());
+ assertNotNull(actualFcPort.getNode());
+ assertNotNull(actualFcPort.getNode().getValue());
+
+ assertNotNull(expectedFcPort.getTp());
+ assertNotNull(expectedFcPort.getTp().getValue());
+ assertNotNull(actualFcPort.getTp());
+ assertNotNull(actualFcPort.getTp().getValue());
+
+ //TODO assertions for other parameters
+ //TODO add possibility of null paramaters
+
+ boolean result =
+ expectedFcPort.getTopology().getValue().equals(actualFcPort.getTopology().getValue()) &&
+ expectedFcPort.getNode().getValue().equals(actualFcPort.getNode().getValue()) &&
+ expectedFcPort.getTp().getValue().equals(actualFcPort.getTp().getValue());
+
+ return result;
+ }
+
+ private static ForwardingConstruct fc(FcPort... ports) {
+ return new ForwardingConstructBuilder()
+ .setFcPort(Arrays.asList(ports))
+ .setKey(fcKey)
+ .build();
+ }
+
+ private static FcPort port(String topo, String host, String port) {
+ return new FcPortBuilder()
+ .setTopology(new TopologyId(topo))
+ .setNode(new NodeId(host))
+ .setTp(new TpId(port))
+ .build();
+ }
+}
--- /dev/null
+module mef-unimgr-ext {
+ namespace "urn:mef:unimgr-ext";
+ prefix mef-unimgr-ext;
+
+ import onf-core-network-module {
+ prefix onf-cn;
+ }
+
+ revision 2016-07-25 {
+ }
+
+ typedef ActivationStatus {
+ type enumeration {
+ enum INACTIVE;
+ enum ACTIVE;
+ enum FAILED;
+ }
+ }
+
+ augment "/onf-cn:forwarding-constructs/onf-cn:forwarding-construct" {
+ container unimgr-attrs {
+ leaf status {
+ type ActivationStatus;
+ config false;
+ default INACTIVE;
+ }
+ }
+ }
+}