VOL-3112 Group removal support by Open OLT Adapter

Change-Id: I2a21741faa2631aca5e727f73b42aa04018a2059
diff --git a/internal/pkg/core/device_handler.go b/internal/pkg/core/device_handler.go
index 2463482..9a00608 100644
--- a/internal/pkg/core/device_handler.go
+++ b/internal/pkg/core/device_handler.go
@@ -1441,8 +1441,11 @@
 				errorsList = append(errorsList, err)
 			}
 		}
-		if len(groups.ToRemove.Items) != 0 {
-			logger.Debugw(ctx, "group-delete-operation-not-supported", log.Fields{"device-id": dh.device.Id})
+		for _, group := range groups.ToRemove.Items {
+			err := dh.flowMgr.DeleteGroup(ctx, group)
+			if err != nil {
+				errorsList = append(errorsList, err)
+			}
 		}
 	}
 	if len(errorsList) > 0 {
diff --git a/internal/pkg/core/openolt_flowmgr.go b/internal/pkg/core/openolt_flowmgr.go
index 28d2065..520ee7a 100644
--- a/internal/pkg/core/openolt_flowmgr.go
+++ b/internal/pkg/core/openolt_flowmgr.go
@@ -2672,6 +2672,32 @@
 	return nil
 }
 
+// DeleteGroup deletes a group from the device
+func (f *OpenOltFlowMgr) DeleteGroup(ctx context.Context, group *ofp.OfpGroupEntry) error {
+	logger.Debugw(ctx, "delete-group", log.Fields{"group": group})
+	if group == nil {
+		logger.Error(ctx, "unable-to-delete-group--invalid-argument--group-is-nil")
+		return olterrors.NewErrInvalidValue(log.Fields{"group": group}, nil)
+	}
+
+	groupToOlt := openoltpb2.Group{
+		GroupId: group.Desc.GroupId,
+	}
+
+	logger.Debugw(ctx, "deleting-group-from-device", log.Fields{"groupToOlt": groupToOlt})
+	_, err := f.deviceHandler.Client.DeleteGroup(ctx, &groupToOlt)
+	if err != nil {
+		logger.Errorw(ctx, "delete-group-failed-on-dev", log.Fields{"groupToOlt": groupToOlt, "err": err})
+		return olterrors.NewErrAdapter("delete-group-operation-failed", log.Fields{"groupToOlt": groupToOlt}, err)
+	}
+	//remove group from the store
+	if err := f.resourceMgr.RemoveFlowGroupFromKVStore(ctx, group.Desc.GroupId, false); err != nil {
+		return olterrors.NewErrPersistence("delete", "flow-group", group.Desc.GroupId, log.Fields{"group": group}, err)
+	}
+	logger.Debugw(ctx, "delete-group-operation-performed-on-the-device-successfully ", log.Fields{"groupToOlt": groupToOlt})
+	return nil
+}
+
 //buildGroupAction creates and returns a group action
 func (f *OpenOltFlowMgr) buildGroupAction() *openoltpb2.Action {
 	var actionCmd openoltpb2.ActionCmd
diff --git a/internal/pkg/core/openolt_flowmgr_test.go b/internal/pkg/core/openolt_flowmgr_test.go
index 1faa8c0..15e0244 100644
--- a/internal/pkg/core/openolt_flowmgr_test.go
+++ b/internal/pkg/core/openolt_flowmgr_test.go
@@ -1087,17 +1087,20 @@
 	}
 }
 
-func TestOpenOltFlowMgr_TestMulticastFlow(t *testing.T) {
+func TestOpenOltFlowMgr_TestMulticastFlowAndGroup(t *testing.T) {
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 	defer cancel()
 	//create group
 	group := newGroup(2, []uint32{1})
-	flowMgr.AddGroup(ctx, group)
-
+	err := flowMgr.AddGroup(ctx, group)
+	if err != nil {
+		t.Error("group-add failed", err)
+		return
+	}
 	//create multicast flow
 	multicastFlowArgs := &fu.FlowArgs{
 		MatchFields: []*ofp.OfpOxmOfbField{
-			fu.InPort(65536),
+			fu.InPort(1048576),
 			fu.VlanVid(660),             //vlan
 			fu.Metadata_ofp(uint64(66)), //inner vlan
 			fu.EthType(0x800),           //ipv4
@@ -1108,10 +1111,31 @@
 		},
 	}
 	ofpStats, _ := fu.MkFlowStat(multicastFlowArgs)
-	flowMgr.AddFlow(ctx, ofpStats, &voltha.FlowMetadata{})
+	fmt.Println(ofpStats.Id)
+	err = flowMgr.AddFlow(ctx, ofpStats, &voltha.FlowMetadata{})
+	if err != nil {
+		t.Error("Multicast flow-add failed", err)
+		return
+	}
 
 	//add bucket to the group
 	group = newGroup(2, []uint32{1, 2})
+	err = flowMgr.ModifyGroup(ctx, group)
+	if err != nil {
+		t.Error("modify-group failed", err)
+		return
+	}
+	//remove the multicast flow
+	err = flowMgr.RemoveFlow(ctx, ofpStats)
+	if err != nil {
+		t.Error("Multicast flow-remove failed", err)
+		return
+	}
 
-	flowMgr.ModifyGroup(ctx, group)
+	//remove the group
+	err = flowMgr.DeleteGroup(ctx, group)
+	if err != nil {
+		t.Error("delete-group failed", err)
+		return
+	}
 }
diff --git a/internal/pkg/resourcemanager/resourcemanager.go b/internal/pkg/resourcemanager/resourcemanager.go
index 3557bbf..42c3d21 100755
--- a/internal/pkg/resourcemanager/resourcemanager.go
+++ b/internal/pkg/resourcemanager/resourcemanager.go
@@ -1484,7 +1484,7 @@
 }
 
 //RemoveFlowGroupFromKVStore removes flow group from KV store
-func (RsrcMgr *OpenOltResourceMgr) RemoveFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) bool {
+func (RsrcMgr *OpenOltResourceMgr) RemoveFlowGroupFromKVStore(ctx context.Context, groupID uint32, cached bool) error {
 	var path string
 	if cached {
 		path = fmt.Sprintf(FlowGroupCached, groupID)
@@ -1493,9 +1493,9 @@
 	}
 	if err := RsrcMgr.KVStore.Delete(ctx, path); err != nil {
 		logger.Errorf(ctx, "Failed to remove resource %s due to %s", path, err)
-		return false
+		return err
 	}
-	return true
+	return nil
 }
 
 //GetFlowGroupFromKVStore fetches flow group from the KV store. Returns (false, {} error) if any problem occurs during
diff --git a/internal/pkg/resourcemanager/resourcemanager_test.go b/internal/pkg/resourcemanager/resourcemanager_test.go
index 817825d..73b74df 100644
--- a/internal/pkg/resourcemanager/resourcemanager_test.go
+++ b/internal/pkg/resourcemanager/resourcemanager_test.go
@@ -1160,8 +1160,8 @@
 			RsrcMgr := testResMgrObject(tt.fields)
 			ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 			defer cancel()
-			success := RsrcMgr.RemoveFlowGroupFromKVStore(ctx, tt.args.groupID, tt.args.cached)
-			if !success {
+			err := RsrcMgr.RemoveFlowGroupFromKVStore(ctx, tt.args.groupID, tt.args.cached)
+			if err != nil {
 				t.Errorf("%s got false but wants true", tt.name)
 				return
 			}
diff --git a/pkg/mocks/mockKVClient.go b/pkg/mocks/mockKVClient.go
index 5e13d1d..fe6310b 100644
--- a/pkg/mocks/mockKVClient.go
+++ b/pkg/mocks/mockKVClient.go
@@ -131,6 +131,20 @@
 			str, _ := json.Marshal(data)
 			return kvstore.NewKVPair(key, str, "mock", 3000, 1), nil
 		}
+		if strings.Contains(key, "/{olt}/{0,-1,-1}/flow_id_info/") {
+			//multicast flow
+			data := []resourcemanager.FlowInfo{
+				{
+					Flow:            &openolt.Flow{FlowId: 1, OnuId: 0, UniId: 0, GemportId: 4000},
+					FlowStoreCookie: uint64(48132224281636694),
+					LogicalFlowID:   3961977515762683568,
+				},
+			}
+			logger.Debug(ctx, "Error Error Error Key:", FlowIDs)
+			str, _ := json.Marshal(data)
+			return kvstore.NewKVPair(key, str, "mock", 3000, 1), nil
+		}
+
 		if strings.Contains(key, FlowIDInfo) {
 
 			data := []resourcemanager.FlowInfo{