ONOS-6027 add request/cancelPackets tests to VirtualNetworkPacketManagerTest

Change-Id: Id1316a3768061bb61980a33f0e664805249eaa18
diff --git a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
index 41b7dce..3f5a8a6 100644
--- a/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
+++ b/incubator/net/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManager.java
@@ -302,7 +302,7 @@
      * @param request the packet request
      */
     private void pushRule(Device device, PacketRequest request) {
-        if (!device.type().equals(Device.Type.SWITCH)) {
+        if (!device.type().equals(Device.Type.VIRTUAL)) {
             return;
         }
 
@@ -325,7 +325,7 @@
      * @param request the packet request
      */
     private void removeRule(Device device, PacketRequest request) {
-        if (!device.type().equals(Device.Type.SWITCH)) {
+        if (!device.type().equals(Device.Type.VIRTUAL)) {
             return;
         }
         ForwardingObjective forwarding = createBuilder(request)
diff --git a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java
index 9fe9d86..1a49e22 100644
--- a/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java
+++ b/incubator/net/src/test/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkPacketManagerTest.java
@@ -16,18 +16,22 @@
 
 package org.onosproject.incubator.net.virtual.impl;
 
+import com.google.common.collect.Sets;
 import org.junit.Before;
 import org.junit.Test;
 import org.onlab.junit.TestUtils;
 import org.onlab.osgi.TestServiceDirectory;
+import org.onosproject.TestApplicationId;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.ClusterServiceAdapter;
 import org.onosproject.common.event.impl.TestEventDispatcher;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.core.IdGenerator;
 import org.onosproject.event.EventDeliveryService;
 import org.onosproject.incubator.net.virtual.NetworkId;
+import org.onosproject.incubator.net.virtual.VirtualDevice;
 import org.onosproject.incubator.net.virtual.VirtualNetwork;
 import org.onosproject.incubator.net.virtual.VirtualNetworkPacketStore;
 import org.onosproject.incubator.net.virtual.VirtualNetworkStore;
@@ -37,21 +41,36 @@
 import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService;
 import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore;
 import org.onosproject.incubator.store.virtual.impl.SimpleVirtualPacketStore;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.NetTestTools;
+import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.flowobjective.Objective;
 import org.onosproject.net.intent.FakeIntentManager;
 import org.onosproject.net.intent.TestableIntentService;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.OutboundPacket;
 import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.service.TestStorageService;
 
 import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
 import static org.junit.Assert.*;
+import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
+import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE;
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.onosproject.net.packet.PacketPriority.REACTIVE;
 
 public class VirtualNetworkPacketManagerTest extends VirtualNetworkTestUtil {
 
@@ -74,6 +93,8 @@
     private VirtualNetworkPacketManager packetManager1;
     private VirtualNetworkPacketManager packetManager2;
 
+    private ApplicationId appId = new TestApplicationId("VirtualPacketManagerTest");
+
     @Before
     public void setUp() throws TestUtils.TestUtilsException {
         virtualNetworkManagerStore = new DistributedVirtualNetworkStore();
@@ -163,6 +184,93 @@
         assertEquals("Packet not emitted correctly", packet, emittedPacket);
     }
 
+    /**
+     * Tests the addition and removal of packet requests for a device.
+     *
+     * @throws TestUtils.TestUtilsException
+     */
+    @Test
+    public void requestAndCancelPacketsForDeviceTest() throws TestUtils.TestUtilsException {
+        TestFlowObjectiveService testFlowObjectiveService = new TestFlowObjectiveService();
+        TestUtils.setField(packetManager1, "objectiveService", testFlowObjectiveService);
+        TrafficSelector ts = DefaultTrafficSelector.emptySelector();
+        Optional<DeviceId> optionalDeviceId = Optional.of(VDID3);
+
+        // add first request
+        packetManager1.requestPackets(ts, CONTROL, appId, optionalDeviceId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, CONTROL, ADD);
+
+        // add same request as first
+        packetManager1.requestPackets(ts, CONTROL, appId, optionalDeviceId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, CONTROL, ADD);
+
+        // add second request
+        packetManager1.requestPackets(ts, REACTIVE, appId, optionalDeviceId);
+        assertEquals("2 packets expected", 2, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, REACTIVE, ADD);
+
+        // cancel second request
+        packetManager1.cancelPackets(ts, REACTIVE, appId, optionalDeviceId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, REACTIVE, REMOVE);
+
+        // cancel second request again
+        packetManager1.cancelPackets(ts, REACTIVE, appId, optionalDeviceId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, REACTIVE, REMOVE);
+
+        // cancel first request
+        packetManager1.cancelPackets(ts, CONTROL, appId, optionalDeviceId);
+        assertEquals("0 packet expected", 0, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, CONTROL, REMOVE);
+    }
+
+    /**
+     * Tests the addition and removal of packet requests for all devices in a virtual
+     * network.
+     *
+     * @throws TestUtils.TestUtilsException
+     */
+    @Test
+    public void requestAndCancelPacketsForVnetTest() throws TestUtils.TestUtilsException {
+        TestFlowObjectiveService testFlowObjectiveService = new TestFlowObjectiveService();
+        TestUtils.setField(packetManager1, "objectiveService", testFlowObjectiveService);
+        TrafficSelector ts = DefaultTrafficSelector.emptySelector();
+        Set<VirtualDevice> vnet1Devices = manager.getVirtualDevices(vnet1.id());
+
+        // add first request
+        packetManager1.requestPackets(ts, CONTROL, appId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectives(vnet1Devices, ts, CONTROL, ADD);
+
+        // add same request as first
+        packetManager1.requestPackets(ts, CONTROL, appId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectives(vnet1Devices, ts, CONTROL, ADD);
+
+        // add second request
+        packetManager1.requestPackets(ts, REACTIVE, appId);
+        assertEquals("2 packets expected", 2, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectives(vnet1Devices, ts, REACTIVE, ADD);
+
+        // cancel second request
+        packetManager1.cancelPackets(ts, REACTIVE, appId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectives(vnet1Devices, ts, REACTIVE, REMOVE);
+
+        // cancel second request again
+        packetManager1.cancelPackets(ts, REACTIVE, appId);
+        assertEquals("1 packet expected", 1, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectives(vnet1Devices, ts, REACTIVE, REMOVE);
+
+        // cancel first request
+        packetManager1.cancelPackets(ts, CONTROL, appId);
+        assertEquals("0 packet expected", 0, packetManager1.getRequests().size());
+        testFlowObjectiveService.validateObjectives(vnet1Devices, ts, CONTROL, REMOVE);
+    }
+
     private static OutboundPacket emittedPacket = null;
 
     /**
@@ -181,6 +289,11 @@
                 }
             };
         }
+
+        @Override
+        public ApplicationId registerApplication(String name) {
+            return appId;
+        }
     }
 
     private class TestPacketProvider extends AbstractVirtualProvider
@@ -212,4 +325,52 @@
 
         }
     }
-}
\ No newline at end of file
+
+    private class TestFlowObjectiveService extends FlowObjectiveServiceAdapter {
+        // track objectives received for each device
+        private final Map<DeviceId, Set<ForwardingObjective>> deviceFwdObjs = new HashMap<>();
+
+        @Override
+        public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
+            deviceFwdObjs.compute(deviceId, (deviceId1, forwardingObjectives) -> {
+                        if (forwardingObjectives == null) {
+                            return Sets.newHashSet(forwardingObjective);
+                        }
+                        forwardingObjectives.add(forwardingObjective);
+                        return forwardingObjectives;
+                    }
+            );
+        }
+
+        private void validateObjectives(Set<VirtualDevice> vdevs, TrafficSelector ts,
+                                    PacketPriority pp, Objective.Operation op) {
+            assertNotNull("set of devices must not be null", vdevs);
+            for (VirtualDevice vdev: vdevs) {
+                assertTrue("Forwarding objective must exist for device " + vdev.id(),
+                           deviceHasObjective(vdev.id(), ts, pp, op));
+            }
+        }
+
+        private void validateObjectiveForDevice(DeviceId deviceId, TrafficSelector ts,
+                                    PacketPriority pp, Objective.Operation op) {
+            assertNotNull("deviceId must not be null", deviceId);
+            assertTrue("Forwarding objective must exist for device " + deviceId,
+                           deviceHasObjective(deviceId, ts, pp, op));
+        }
+
+        private boolean deviceHasObjective(DeviceId deviceId, TrafficSelector ts,
+                                   PacketPriority pp, Objective.Operation op) {
+            Set<ForwardingObjective> fos = deviceFwdObjs.get(deviceId);
+            if (fos != null) {
+                for (ForwardingObjective fo: fos) {
+                    if (fo.selector().equals(ts)
+                            && fo.priority() == pp.priorityValue()
+                            && fo.op().equals(op)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+}
diff --git a/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/SimpleVirtualPacketStore.java b/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/SimpleVirtualPacketStore.java
index 93fc7d8..cb779ee 100644
--- a/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/SimpleVirtualPacketStore.java
+++ b/incubator/store/src/main/java/org/onosproject/incubator/store/virtual/impl/SimpleVirtualPacketStore.java
@@ -54,6 +54,9 @@
 
         requests.get(networkId).compute(request.selector(), (s, existingRequests) -> {
             if (existingRequests == null) {
+                if (hasDelegate(networkId)) {
+                    delegateMap.get(networkId).requestPackets(request);
+                }
                 return ImmutableSet.of(request);
             } else if (!existingRequests.contains(request)) {
                 if (hasDelegate(networkId)) {
@@ -75,12 +78,12 @@
             if (existingRequests.contains(request)) {
                 HashSet<PacketRequest> newRequests = Sets.newHashSet(existingRequests);
                 newRequests.remove(request);
+                if (hasDelegate(networkId)) {
+                    delegateMap.get(networkId).cancelPackets(request);
+                }
                 if (newRequests.size() > 0) {
                     return ImmutableSet.copyOf(newRequests);
                 } else {
-                    if (hasDelegate(networkId)) {
-                        delegateMap.get(networkId).cancelPackets(request);
-                    }
                     return null;
                 }
             } else {