ONOS-973: Implemented a unit test for OpenFlowGroupProvider implmentation.
 - Fixed a bug in OpenFlowGroupProvider of wrong handling of pending group operations.

Change-Id: I70b80629f4eed000110d242f3558abe49b6b13bc
diff --git a/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java b/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
new file mode 100644
index 0000000..dd6d9ff
--- /dev/null
+++ b/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
@@ -0,0 +1,402 @@
+package org.onosproject.provider.of.group.impl;
+
+import com.google.common.collect.Lists;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.group.DefaultGroupBucket;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupOperation;
+import org.onosproject.net.group.GroupOperations;
+import org.onosproject.net.group.GroupProvider;
+import org.onosproject.net.group.GroupProviderRegistry;
+import org.onosproject.net.group.GroupProviderService;
+import org.onosproject.net.provider.AbstractProviderService;
+import org.onosproject.net.provider.ProviderId;
+import org.onosproject.openflow.controller.Dpid;
+import org.onosproject.openflow.controller.OpenFlowController;
+import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowSwitch;
+import org.onosproject.openflow.controller.OpenFlowSwitchListener;
+import org.onosproject.openflow.controller.PacketListener;
+import org.onosproject.openflow.controller.RoleState;
+import org.projectfloodlight.openflow.protocol.OFFactories;
+import org.projectfloodlight.openflow.protocol.OFFactory;
+import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupMod;
+import org.projectfloodlight.openflow.protocol.OFGroupModFailedCode;
+import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
+import org.projectfloodlight.openflow.protocol.OFGroupType;
+import org.projectfloodlight.openflow.protocol.OFMessage;
+import org.projectfloodlight.openflow.protocol.OFPortDesc;
+import org.projectfloodlight.openflow.protocol.OFVersion;
+import org.projectfloodlight.openflow.protocol.errormsg.OFGroupModFailedErrorMsg;
+import org.projectfloodlight.openflow.types.OFGroup;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class OpenFlowGroupProviderTest {
+
+    OpenFlowGroupProvider provider = new OpenFlowGroupProvider();
+    private final OpenFlowController controller = new TestController();
+    GroupProviderRegistry providerRegistry = new TestGroupProviderRegistry();
+    GroupProviderService providerService;
+
+    private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
+    private Dpid dpid1 = Dpid.dpid(deviceId.uri());
+
+    @Before
+    public void setUp() {
+        provider.controller = controller;
+        provider.providerRegistry = providerRegistry;
+        provider.activate();
+    }
+
+    @Test
+    public void basics() {
+        assertNotNull("registration expected", providerService);
+        assertEquals("incorrect provider", provider, providerService.provider());
+    }
+
+    @Test
+    public void addGroup() {
+
+        GroupId groupId = new DefaultGroupId(1);
+
+        List<GroupBucket> bucketList = Lists.newArrayList();
+        TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+        builder.setOutput(PortNumber.portNumber(1));
+        GroupBucket bucket =
+                DefaultGroupBucket.createSelectGroupBucket(builder.build());
+        bucketList.add(bucket);
+        GroupBuckets buckets = new GroupBuckets(bucketList);
+
+        List<GroupOperation> operationList = Lists.newArrayList();
+        GroupOperation operation = GroupOperation.createAddGroupOperation(groupId,
+                GroupDescription.Type.SELECT, buckets);
+        operationList.add(operation);
+        GroupOperations operations = new GroupOperations(operationList);
+
+        provider.performGroupOperation(deviceId, operations);
+
+        final Dpid dpid = Dpid.dpid(deviceId.uri());
+        TestOpenFlowSwitch sw = (TestOpenFlowSwitch) controller.getSwitch(dpid);
+        assertNotNull("Switch should not be nul", sw);
+        assertNotNull("OFGroupMsg should not be null", sw.msg);
+
+    }
+
+
+    @Test
+    public void groupModFailure() {
+        TestOpenFlowGroupProviderService testProviderService =
+                (TestOpenFlowGroupProviderService) providerService;
+
+        GroupId groupId = new DefaultGroupId(1);
+        List<GroupBucket> bucketList = Lists.newArrayList();
+        TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
+        builder.setOutput(PortNumber.portNumber(1));
+        GroupBucket bucket =
+                DefaultGroupBucket.createSelectGroupBucket(builder.build());
+        bucketList.add(bucket);
+        GroupBuckets buckets = new GroupBuckets(bucketList);
+        List<GroupOperation> operationList = Lists.newArrayList();
+        GroupOperation operation = GroupOperation.createAddGroupOperation(groupId,
+                GroupDescription.Type.SELECT, buckets);
+        operationList.add(operation);
+        GroupOperations operations = new GroupOperations(operationList);
+
+        provider.performGroupOperation(deviceId, operations);
+
+        OFGroupModFailedErrorMsg.Builder errorBuilder =
+                OFFactories.getFactory(OFVersion.OF_13).errorMsgs().buildGroupModFailedErrorMsg();
+        OFGroupMod.Builder groupBuilder = OFFactories.getFactory(OFVersion.OF_13).buildGroupModify();
+        groupBuilder.setGroupType(OFGroupType.ALL);
+        groupBuilder.setGroup(OFGroup.of(1));
+        errorBuilder.setCode(OFGroupModFailedCode.GROUP_EXISTS);
+        errorBuilder.setXid(provider.getXidAndAdd(0) - 1);
+
+        controller.processPacket(dpid1, errorBuilder.build());
+
+        assertNotNull("Operation failed should not be null",
+                testProviderService.failedOperation);
+    }
+
+
+    @Test
+    public void groupStatsEvent() {
+        TestOpenFlowGroupProviderService testProviderService =
+                (TestOpenFlowGroupProviderService) providerService;
+
+        OFGroupStatsReply.Builder rep1 =
+                OFFactories.getFactory(OFVersion.OF_13).buildGroupStatsReply();
+        rep1.setXid(1);
+        controller.processPacket(dpid1, rep1.build());
+        OFGroupDescStatsReply.Builder rep2 =
+                OFFactories.getFactory(OFVersion.OF_13).buildGroupDescStatsReply();
+        assertNull("group entries is not set yet", testProviderService.getGroupEntries());
+
+        rep2.setXid(2);
+        controller.processPacket(dpid1, rep2.build());
+        assertNotNull("group entries should be set", testProviderService.getGroupEntries());
+    }
+
+
+
+    @After
+    public void tearDown() {
+        provider.deactivate();
+        provider.providerRegistry = null;
+        provider.controller = null;
+    }
+
+    private class TestOpenFlowGroupProviderService
+            extends AbstractProviderService<GroupProvider>
+            implements GroupProviderService {
+
+        Collection<Group> groups = null;
+        GroupOperation failedOperation = null;
+
+        protected TestOpenFlowGroupProviderService(GroupProvider provider) {
+            super(provider);
+        }
+
+        @Override
+        public void groupOperationFailed(GroupOperation operation) {
+            this.failedOperation = operation;
+        }
+
+        @Override
+        public void pushGroupMetrics(DeviceId deviceId, Collection<Group> groupEntries) {
+            this.groups = groupEntries;
+        }
+
+        public Collection<Group> getGroupEntries() {
+            return groups;
+        }
+    }
+
+    private class TestController implements OpenFlowController {
+
+        OpenFlowEventListener eventListener = null;
+        List<OpenFlowSwitch> switches = Lists.newArrayList();
+
+        public TestController() {
+            OpenFlowSwitch testSwitch = new TestOpenFlowSwitch();
+            switches.add(testSwitch);
+        }
+
+        @Override
+        public void addListener(OpenFlowSwitchListener listener) {
+        }
+
+        @Override
+        public void removeListener(OpenFlowSwitchListener listener) {
+
+        }
+
+        @Override
+        public void addPacketListener(int priority, PacketListener listener) {
+
+        }
+
+        @Override
+        public void removePacketListener(PacketListener listener) {
+
+        }
+
+        @Override
+        public void addEventListener(OpenFlowEventListener listener) {
+            this.eventListener = listener;
+        }
+
+        @Override
+        public void removeEventListener(OpenFlowEventListener listener) {
+
+        }
+
+        @Override
+        public void write(Dpid dpid, OFMessage msg) {
+
+        }
+
+        @Override
+        public void processPacket(Dpid dpid, OFMessage msg) {
+            eventListener.handleMessage(dpid, msg);
+        }
+
+        @Override
+        public void setRole(Dpid dpid, RoleState role) {
+
+        }
+
+        @Override
+        public Iterable<OpenFlowSwitch> getSwitches() {
+            return switches;
+        }
+
+        @Override
+        public Iterable<OpenFlowSwitch> getMasterSwitches() {
+            return null;
+        }
+
+        @Override
+        public Iterable<OpenFlowSwitch> getEqualSwitches() {
+            return null;
+        }
+
+        @Override
+        public OpenFlowSwitch getSwitch(Dpid dpid) {
+            return switches.get(0);
+        }
+
+        @Override
+        public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
+            return null;
+        }
+
+        @Override
+        public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
+            return null;
+        }
+
+    }
+
+    private class TestGroupProviderRegistry implements GroupProviderRegistry {
+
+        @Override
+        public GroupProviderService register(GroupProvider provider) {
+            providerService = new TestOpenFlowGroupProviderService(provider);
+            return providerService;
+        }
+
+        @Override
+        public void unregister(GroupProvider provider) {
+        }
+
+        @Override
+        public Set<ProviderId> getProviders() {
+            return null;
+        }
+    }
+
+    private class TestOpenFlowSwitch implements OpenFlowSwitch {
+
+        OFMessage msg = null;
+
+        @Override
+        public void sendMsg(OFMessage msg) {
+            this.msg = msg;
+        }
+
+        @Override
+        public void sendMsg(List<OFMessage> msgs) {
+
+        }
+
+        @Override
+        public void sendMsg(OFMessage msg, TableType tableType) {
+
+        }
+
+        @Override
+        public void handleMessage(OFMessage fromSwitch) {
+
+        }
+
+        @Override
+        public void setRole(RoleState role) {
+
+        }
+
+        @Override
+        public RoleState getRole() {
+            return null;
+        }
+
+        @Override
+        public List<OFPortDesc> getPorts() {
+            return null;
+        }
+
+        @Override
+        public OFFactory factory() {
+            return OFFactories.getFactory(OFVersion.OF_13);
+        }
+
+        @Override
+        public String getStringId() {
+            return null;
+        }
+
+        @Override
+        public long getId() {
+            return 0;
+        }
+
+        @Override
+        public String manufacturerDescription() {
+            return null;
+        }
+
+        @Override
+        public String datapathDescription() {
+            return null;
+        }
+
+        @Override
+        public String hardwareDescription() {
+            return null;
+        }
+
+        @Override
+        public String softwareDescription() {
+            return null;
+        }
+
+        @Override
+        public String serialNumber() {
+            return null;
+        }
+
+        @Override
+        public boolean isConnected() {
+            return false;
+        }
+
+        @Override
+        public void disconnectSwitch() {
+
+        }
+
+        @Override
+        public void returnRoleReply(RoleState requested, RoleState response) {
+
+        }
+
+        @Override
+        public boolean isOptical() {
+            return false;
+        }
+
+        @Override
+        public String channelId() {
+            return null;
+        }
+    }
+}
\ No newline at end of file