Bug 5617: Added UT for GroupTable and ChainActionFlows 07/37207/1
authorVladimir Lavor <vlavor@cisco.com>
Wed, 30 Mar 2016 14:13:22 +0000 (16:13 +0200)
committerVladimir Lavor <vlavor@cisco.com>
Wed, 6 Apr 2016 15:22:35 +0000 (15:22 +0000)
Signed-off-by: Vladimir Lavor <vlavor@cisco.com>
Change-Id: I2a45247bbc7a3b611baa6a1cf55b26da06ef9232
(cherry picked from commit 619e7bf903b9f096af6617432350b9e8b5ff072a)

renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlows.java
renderers/ofoverlay/src/main/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTable.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/ChainActionFlowsTest.java
renderers/ofoverlay/src/test/java/org/opendaylight/groupbasedpolicy/renderer/ofoverlay/flow/GroupTableTest.java

index d630535b35af58a368695cc578bbde30978f67c1..f77fb1702814b476aff96799d209f0bddb6221f3 100755 (executable)
@@ -210,8 +210,7 @@ public class ChainActionFlows {
         return flowb.build();
     }
 
-    @VisibleForTesting
-    static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements,
+    private static Flow createExternalFlow(SfcNshHeader sfcNshHeader, NodeConnectorId tunPort, NetworkElements netElements,
                                    PolicyManager policyManager, SwitchManager switchManager, Ipv4Address ipTunDest) {
 
         short tableId = policyManager.getTABLEID_EXTERNAL_MAPPER();
@@ -345,8 +344,7 @@ public class ChainActionFlows {
 
     }
 
-    @VisibleForTesting
-    static Integer returnOfPortFromNodeConnector(NodeConnectorId nodeConnectorId) {
+    private static Integer returnOfPortFromNodeConnector(NodeConnectorId nodeConnectorId) {
         String[] elements = StringUtils.split(nodeConnectorId.getValue(), ":");
         if (elements.length != 3)
             return null;
index 8b21fd13c446e0e669a4fd4a671f2ae453c770d4..fdb53bf244d72ee99b7e67e9072afb1cd03bc6c1 100644 (file)
@@ -8,19 +8,8 @@
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.actionList;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.createNodePath;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.getOfPortNum;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;
-import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.outputAction;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-
-import org.antlr.v4.runtime.misc.Array2DHashSet;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Optional;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.groupbasedpolicy.dto.EgKey;
@@ -46,7 +35,12 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
 
 /**
  * Manage the group tables for handling broadcast/multicast
@@ -60,156 +54,163 @@ public class GroupTable extends OfTable {
         super(ctx);
     }
 
-    FlowCapableNode getFCNodeFromDatastore(NodeId nodeId)
-            throws ExecutionException, InterruptedException {
-        FlowCapableNode fcn = null;
-        ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
-        InstanceIdentifier<FlowCapableNode> fcniid = createNodePath(nodeId).builder()
-                .augmentation(FlowCapableNode.class).build();
-
-        Optional<FlowCapableNode> r = t.read(LogicalDatastoreType.OPERATIONAL, fcniid).get();
-        if (!r.isPresent()) {
-            LOG.warn("Node {} is not present", fcniid);
-            return null;
-        }
-        fcn = r.get();
-        t.close();
-        return fcn;
-    }
-
     @Override
     public void sync(Endpoint endpoint, OfWriter ofWriter) throws Exception {
-
-        // TODO: only temporary workaround, use src & dst endpoint in implementation
-        NodeId nodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint);
+        NodeId endpointNodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint);
+        if (endpointNodeId == null) {
+            LOG.warn("Endpoint {} has no location specified, skipped", endpoint);
+            return;
+        }
 
         // there appears to be no way of getting only the existing group
-        // tables unfortunately, so we have to get the whole goddamned node.
+        // tables unfortunately, so we have to get the whole node.
         // Since this is happening concurrently with other things that are
         // working in subtrees of nodes, we have to do two transactions
-        FlowCapableNode fcn = getFCNodeFromDatastore(nodeId);
+        FlowCapableNode fcn = getFCNodeFromDatastore(endpointNodeId);
         if (fcn == null)
             return;
+        EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
+        if (ordinals == null) {
+            LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", endpoint);
+            return;
+        }
+        GroupId groupId = new GroupId(Long.valueOf(ordinals.getFdId()));
+        if (!ofWriter.groupExists(endpointNodeId, groupId.getValue())) {
+            LOG.info("createGroup {} {}", endpointNodeId, groupId);
+            ofWriter.writeGroup(endpointNodeId, groupId);
+        }
+        syncGroups(endpointNodeId, ordinals, endpoint, groupId, ofWriter);
+    }
 
-        for (Endpoint localEp : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
-            EndpointFwdCtxOrdinals localEpFwdCtxOrds =
-                    OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, localEp);
-            if (localEpFwdCtxOrds == null) {
-                LOG.info("getEndpointFwdCtxOrdinals is null for EP {}", localEp);
-                continue;
-            }
-
-            GroupId gid = new GroupId(Long.valueOf(localEpFwdCtxOrds.getFdId()));
-            if (!ofWriter.groupExists(nodeId, gid.getValue())) {
-                LOG.info("createGroup {} {}", nodeId, gid);
-                ofWriter.writeGroup(nodeId, gid);
-            }
-
-            for (EgKey epg : ctx.getEndpointManager().getGroupsForNode(nodeId)) {
-
-                // we'll use the fdId with the high bit set for remote bucket
-                // and just the local port number for local bucket
-                for (NodeId destNode : findPeerNodesForGroup(epg)) {
-                    if (nodeId.equals(destNode))
+    @VisibleForTesting
+    void syncGroups(NodeId nodeId, EndpointFwdCtxOrdinals ordinals, Endpoint endpoint, GroupId groupId,
+                            OfWriter ofWriter) throws Exception {
+        for (EgKey endpointGroupKey : ctx.getEndpointManager().getGroupsForNode(nodeId)) {
+            // we'll use the fdId with the high bit set for remote bucket
+            // and just the local port number for local bucket
+            for (NodeId destinationNode : findPeerNodesForGroup(endpointGroupKey)) {
+                if (nodeId.equals(destinationNode))
+                    continue;
+                if (isFloodDomainOnNode(ordinals.getFdId(), destinationNode)) {
+                    Long bucketId;
+                    try {
+                        bucketId = (long) OrdinalFactory.getContextOrdinal(destinationNode);
+                    } catch (Exception e) {
+                        LOG.error("Error during getting of context ordinal, node: {}", destinationNode);
                         continue;
-
-                    if(isFloodDomainOnNode(localEpFwdCtxOrds.getFdId(), destNode)) {
-                        long bucketId = OrdinalFactory.getContextOrdinal(destNode);
-                        bucketId |= 1L << 31;
-
-                        IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(destNode, TunnelTypeVxlan.class);
-                        NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
-                        if (tunDst == null || tunPort == null)
-                            continue;
-                        Action tundstAction = null;
-                        if (tunDst.getIpv4Address() != null) {
-                            String nextHop = tunDst.getIpv4Address().getValue();
-                            tundstAction = nxLoadTunIPv4Action(nextHop, true);
-                        } else {
-                            LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
-                                    destNode);
-                            continue;
-                        }
-                        BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId)))
-                                .setAction(actionList(tundstAction, outputAction(tunPort)));
-                        ofWriter.writeBucket(nodeId, gid, bb.build());
                     }
+                    bucketId |= 1L << 31;
+                    IpAddress tunDst = ctx.getSwitchManager().getTunnelIP(destinationNode, TunnelTypeVxlan.class);
+                    NodeConnectorId tunPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
+                    if (tunDst == null || tunPort == null)
+                        continue;
+                    Action tunDstAction;
+                    if (tunDst.getIpv4Address() != null) {
+                        String nextHop = tunDst.getIpv4Address().getValue();
+                        tunDstAction = nxLoadTunIPv4Action(nextHop, true);
+                    } else {
+                        LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
+                                destinationNode);
+                        continue;
+                    }
+                    BucketBuilder bucketBuilder = new BucketBuilder().setBucketId(new BucketId(bucketId))
+                            .setAction(actionList(tunDstAction, outputAction(tunPort)));
+                    ofWriter.writeBucket(nodeId, groupId, bucketBuilder.build());
                 }
-                // TODO broadcasts are not separated by EPG between endpoints on the same node
-                OfOverlayContext ofc = localEp.getAugmentation(OfOverlayContext.class);
-                if (EndpointManager.isExternal(localEp, ctx.getTenant(localEp.getTenant()).getExternalImplicitGroups()))
-                    continue;
-
-                long bucketId;
-                try {
-                    bucketId = getOfPortNum(ofc.getNodeConnectorId());
-                } catch (NumberFormatException e) {
-                    LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), e);
-                    continue;
-                }
-                Action output = outputAction(ofc.getNodeConnectorId());
-                BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(Long.valueOf(bucketId))).setAction(
-                        FlowUtils.actionList(output));
-                ofWriter.writeBucket(nodeId, gid, bb.build());
-
-                // if boradcast exceeds internal domain
-                for (Endpoint extEp : ctx.getEndpointManager().getExtEpsNoLocForGroup(epg)) {
-                    if (extEp.getNetworkContainment() != null
-                            && extEp.getNetworkContainment().equals(localEp.getNetworkContainment())) {
-                        L2FloodDomain l2Fd = ctx.getTenant(extEp.getTenant()).resolveL2FloodDomain(
-                                extEp.getNetworkContainment());
-                        if (l2Fd != null) {
-                            Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class);
-                            // external endpoints do not have location augmentation
-                            // however they are beyond external ports
-                            for (NodeConnectorId extNcId : ctx.getSwitchManager().getExternalPorts(nodeId)) {
-                                try {
-                                    bucketId = getOfPortNum(extNcId);
-                                } catch (NumberFormatException e) {
-                                    LOG.warn("Could not parse external port number {}", extNcId, e);
-                                    continue;
-                                }
-                                ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder>
+            }
+            // TODO broadcasts are not separated by EPG between endpoints on the same node
+            OfOverlayContext ofc = endpoint.getAugmentation(OfOverlayContext.class);
+            if (EndpointManager.isExternal(endpoint, ctx.getTenant(endpoint.getTenant()).getExternalImplicitGroups()))
+                continue;
+            long bucketId;
+            try {
+                bucketId = getOfPortNum(ofc.getNodeConnectorId());
+            } catch (NumberFormatException e) {
+                LOG.warn("Could not parse port number {}", ofc.getNodeConnectorId(), e);
+                continue;
+            }
+            Action output = outputAction(ofc.getNodeConnectorId());
+            BucketBuilder bb = new BucketBuilder().setBucketId(new BucketId(bucketId)).setAction(
+                    FlowUtils.actionList(output));
+            ofWriter.writeBucket(nodeId, groupId, bb.build());
+            // if broadcast exceeds internal domain
+            for (Endpoint extEp : ctx.getEndpointManager().getExtEpsNoLocForGroup(endpointGroupKey)) {
+                if (extEp.getNetworkContainment() != null
+                        && extEp.getNetworkContainment().equals(endpoint.getNetworkContainment())) {
+                    L2FloodDomain l2Fd = ctx.getTenant(extEp.getTenant())
+                            .resolveL2FloodDomain(extEp.getNetworkContainment());
+                    if (l2Fd != null) {
+                        Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class);
+                        // external endpoints do not have location augmentation
+                        // however they are beyond external ports
+                        for (NodeConnectorId extNcId : ctx.getSwitchManager().getExternalPorts(nodeId)) {
+                            try {
+                                bucketId = getOfPortNum(extNcId);
+                            } catch (NumberFormatException e) {
+                                LOG.warn("Could not parse external port number {}", extNcId, e);
+                                continue;
+                            }
+                            ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder>
                                     actionList = new ArrayList<>();
-                                if (segmentation != null) {
-                                    Integer vlanId = segmentation.getSegmentationId();
-                                    actionList.addAll(FlowUtils.pushVlanActions(vlanId));
-                                    actionList.add(new ActionBuilder().setOrder(2).setAction(outputAction(extNcId)));
-                                } else {
-                                    actionList.add(new ActionBuilder().setOrder(0).setAction(outputAction(extNcId)));
-                                }
-                                bb.setBucketId(new BucketId(Long.valueOf(bucketId))).setAction(
-                                        FlowUtils.actionList(actionList));
-                                ofWriter.writeBucket(nodeId, gid, bb.build());
+                            if (segmentation != null) {
+                                Integer vlanId = segmentation.getSegmentationId();
+                                actionList.addAll(FlowUtils.pushVlanActions(vlanId));
+                                actionList.add(new ActionBuilder().setOrder(2).setAction(outputAction(extNcId)));
+                            } else {
+                                actionList.add(new ActionBuilder().setOrder(0).setAction(outputAction(extNcId)));
                             }
+                            bb.setBucketId(new BucketId(bucketId)).setAction(
+                                    FlowUtils.actionList(actionList));
+                            ofWriter.writeBucket(nodeId, groupId, bb.build());
                         }
                     }
                 }
             }
         }
+
     }
 
     /**
      * @param sourceEpgKey a key of source group
      * @return all the nodes on which endpoints are either in groups that have policy with source
-     *         group, or are in the source group
+     * group, or are in the source group
      */
     private Set<NodeId> findPeerNodesForGroup(EgKey sourceEpgKey) {
-        Set<NodeId> nodes = new HashSet<NodeId>();
+        Set<NodeId> nodes = new HashSet<>();
         nodes.addAll(ctx.getEndpointManager().getNodesForGroup(sourceEpgKey));
-        for (EgKey dstEpgs : ctx.getCurrentPolicy().getPeers(sourceEpgKey)) {
-            nodes.addAll(ctx.getEndpointManager().getNodesForGroup(dstEpgs));
+        for (EgKey dstEpGroups : ctx.getCurrentPolicy().getPeers(sourceEpgKey)) {
+            nodes.addAll(ctx.getEndpointManager().getNodesForGroup(dstEpGroups));
         }
         return nodes;
     }
 
     private boolean isFloodDomainOnNode(int fdId, NodeId node) throws Exception {
-        for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(node)) {
-            int epFdId = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, ep).getFdId();
+        for (Endpoint endpoint : ctx.getEndpointManager().getEndpointsForNode(node)) {
+            EndpointFwdCtxOrdinals endpointFwdCtxOrdinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
+            if (endpointFwdCtxOrdinals == null) {
+                continue;
+            }
+            int epFdId = endpointFwdCtxOrdinals.getFdId();
             if (fdId == epFdId) {
                 return true;
             }
         }
         return false;
     }
+
+    private FlowCapableNode getFCNodeFromDatastore(NodeId nodeId)
+            throws ExecutionException, InterruptedException {
+        ReadOnlyTransaction t = ctx.getDataBroker().newReadOnlyTransaction();
+        InstanceIdentifier<FlowCapableNode> fcnIid = createNodePath(nodeId).builder()
+                .augmentation(FlowCapableNode.class).build();
+
+        Optional<FlowCapableNode> r = t.read(LogicalDatastoreType.OPERATIONAL, fcnIid).get();
+        if (!r.isPresent()) {
+            LOG.warn("Node {} is not present", fcnIid);
+            return null;
+        }
+        FlowCapableNode fcn = r.get();
+        t.close();
+        return fcn;
+    }
 }
index 0957f00b66aeb7c80d4e19400383ef5ae33cd185..28d820e598cf01ce70d89f774f4addb7b6eb4392 100644 (file)
 \r
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;\r
 \r
-import static org.junit.Assert.assertEquals;\r
-import static org.junit.Assert.assertTrue;\r
-import static org.mockito.Mockito.mock;\r
-import static org.mockito.Mockito.when;\r
-\r
-import org.junit.Assert;\r
+import com.google.common.base.Preconditions;\r
 import org.junit.Before;\r
 import org.junit.Test;\r
+import org.mockito.ArgumentCaptor;\r
+import org.mockito.Captor;\r
+import org.opendaylight.groupbasedpolicy.dto.EgKey;\r
+import org.opendaylight.groupbasedpolicy.dto.PolicyInfo;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager;\r
-import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory.EndpointFwdCtxOrdinals;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;\r
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.MapperUtilsTest;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.policyenforcer.NetworkElements;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader;\r
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.sfcutils.SfcNshHeader.SfcNshHeaderBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.TenantBuilder;\r
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg1;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe;\r
 \r
-public class ChainActionFlowsTest {\r
+import java.math.BigInteger;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import static org.junit.Assert.assertArrayEquals;\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertNotNull;\r
+import static org.junit.Assert.assertTrue;\r
+import static org.mockito.Mockito.any;\r
+import static org.mockito.Mockito.mock;\r
+import static org.mockito.Mockito.times;\r
+import static org.mockito.Mockito.verify;\r
+import static org.mockito.Mockito.when;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNsiMatch;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxNspMatch;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxRegMatch;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.addNxTunIdMatch;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.applyActionIns;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.base;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.gotoTableIns;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.instructions;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc1RegAction;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadNshc2RegAction;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadRegAction;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIPv4Action;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxLoadTunIdAction;\r
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.nxOutputRegAction;\r
 \r
-    private SfcNshHeader sfcNshHeader;\r
-    private NodeConnectorId tunPort;\r
-    private NetworkElements netElements;\r
-    private PolicyManager policyManager;\r
-    private SwitchManager switchManager;\r
-    private Ipv4Address ip1 = new Ipv4Address("10.1.1.1");\r
-    private Ipv4Address ip2 = new Ipv4Address("10.1.1.2");\r
+public class ChainActionFlowsTest extends MapperUtilsTest {\r
+\r
+    @Captor\r
+    private final ArgumentCaptor<NodeId> nodeIdCaptor = ArgumentCaptor.forClass(NodeId.class);\r
+    private final ArgumentCaptor<Short> tableIdCaptor = ArgumentCaptor.forClass(Short.class);\r
+    private final ArgumentCaptor<Flow> flowCaptor = ArgumentCaptor.forClass(Flow.class);\r
 \r
     @Before\r
-    public void setup() {\r
-        policyManager = mock(PolicyManager.class);\r
+    public void init() {\r
+        ctx = mock(OfContext.class);\r
+        endpointManager = mock(EndpointManager.class);\r
         switchManager = mock(SwitchManager.class);\r
-        EndpointFwdCtxOrdinals ords = mock(EndpointFwdCtxOrdinals.class);\r
-        sfcNshHeader = mock(SfcNshHeader.class);\r
-        netElements = mock(NetworkElements.class);\r
-        when(netElements.getSrcNodeId()).thenReturn(new NodeId("openflow:1"));\r
-        when(netElements.getSrcEpOrdinals()).thenReturn(ords);\r
-        when(netElements.getSrcEpOrdinals().getL3Id()).thenReturn(7);\r
-        when(netElements.getDstNodeId()).thenReturn(new NodeId("openflow:1"));\r
-        when(netElements.getDstEpOrdinals()).thenReturn(ords);\r
-        when(netElements.getDstEpOrdinals().getL3Id()).thenReturn(7);\r
-        when(netElements.getLocalNodeId()).thenReturn(new NodeId("openflow:1"));\r
-        tunPort = new NodeConnectorId("openflow:1:42");\r
+        policyManager = mock(PolicyManager.class);\r
+        policyInfo = mock(PolicyInfo.class);\r
+        ofWriter = mock(OfWriter.class);\r
     }\r
 \r
     @Test\r
-    public void createExternalFlowTest() throws Exception {\r
-        // Note C1 != tunDest ie ip1 and ip2 - output action\r
-        sfcNshHeader = new SfcNshHeaderBuilder().setNshMetaC1(SfcNshHeader.convertIpAddressToLong(ip1))\r
-                .setNshTunIpDst(ip2)\r
-                .setNshMetaC2(7L)\r
-                .setNshNsiToChain((short) 1)\r
-                .build();\r
-\r
-        Flow flow = ChainActionFlows.createExternalFlow(sfcNshHeader, tunPort, netElements, policyManager, switchManager, ip2);\r
-        assertEquals(policyManager.getTABLEID_EXTERNAL_MAPPER(), flow.getTableId().shortValue());\r
-        assertTrue(flow.getInstructions().getInstruction()\r
-                .get(0).getInstruction().toString().contains("_outputAction=OutputAction"));\r
-\r
-        // Note C1 == tunDest ie ip1\r
-        sfcNshHeader = new SfcNshHeaderBuilder().setNshMetaC1(SfcNshHeader.convertIpAddressToLong(ip1))\r
-                .setNshTunIpDst(ip1)\r
-                .setNshMetaC2(7L)\r
-                .setNshNsiToChain((short) 1)\r
-                .build();\r
-\r
-        flow = ChainActionFlows.createExternalFlow(sfcNshHeader, tunPort, netElements, policyManager, switchManager, ip2);\r
-\r
-        assertTrue(flow.getInstructions().getInstruction()\r
-                .get(0).getInstruction().toString().contains("_outputAction=OutputAction"));\r
+    public void createChainTunnelFlows_directionIn() throws Exception {\r
+        // Tenant\r
+        TenantBuilder tenantBuilder = buildTenant();\r
+        Tenant tenant = tenantBuilder.build();\r
+        // Source Endpoint\r
+        EndpointBuilder sourceEndpointBuilder = buildEndpoint(IPV4_0, MAC_0, CONNECTOR_0);\r
+        Endpoint sourceEndpoint = sourceEndpointBuilder.build();\r
+        EgKey sourceEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_0);\r
+        // Destination Endpoint\r
+        EndpointBuilder destinationEndpointBuilder = buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1);\r
+        Endpoint destinationEndpoint = destinationEndpointBuilder.build();\r
+        EgKey destinationEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_1);\r
+        // Nsh header\r
+        SfcNshHeaderBuilder nshHeaderBuilder = new SfcNshHeaderBuilder();\r
+        nshHeaderBuilder.setNshNsiFromChain((short) 250);\r
+        nshHeaderBuilder.setNshNspFromChain(27L);\r
+        SfcNshHeader nshHeader = nshHeaderBuilder.build();\r
+\r
+        when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant());\r
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);\r
+        when(ctx.getSwitchManager()).thenReturn(switchManager);\r
+        when(ctx.getPolicyManager()).thenReturn(policyManager);\r
+        when(ctx.getCurrentPolicy()).thenReturn(policyInfo);\r
+        when(switchManager.getTunnelPort(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(CONNECTOR_2);\r
+        when(switchManager.getTunnelIP(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(new IpAddress(IPV4_2));\r
+        when(policyManager.getTABLEID_PORTSECURITY()).thenReturn((short) 4);\r
+        when(policyManager.getTABLEID_SOURCE_MAPPER()).thenReturn((short) 2);\r
+\r
+        // Net elements\r
+        NetworkElements netElements = new NetworkElements(sourceEndpoint, destinationEndpoint, sourceEgKey,\r
+                destinationEgKey, NODE_ID, ctx);\r
+        assertNotNull(netElements);\r
+\r
+        ChainActionFlows.createChainTunnelFlows(nshHeader, netElements, ofWriter, ctx, HasDirection.Direction.In);\r
+\r
+        // Verify flows and capture arguments\r
+        verify(ofWriter, times(4)).writeFlow(nodeIdCaptor.capture(), tableIdCaptor.capture(), flowCaptor.capture());\r
+\r
+        // Verify nodeIds\r
+        for (NodeId capturedNodeId : nodeIdCaptor.getAllValues()) {\r
+            assertEquals(capturedNodeId, NODE_ID);\r
+        }\r
+\r
+        // Verify tableIds\r
+        List<Short> tableIds = tableIdCaptor.getAllValues();\r
+        Short expectedTableIds[] = {4, 2, 0, 2};\r
+        assertArrayEquals(expectedTableIds, tableIds.toArray());\r
+\r
+        // Verify flows\r
+        List<Flow> flows = flowCaptor.getAllValues();\r
+        assertNotNull(flows);\r
+        assertTrue(flows.size() == 4);\r
+        assertEquals(flows.get(0), allowFromChainTestFlow());\r
+        assertEquals(flows.get(1), createChainTunnelTestFlow(netElements).get(0)); // contains only 1 entry\r
+        assertEquals(flows.get(2), allowFromChainTunnelTestFlow());\r
+        assertEquals(flows.get(3), createChainBroadcastTestFlow());\r
     }\r
 \r
     @Test\r
-    public void returnOfPortFromNodeConnectorTest() {\r
-        NodeConnectorId ncId = new NodeConnectorId("openflow:1:42");\r
-        Integer port = ChainActionFlows.returnOfPortFromNodeConnector(ncId);\r
-        assertEquals(new Integer("42"), port);\r
+    public void createChainTunnelFlows_directionOut() throws Exception {\r
+        // Tenant\r
+        TenantBuilder tenantBuilder = buildTenant();\r
+        Tenant tenant = tenantBuilder.build();\r
+        // Source Endpoint\r
+        EndpointBuilder sourceEndpointBuilder = buildEndpoint(IPV4_0, MAC_0, CONNECTOR_0);\r
+        Endpoint sourceEndpoint = sourceEndpointBuilder.build();\r
+        EgKey sourceEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_0);\r
+        // Destination Endpoint\r
+        EndpointBuilder destinationEndpointBuilder = buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1);\r
+        Endpoint destinationEndpoint = destinationEndpointBuilder.build();\r
+        EgKey destinationEgKey = new EgKey(tenant.getId(), ENDPOINT_GROUP_1);\r
+        // Nsh header\r
+        SfcNshHeaderBuilder nshHeaderBuilder = new SfcNshHeaderBuilder();\r
+        nshHeaderBuilder.setNshNsiToChain((short) 255);\r
+        nshHeaderBuilder.setNshNspToChain(27L);\r
+        nshHeaderBuilder.setNshTunIpDst(IPV4_2);\r
+        SfcNshHeader nshHeader = nshHeaderBuilder.build();\r
+\r
+        when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant());\r
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);\r
+        when(ctx.getSwitchManager()).thenReturn(switchManager);\r
+        when(ctx.getPolicyManager()).thenReturn(policyManager);\r
+        when(ctx.getCurrentPolicy()).thenReturn(policyInfo);\r
+        when(switchManager.getTunnelPort(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(CONNECTOR_2);\r
+        when(switchManager.getTunnelIP(NODE_ID, TunnelTypeVxlanGpe.class)).thenReturn(new IpAddress(IPV4_2));\r
+        when(policyManager.getTABLEID_EXTERNAL_MAPPER()).thenReturn((short) 6);\r
+\r
+\r
+        // Net elements\r
+        NetworkElements netElements = new NetworkElements(sourceEndpoint, destinationEndpoint, sourceEgKey,\r
+                destinationEgKey, NODE_ID, ctx);\r
+        assertNotNull(netElements);\r
+\r
+        ChainActionFlows.createChainTunnelFlows(nshHeader, netElements, ofWriter, ctx, HasDirection.Direction.Out);\r
+\r
+        // Verify flows and capture arguments\r
+        verify(ofWriter, times(1)).writeFlow(NODE_ID, (short) 6, createExternalTestFlow());\r
+    }\r
+\r
+    private Flow allowFromChainTestFlow() {\r
+        MatchBuilder matchBuilder = new MatchBuilder();\r
+        FlowUtils.addNxNshc1RegMatch(matchBuilder, 0L);\r
+        FlowUtils.addNxNsiMatch(matchBuilder, (short) 250);\r
+        FlowUtils.addNxNspMatch(matchBuilder, 27L);\r
+        Match match = matchBuilder.setInPort(CONNECTOR_2).build();\r
+\r
+        FlowId flowId = FlowIdUtils.newFlowId((short) 4, "chainport", match);\r
+        FlowBuilder flowBuilder = new FlowBuilder().setTableId((short) 4).setBarrier(false).setHardTimeout(0)\r
+                .setIdleTimeout(0).setId(flowId).setPriority(1200).setMatch(match)\r
+                .setInstructions(FlowUtils.gotoTableInstructions((short) 2));\r
+        return flowBuilder.build();\r
+    }\r
+\r
+    private List<Flow> createChainTunnelTestFlow(NetworkElements networkElements) {\r
+        Preconditions.checkNotNull(networkElements);\r
+        List<Flow> flows = new ArrayList<>();\r
+        Action segReg = nxLoadRegAction(NxmNxReg0.class, BigInteger.valueOf(1L));\r
+        Action scgReg = nxLoadRegAction(NxmNxReg1.class, BigInteger.valueOf(0xffffff));\r
+        Action bdReg = nxLoadRegAction(NxmNxReg4.class, BigInteger.valueOf(0L));\r
+        Action fdReg = nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(0L));\r
+        Action vrfReg = nxLoadRegAction(NxmNxReg6.class, BigInteger.valueOf(0L));\r
+        for (L3Address address : networkElements.getDstEp().getL3Address()) {\r
+            Layer3Match l3Match = new Ipv4MatchBuilder().setIpv4Source(new Ipv4Prefix(address.getIpAddress()\r
+                    .getIpv4Address().getValue() + IP_PREFIX_32)).build();\r
+            MatchBuilder mb = new MatchBuilder().setInPort(CONNECTOR_2).setLayer3Match(l3Match)\r
+                    .setEthernetMatch(FlowUtils.ethernetMatch(null, null, FlowUtils.IPv4));\r
+            addNxTunIdMatch(mb, 2);\r
+            addNxNspMatch(mb, 27L);\r
+            addNxNsiMatch(mb, (short) 250);\r
+            Match match = mb.build();\r
+            FlowId flowId = FlowIdUtils.newFlowId((short) 2, "chaintunnel", match);\r
+            FlowBuilder flowBuilder = base((short) 2).setId(flowId).setPriority(150).setMatch(match).setInstructions(\r
+                    instructions(applyActionIns(segReg, scgReg, bdReg, fdReg, vrfReg),\r
+                            gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));\r
+            flows.add(flowBuilder.build());\r
+        }\r
+        assertTrue(flows.size() == 1);\r
+        return flows;\r
+    }\r
+\r
+    private Flow allowFromChainTunnelTestFlow() {\r
+        MatchBuilder matchBuilder = new MatchBuilder().setInPort(CONNECTOR_2);\r
+        addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg1.class, 0xffffffL));\r
+        Match match = matchBuilder.build();\r
+        FlowId flowId = FlowIdUtils.newFlowId((short) 0, "chainport", match);\r
+        FlowBuilder flowBuilder = base((short) 0).setId(flowId).setMatch(match)\r
+                .setPriority(65000).setInstructions(instructions(applyActionIns(nxOutputRegAction(NxmNxReg7.class))));\r
+        return flowBuilder.build();\r
+    }\r
+\r
+    private Flow createChainBroadcastTestFlow() {\r
+        MatchBuilder matchBuilder = new MatchBuilder().setInPort(CONNECTOR_2);\r
+        addNxNsiMatch(matchBuilder, (short) 250);\r
+        addNxNspMatch(matchBuilder, 27L);\r
+        addNxTunIdMatch(matchBuilder, 0);\r
+        Match match = matchBuilder.build();\r
+        FlowId flowId = FlowIdUtils.newFlowId((short) 2, "chainbroadcast", match);\r
+        FlowBuilder flowBuilder = base((short) 2).setId(flowId).setPriority(150).setMatch(match)\r
+                .setInstructions(instructions(applyActionIns(nxLoadRegAction(NxmNxReg5.class, BigInteger.valueOf(0))),\r
+                        gotoTableIns(ctx.getPolicyManager().getTABLEID_DESTINATION_MAPPER())));\r
+        return flowBuilder.build();\r
+    }\r
+\r
+    private Flow createExternalTestFlow() {\r
+        Action loadC1 = nxLoadNshc1RegAction(null);\r
+        Action loadC2 = nxLoadNshc2RegAction(2L);\r
+        Action loadChainTunVnId = nxLoadTunIdAction(BigInteger.valueOf(2L), false);\r
+        Action loadChainTunDest = nxLoadTunIPv4Action(IPV4_2.getValue(), false);\r
+        Action outputAction = FlowUtils.createActionResubmit(null, (short) 0);\r
+\r
+        MatchBuilder matchBuilder = new MatchBuilder();\r
+        addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, 0L));\r
+        addNxTunIdMatch(matchBuilder, 2);\r
+        addNxNspMatch(matchBuilder, 27L);\r
+        addNxNsiMatch(matchBuilder, (short) 255);\r
+\r
 \r
-        ncId = new NodeConnectorId("openflow:1");\r
-        Assert.assertNull(ChainActionFlows.returnOfPortFromNodeConnector(ncId));\r
+        Match match = matchBuilder.build();\r
+        FlowId flowId = FlowIdUtils.newFlowId(((short) 6), "chainexternal", match);\r
+        FlowBuilder flowBuilder = base((short) 6).setId(flowId).setPriority(1000).setMatch(match)\r
+                .setInstructions(instructions(applyActionIns(loadC1, loadC2, loadChainTunDest, loadChainTunVnId,\r
+                        outputAction)));\r
+        return flowBuilder.build();\r
     }\r
 }\r
index 8fe25913bd09f9b0347d31da4ea37d7d30befaf6..5f79a61f153b17bdd69efbb98cf0367bf4970095 100755 (executable)
 
 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
 
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
+import org.mockito.InOrder;
 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.ReadWriteTransaction;
-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.groupbasedpolicy.dto.EgKey;
-import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
 import org.opendaylight.groupbasedpolicy.dto.PolicyInfo;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.MapperUtilsTest;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.node.SwitchManager;
+import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.ovs.rev140701.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContextBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
-import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.util.concurrent.CheckedFuture;
-
-public class GroupTableTest {
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
 
-    private GroupTable groupTable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
-    private OfContext ofContext;
+public class GroupTableTest extends MapperUtilsTest {
 
+    private final GroupId GROUP_ID = new GroupId(27L);
+    private GroupTable groupTable;
+    // DataStore mocks
     private DataBroker dataBroker;
     private ReadOnlyTransaction readOnlyTransaction;
-    private WriteTransaction writeTransaction;
-    private ReadWriteTransaction readWriteTransaction;
-
-    private CheckedFuture<Optional<FlowCapableNode>, ReadFailedException> checkedFutureFCNRead;
-    private CheckedFuture<Void, TransactionCommitFailedException> checkedFutureWrite;
-    private Optional<FlowCapableNode> optionalFlowCapableNode;
-
+    private CheckedFuture checkedFutureFCNRead;
+    private Optional optionalFlowCapableNode;
     private FlowCapableNode flowCapableNode;
-    private Group group;
-    private List<Group> groups;
-    private Buckets buckets;
-    private Bucket bucket;
-    private NodeId nodeId;
-    private OfWriter ofWriter;
-    private Bucket bucketOther;
-    private EndpointManager endpointManager;
-    private Endpoint localEp;
-    private EgKey egKey;
-    private OfOverlayContext ofc;
-    private NodeConnectorId nodeConnectorId;
-
-    @SuppressWarnings("unchecked")
+
     @Before
-    public void initialisation() throws Exception {
-        ofContext = mock(OfContext.class);
-        groupTable = spy(new GroupTable(ofContext));
+    public void init() {
+        ctx = mock(OfContext.class);
+        endpointManager = mock(EndpointManager.class);
+        switchManager = mock(SwitchManager.class);
+        policyInfo = mock(PolicyInfo.class);
+        groupTable = new GroupTable(ctx);
+        ofWriter = mock(OfWriter.class);
+        OrdinalFactory.resetPolicyOrdinalValue();
+    }
 
-        dataBroker = mock(DataBroker.class);
-        when(ofContext.getDataBroker()).thenReturn(dataBroker);
+    @Test
+    public void sync_noEpNodeId() throws Exception {
+        initDataStoreMocks();
+        EndpointBuilder endpointBuilder = new EndpointBuilder();
+        Endpoint endpoint = endpointBuilder.build();
 
-        checkedFutureFCNRead =  mock(CheckedFuture.class);
-        optionalFlowCapableNode = mock(Optional.class);
-        flowCapableNode = mock(FlowCapableNode.class);
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);
 
-        when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode);
-
-        when(optionalFlowCapableNode.isPresent()).thenReturn(true);
-        when(optionalFlowCapableNode.get()).thenReturn(flowCapableNode);
+        groupTable.sync(endpoint, ofWriter);
 
+        verifyZeroInteractions(ofWriter);
+    }
 
-        readOnlyTransaction = mock(ReadOnlyTransaction.class);
+    @Test
+    public void sync_nodeIsNotFlowCapable() throws Exception {
+        initDataStoreMocks();
+        EndpointBuilder endpointBuilder = new EndpointBuilder();
+        OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder();
+        ofOverlayContextBuilder.setNodeId(NODE_ID);
+        endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build());
+        Endpoint endpoint = endpointBuilder.build();
+
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);
+        when(ctx.getDataBroker()).thenReturn(dataBroker);
+        when(endpointManager.getEndpointNodeId(any(Endpoint.class))).thenCallRealMethod();
         when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
-        when(readOnlyTransaction.read(any(LogicalDatastoreType.class),
-                any(InstanceIdentifier.class))).thenReturn(checkedFutureFCNRead);
-
-        writeTransaction = mock(WriteTransaction.class);
-        when(dataBroker.newWriteOnlyTransaction()).thenReturn(writeTransaction);
-        checkedFutureWrite = mock(CheckedFuture.class);
-        when(writeTransaction.submit()).thenReturn(checkedFutureWrite);
-
-        readWriteTransaction = mock(ReadWriteTransaction.class);
-        when(dataBroker.newReadWriteTransaction()).thenReturn(readWriteTransaction);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class)))
+                .thenReturn(checkedFutureFCNRead);
+        when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode);
+        when(optionalFlowCapableNode.isPresent()).thenReturn(true);
 
-        group = mock(Group.class);
-        groups = Collections.singletonList(group);
-        when(flowCapableNode.getGroup()).thenReturn(groups);
+        groupTable.sync(endpoint, ofWriter);
 
-        buckets = mock(Buckets.class);
-        when(group.getBuckets()).thenReturn(buckets);
-        bucket = mock(Bucket.class);
-        when(bucket.getAction()).thenReturn(Collections.singletonList(mock(Action.class)));
-        List<Bucket> bucketList = Collections.singletonList(bucket);
-        when(buckets.getBucket()).thenReturn(bucketList);
+        verify(optionalFlowCapableNode, times(1)).isPresent();
+        verifyZeroInteractions(ofWriter);
+    }
 
-        bucketOther = mock(Bucket.class);
-        when(bucketOther.getAction()).thenReturn(Collections.singletonList(mock(Action.class)));
+    @Test
+    public void sync_nullOrdinals() throws Exception {
+        initDataStoreMocks();
+        EndpointBuilder endpointBuilder = new EndpointBuilder();
+        OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder();
+        ofOverlayContextBuilder.setNodeId(NODE_ID);
+        endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build());
+        Endpoint endpoint = endpointBuilder.build();
+
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);
+        when(ctx.getDataBroker()).thenReturn(dataBroker);
+        when(endpointManager.getEndpointNodeId(any(Endpoint.class))).thenCallRealMethod();
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class)))
+                .thenReturn(checkedFutureFCNRead);
+        when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode);
+        when(optionalFlowCapableNode.isPresent()).thenReturn(true);
+        when(optionalFlowCapableNode.get()).thenReturn(flowCapableNode);
 
+        groupTable.sync(endpoint, ofWriter);
 
-        nodeId = mock(NodeId.class);
-        ofWriter = mock(OfWriter.class);
-
-        endpointManager = mock(EndpointManager.class);
-        when(ofContext.getEndpointManager()).thenReturn(endpointManager);
-        localEp = mock(Endpoint.class);
-        when(endpointManager.getEndpointsForNode(nodeId)).thenReturn(Collections.singletonList(
-                localEp));
-        IndexedTenant indexedTenant = mock(IndexedTenant.class);
-        when(ofContext.getTenant(any(TenantId.class))).thenReturn(indexedTenant);
-        EndpointGroup epg = mock(EndpointGroup.class);
-        when(indexedTenant.getEndpointGroup(any(EndpointGroupId.class))).thenReturn(epg);
-        egKey = mock(EgKey.class);
-        when(endpointManager.getGroupsForNode(any(NodeId.class))).thenReturn(
-                new HashSet<>(Collections.singletonList(egKey)));
-        ofc = mock(OfOverlayContext.class);
-        when(localEp.getAugmentation(OfOverlayContext.class)).thenReturn(ofc);
-        nodeConnectorId = mock(NodeConnectorId.class);
-        when(ofc.getNodeConnectorId()).thenReturn(nodeConnectorId);
+        verify(optionalFlowCapableNode, times(1)).isPresent();
+        verifyZeroInteractions(ofWriter);
     }
 
-    @Ignore
     @Test
-    public void updateTest() throws Exception {
-        //doNothing().when(groupTable).sync(NODE_ID, ofWriter);
+    public void sync() throws Exception {
+        initDataStoreMocks();
+        EndpointBuilder endpointBuilder = new EndpointBuilder();
+        OfOverlayContextBuilder ofOverlayContextBuilder = new OfOverlayContextBuilder();
+        ofOverlayContextBuilder.setNodeId(NODE_ID);
+        endpointBuilder.addAugmentation(OfOverlayContext.class, ofOverlayContextBuilder.build());
+        endpointBuilder.setNetworkContainment(NET_DOMAIN_ID);
+        endpointBuilder.setTenant(buildTenant().getId());
+        Endpoint endpoint = endpointBuilder.build();
+
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);
+        when(ctx.getCurrentPolicy()).thenReturn(policyInfo);
+        when(ctx.getDataBroker()).thenReturn(dataBroker);
+        when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant());
+        when(endpointManager.getEndpointNodeId(any(Endpoint.class))).thenCallRealMethod();
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(readOnlyTransaction);
+        when(readOnlyTransaction.read(eq(LogicalDatastoreType.OPERATIONAL), any(InstanceIdentifier.class)))
+                .thenReturn(checkedFutureFCNRead);
+        when(checkedFutureFCNRead.get()).thenReturn(optionalFlowCapableNode);
+        when(optionalFlowCapableNode.isPresent()).thenReturn(true);
+        when(optionalFlowCapableNode.get()).thenReturn(flowCapableNode);
 
-        //groupTable.sync(NODE_ID, ofWriter);
-        //verify(groupTable).sync(any(NodeId.class), any(OfWriter.class));
-    }
+        groupTable.sync(endpoint, ofWriter);
 
-    @Ignore
-    @Test
-    public void updateTestNoFCN() throws Exception {
-        doReturn(null).when(groupTable).getFCNodeFromDatastore(any(NodeId.class));
-
-        //groupTable.sync(NODE_ID, ofWriter);
-        verify(ofWriter, never()).writeBucket(any(NodeId.class), any(GroupId.class), any(Bucket.class));;
-        verify(ofWriter, never()).writeFlow(any(NodeId.class), any(Short.class), any(Flow.class));
-        verify(ofWriter, never()).writeGroup(any(NodeId.class), any(GroupId.class), any(GroupTypes.class),
-                any(String.class), any(String.class), any(Boolean.class));
+        verify(optionalFlowCapableNode, times(1)).isPresent();
+        verify(ofWriter, times(1)).writeGroup(NODE_ID, new GroupId(0L));
     }
 
-    @Ignore
     @Test
-    public void syncTestNoGroup() throws Exception {
-        when(ofWriter.groupExists(any(NodeId.class), any(Long.class))).thenReturn(false);
-        when(endpointManager.getGroupsForNode(any(NodeId.class))).thenReturn(
-                Collections.<EgKey>emptySet());
-
-        //groupTable.sync(NODE_ID, ofWriter);
-        verify(ofWriter).writeGroup(any(NodeId.class), any(GroupId.class));
+    public void syncGroups_groupsForNode() throws Exception {
+        // Define NodeIds
+        NodeId nodeWithoutTunnel = new NodeId("nodeIdWithoutTunnel");
+        NodeId nodeIdIpV6 = new NodeId("nodeIdIpV6");
+        NodeId nodeIdIpV4 = new NodeId("nodeIdIpV4");
+        Endpoint endpoint = buildEndpoint(IPV4_0, MAC_0, new NodeConnectorId(OPENFLOW + CONNECTOR_0.getValue())).build();
+
+        when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant());
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);
+        when(ctx.getCurrentPolicy()).thenReturn(policyInfo);
+
+        OrdinalFactory.EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
+        Preconditions.checkNotNull(ordinals);
+
+        // EgKeys
+        Set<EgKey> egKeys = new HashSet<>();
+        egKeys.add(new EgKey(buildTenant().getId(), endpoint.getEndpointGroup()));
+        // Nodes
+        Set<NodeId> nodeIds = new HashSet<>();
+        nodeIds.add(NODE_ID);
+        nodeIds.add(nodeWithoutTunnel);
+        nodeIds.add(nodeIdIpV6);
+        nodeIds.add(nodeIdIpV4);
+        // Endpoints
+        Collection<Endpoint> endpoints = new HashSet<>();
+        endpoints.add(buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1).build());
+        endpoints.add(buildEndpoint(IPV4_2, MAC_2, CONNECTOR_2).build());
+
+        when(ctx.getSwitchManager()).thenReturn(switchManager);
+        when(endpointManager.getGroupsForNode(NODE_ID)).thenReturn(egKeys);
+        when(endpointManager.getNodesForGroup(any(EgKey.class))).thenReturn(nodeIds);
+        when(endpointManager.getEndpointsForNode(any(NodeId.class))).thenReturn(endpoints);
+        when(switchManager.getTunnelIP(nodeIdIpV6, TunnelTypeVxlan.class)).thenReturn(new IpAddress(IPV6_1));
+        when(switchManager.getTunnelIP(nodeIdIpV4, TunnelTypeVxlan.class)).thenReturn(new IpAddress(IPV4_1));
+        when(switchManager.getTunnelPort(NODE_ID, TunnelTypeVxlan.class)).thenReturn(CONNECTOR_1);
+        when(policyInfo.getPeers(any(EgKey.class))).thenReturn(egKeys);
+
+        groupTable.syncGroups(NODE_ID, ordinals, endpoint, GROUP_ID, ofWriter);
+
+        // Verify method order
+        InOrder order = inOrder(endpointManager, policyInfo, switchManager, ofWriter);
+        order.verify(endpointManager, times(1)).getGroupsForNode(NODE_ID);
+        order.verify(endpointManager, times(1)).getNodesForGroup(any(EgKey.class));
+        order.verify(policyInfo, times(1)).getPeers(any(EgKey.class));
+        order.verify(endpointManager, times(1)).getNodesForGroup(any(EgKey.class));
+        order.verify(switchManager, times(1)).getTunnelIP(nodeWithoutTunnel, TunnelTypeVxlan.class);
+        order.verify(switchManager, times(1)).getTunnelPort(NODE_ID, TunnelTypeVxlan.class);
+        order.verify(switchManager, times(1)).getTunnelIP(any(NodeId.class), eq(TunnelTypeVxlan.class));
+        order.verify(switchManager, times(1)).getTunnelPort(NODE_ID, TunnelTypeVxlan.class);
+        order.verify(switchManager, times(1)).getTunnelIP(any(NodeId.class), eq(TunnelTypeVxlan.class));
+        order.verify(switchManager, times(1)).getTunnelPort(NODE_ID, TunnelTypeVxlan.class);
+        order.verify(ofWriter, atLeastOnce()).writeBucket(any(NodeId.class), any(GroupId.class), any(Bucket.class));
     }
 
-    @Ignore
     @Test
-    public void syncTestGroupExists() throws Exception {
-        when(ofWriter.groupExists(any(NodeId.class), any(Long.class))).thenReturn(true);
-        when(endpointManager.getGroupsForNode(any(NodeId.class))).thenReturn(
-                Collections.<EgKey>emptySet());
+    public void syncGroups_externalEpsWithoutLocation() throws Exception {
+        EndpointBuilder endpointBuilder = buildEndpoint(IPV4_0, MAC_0, new NodeConnectorId(OPENFLOW + CONNECTOR_0.getValue()));
+        endpointBuilder.setNetworkContainment(L2FD_ID);
+        Endpoint endpoint = endpointBuilder.build();
+
+        when(ctx.getTenant(any(TenantId.class))).thenReturn(getTestIndexedTenant());
+        when(ctx.getEndpointManager()).thenReturn(endpointManager);
+        when(ctx.getCurrentPolicy()).thenReturn(policyInfo);
+
+        OrdinalFactory.EndpointFwdCtxOrdinals ordinals = OrdinalFactory.getEndpointFwdCtxOrdinals(ctx, endpoint);
+        Preconditions.checkNotNull(ordinals);
+        // EgKeys
+        Set<EgKey> egKeys = new HashSet<>();
+        egKeys.add(new EgKey(buildTenant().getId(), endpoint.getEndpointGroup()));
+        // NodeConnectorIds
+        Set<NodeConnectorId> externalPorts = new HashSet<>();
+        externalPorts.add(new NodeConnectorId(OPENFLOW + CONNECTOR_1.getValue())); // Correct format
+        externalPorts.add(CONNECTOR_2); // NumberFormatException
+        // Endpoints
+        Collection<Endpoint> endpoints = new HashSet<>();
+        EndpointBuilder noLocEndpointBuilder = buildEndpoint(IPV4_1, MAC_1, CONNECTOR_1);
+        noLocEndpointBuilder.setNetworkContainment(L2FD_ID);
+        endpoints.add(noLocEndpointBuilder.build());
+
+        when(ctx.getSwitchManager()).thenReturn(switchManager);
+        when(endpointManager.getGroupsForNode(NODE_ID)).thenReturn(egKeys);
+        when(endpointManager.getExtEpsNoLocForGroup(any(EgKey.class))).thenReturn(endpoints);
+        when(switchManager.getExternalPorts(NODE_ID)).thenReturn(externalPorts);
+
+        groupTable.syncGroups(NODE_ID, ordinals, endpoint, GROUP_ID, ofWriter);
+
+        // Verify method order
+        InOrder order = inOrder(endpointManager, policyInfo, switchManager, ofWriter);
+        order.verify(endpointManager, times(1)).getGroupsForNode(NODE_ID);
+        order.verify(endpointManager, times(1)).getExtEpsNoLocForGroup(any(EgKey.class));
+        order.verify(switchManager, times(1)).getExternalPorts(any(NodeId.class));
+        order.verify(ofWriter, times(1)).writeBucket(any(NodeId.class), any(GroupId.class), any(Bucket.class));
+    }
 
-        //groupTable.sync(NODE_ID, ofWriter);
-        verify(ofWriter, never()).writeGroup(any(NodeId.class), any(GroupId.class));
+    private void initDataStoreMocks() {
+        dataBroker = mock(DataBroker.class);
+        readOnlyTransaction = mock(ReadOnlyTransaction.class);
+        checkedFutureFCNRead = mock(CheckedFuture.class);
+        optionalFlowCapableNode = mock(Optional.class);
+        flowCapableNode = mock(FlowCapableNode.class);
     }
 }