ONOS-944: Implemented a Group operation failure handler in GroupManger and SimpleGroupStore.

Change-Id: Ib3be4d534ceff04af2dad0c062fd4cd63d49ee82
diff --git a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java
index 8c7de08..9258dcc 100644
--- a/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java
+++ b/core/store/trivial/src/main/java/org/onosproject/store/trivial/impl/SimpleGroupStore.java
@@ -43,6 +43,7 @@
 import org.onosproject.net.group.GroupEvent;
 import org.onosproject.net.group.GroupEvent.Type;
 import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.group.GroupOperation;
 import org.onosproject.net.group.GroupStore;
 import org.onosproject.net.group.GroupStoreDelegate;
 import org.onosproject.net.group.StoredGroupEntry;
@@ -474,6 +475,41 @@
     }
 
     @Override
+    public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
+
+        StoredGroupEntry existing = (groupEntriesById.get(
+                deviceId) != null) ?
+                groupEntriesById.get(deviceId).get(operation.groupId()) :
+                null;
+
+        if (existing == null) {
+            log.warn("No group entry with ID {} found ", operation.groupId());
+            return;
+        }
+
+        switch (operation.opType()) {
+        case ADD:
+            notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing));
+            break;
+        case MODIFY:
+            notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing));
+            break;
+        case DELETE:
+            notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_FAILED, existing));
+            break;
+        default:
+            log.warn("Unknown group operation type {}", operation.opType());
+        }
+
+        ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
+                getGroupKeyTable(existing.deviceId());
+        ConcurrentMap<GroupId, StoredGroupEntry> idTable =
+                getGroupIdTable(existing.deviceId());
+        idTable.remove(existing.id());
+        keyTable.remove(existing.appCookie());
+    }
+
+    @Override
     public void addOrUpdateExtraneousGroupEntry(Group group) {
         ConcurrentMap<GroupId, Group> extraneousIdTable =
                 getExtraneousGroupIdTable(group.deviceId());
@@ -497,4 +533,6 @@
         return FluentIterable.from(
                   getExtraneousGroupIdTable(deviceId).values());
     }
+
+
 }
diff --git a/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java b/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
index 277e1ca..33d7118 100644
--- a/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
+++ b/core/store/trivial/src/test/java/org/onosproject/store/trivial/impl/SimpleGroupStoreTest.java
@@ -40,6 +40,7 @@
 import org.onosproject.net.group.GroupDescription;
 import org.onosproject.net.group.GroupEvent;
 import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.group.GroupOperation;
 import org.onosproject.net.group.GroupStore.UpdateType;
 import org.onosproject.net.group.GroupStoreDelegate;
 
@@ -129,6 +130,18 @@
                 createdGroupId = event.subject().id();
                 assertEquals(Group.GroupState.PENDING_DELETE,
                              event.subject().state());
+            } else if (expectedEvent == GroupEvent.Type.GROUP_ADD_FAILED) {
+                createdGroupId = event.subject().id();
+                assertEquals(Group.GroupState.PENDING_ADD,
+                        event.subject().state());
+            } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_FAILED) {
+                createdGroupId = event.subject().id();
+                assertEquals(Group.GroupState.PENDING_UPDATE,
+                        event.subject().state());
+            } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_FAILED) {
+                createdGroupId = event.subject().id();
+                assertEquals(Group.GroupState.PENDING_DELETE,
+                        event.subject().state());
             }
         }
 
@@ -310,6 +323,92 @@
 
         simpleGroupStore.unsetDelegate(removeGroupEntryDelegate);
 
+
+    }
+
+    @Test
+    public void testGroupOperationFailure() {
+
+        simpleGroupStore.deviceInitialAuditCompleted(D1);
+
+        ApplicationId appId =
+                new DefaultApplicationId(2, "org.groupstore.test");
+        TestGroupKey key = new TestGroupKey("group1");
+        PortNumber[] ports = {PortNumber.portNumber(31),
+                PortNumber.portNumber(32)};
+        List<PortNumber> outPorts = new ArrayList<PortNumber>();
+        outPorts.add(ports[0]);
+        outPorts.add(ports[1]);
+
+        List<GroupBucket> buckets = new ArrayList<GroupBucket>();
+        for (PortNumber portNumber: outPorts) {
+            TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+            tBuilder.setOutput(portNumber)
+                    .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
+                    .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
+                    .pushMpls()
+                    .setMpls(106);
+            buckets.add(DefaultGroupBucket.createSelectGroupBucket(
+                    tBuilder.build()));
+        }
+        GroupBuckets groupBuckets = new GroupBuckets(buckets);
+        GroupDescription groupDesc = new DefaultGroupDescription(
+                D1,
+                Group.Type.SELECT,
+                groupBuckets,
+                key,
+                appId);
+        InternalGroupStoreDelegate checkStoreGroupDelegate =
+                new InternalGroupStoreDelegate(key,
+                        groupBuckets,
+                        GroupEvent.Type.GROUP_ADD_REQUESTED);
+        simpleGroupStore.setDelegate(checkStoreGroupDelegate);
+        // Testing storeGroup operation
+        simpleGroupStore.storeGroupDescription(groupDesc);
+        simpleGroupStore.unsetDelegate(checkStoreGroupDelegate);
+
+        // Testing Group add operation failure
+        Group createdGroup = simpleGroupStore.getGroup(D1, key);
+        checkStoreGroupDelegate.verifyGroupId(createdGroup.id());
+
+        GroupOperation groupAddOp = GroupOperation.
+                createAddGroupOperation(createdGroup.id(),
+                        createdGroup.type(),
+                        createdGroup.buckets());
+        InternalGroupStoreDelegate checkGroupAddFailureDelegate =
+                new InternalGroupStoreDelegate(key,
+                        groupBuckets,
+                        GroupEvent.Type.GROUP_ADD_FAILED);
+        simpleGroupStore.setDelegate(checkGroupAddFailureDelegate);
+        simpleGroupStore.groupOperationFailed(D1, groupAddOp);
+
+
+        // Testing Group modify operation failure
+        simpleGroupStore.unsetDelegate(checkGroupAddFailureDelegate);
+        GroupOperation groupModOp = GroupOperation.
+                createModifyGroupOperation(createdGroup.id(),
+                        createdGroup.type(),
+                        createdGroup.buckets());
+        InternalGroupStoreDelegate checkGroupModFailureDelegate =
+                new InternalGroupStoreDelegate(key,
+                        groupBuckets,
+                        GroupEvent.Type.GROUP_UPDATE_FAILED);
+        simpleGroupStore.setDelegate(checkGroupModFailureDelegate);
+        simpleGroupStore.groupOperationFailed(D1, groupModOp);
+
+        // Testing Group modify operation failure
+        simpleGroupStore.unsetDelegate(checkGroupModFailureDelegate);
+        GroupOperation groupDelOp = GroupOperation.
+                createDeleteGroupOperation(createdGroup.id(),
+                        createdGroup.type());
+        InternalGroupStoreDelegate checkGroupDelFailureDelegate =
+                new InternalGroupStoreDelegate(key,
+                        groupBuckets,
+                        GroupEvent.Type.GROUP_REMOVE_FAILED);
+        simpleGroupStore.setDelegate(checkGroupDelFailureDelegate);
+        simpleGroupStore.groupOperationFailed(D1, groupDelOp);
+
+
     }
 }