[VOL-3107] Add DeleteGroup API to OpenOLT Agent

- DeleteGroup proto API method implemented.
- Unit tests added.

Change-Id: If196a92f7a717fc4cc6c2f0e0bb6ca74fc3683d2
diff --git a/agent/Makefile.in b/agent/Makefile.in
index 9de5071..c2587d8 100644
--- a/agent/Makefile.in
+++ b/agent/Makefile.in
@@ -42,7 +42,7 @@
 # This specifies the GIT tag in https://github.com/opencord/voltha-protos
 # repo that we need to refer to, to pick the right version of
 # openolt.proto and tech_profile.proto
-OPENOLT_PROTO_VER ?= v3.3.6
+OPENOLT_PROTO_VER ?= v3.3.9
 
 # Variables used for Inband build
 INBAND = "n"
diff --git a/agent/common/core.h b/agent/common/core.h
index f4a440e..c68fdf3 100644
--- a/agent/common/core.h
+++ b/agent/common/core.h
@@ -229,6 +229,7 @@
 Status CreateTrafficQueues_(const tech_profile::TrafficQueues *traffic_queues);
 Status RemoveTrafficQueues_(const tech_profile::TrafficQueues *traffic_queues);
 Status PerformGroupOperation_(const openolt::Group *group_cfg);
+Status DeleteGroup_(uint32_t group_id);
 Status OnuItuPonAlarmSet_(const openolt::OnuItuPonAlarm* request);
 uint32_t GetPortNum_(uint32_t flow_id);
 int get_status_bcm_cli_quit(void);
diff --git a/agent/common/server.cc b/agent/common/server.cc
index 17b804e..baeb590 100644
--- a/agent/common/server.cc
+++ b/agent/common/server.cc
@@ -309,6 +309,13 @@
         return PerformGroupOperation_(request);
     };
 
+    Status DeleteGroup(
+            ServerContext* context,
+            const openolt::Group* request,
+            openolt::Empty* response) override {
+        return DeleteGroup_(request->group_id());
+    };
+
     Status OnuItuPonAlarmSet(
             ServerContext* context,
             const openolt::OnuItuPonAlarm* request,
diff --git a/agent/src/core_api_handler.cc b/agent/src/core_api_handler.cc
index 3267c6c..9a22497 100644
--- a/agent/src/core_api_handler.cc
+++ b/agent/src/core_api_handler.cc
@@ -2823,3 +2823,49 @@
 
     return Status::OK;
 }
+
+Status DeleteGroup_(uint32_t group_id) {
+
+    bcmos_errno err = BCM_ERR_OK;
+    bcmolt_group_cfg grp_cfg_obj;
+    bcmolt_group_key key = {};
+
+
+    OPENOLT_LOG(INFO, openolt_log_id, "Delete request received for group %d\n", group_id);
+
+    if (group_id >= 0) {
+        key.id = group_id;
+    } else {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Invalid group id %d.\n", group_id);
+        return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Invalid group id");
+    }
+
+    /* init the BAL INIT API */
+    BCMOLT_CFG_INIT(&grp_cfg_obj, group, key);
+
+    OPENOLT_LOG(DEBUG, openolt_log_id, "Checking if group %d exists...\n",group_id);
+
+    // CONFIGURE GROUP MEMBERS
+    BCMOLT_FIELD_SET_PRESENT(&grp_cfg_obj.data, group_cfg_data, state);
+    err = bcmolt_cfg_get(dev_id, &(grp_cfg_obj.hdr));
+
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Error in querying Group %d, err = %s\n", group_id, bcmos_strerror(err));
+        return bcm_to_grpc_err(err, "Error in querying group");
+    }
+
+    if (grp_cfg_obj.data.state != BCMOLT_GROUP_STATE_NOT_CONFIGURED) {
+        OPENOLT_LOG(DEBUG, openolt_log_id, "Group %d exists. Will be deleted.\n",group_id);
+        err = bcmolt_cfg_clear(dev_id, &(grp_cfg_obj.hdr));
+        if (err != BCM_ERR_OK) {
+            OPENOLT_LOG(ERROR, openolt_log_id, "Group %d cannot be deleted err = %s (%d).\n", group_id, bcmos_strerror(err), err);
+            return bcm_to_grpc_err(err, "Failed to delete group");;
+        }
+    } else {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Group %d does not exist.\n", group_id);
+        return Status(grpc::StatusCode::NOT_FOUND, "Group not found");
+    }
+
+    OPENOLT_LOG(INFO, openolt_log_id, "Group %d has been deleted successfully.\n", group_id);
+    return Status::OK;
+}
\ No newline at end of file
diff --git a/agent/test/Makefile b/agent/test/Makefile
index 1693af0..4f86165 100644
--- a/agent/test/Makefile
+++ b/agent/test/Makefile
@@ -21,7 +21,7 @@
 TOP_DIR=`pwd`
 OPENOLTDEVICE ?= asfvolt16
 
-OPENOLT_PROTO_VER ?= v3.3.6
+OPENOLT_PROTO_VER ?= v3.3.9
 
 GTEST_VER ?= release-1.8.0
 gtest-target = /usr/local/lib/libgtest.a
diff --git a/agent/test/src/test_core.cc b/agent/test/src/test_core.cc
index 698b894..db957e3 100644
--- a/agent/test/src/test_core.cc
+++ b/agent/test/src/test_core.cc
@@ -2809,3 +2809,88 @@
     Status status = OnuItuPonAlarmSet_(onu_itu_pon_alarm_tc);
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
+
+////////////////////////////////////////////////////////////////////////////
+// For testing DeleteGroup functionality
+////////////////////////////////////////////////////////////////////////////
+
+class TestDeleteGroup : public Test {
+    protected:
+        uint32_t group_id = 1;
+        NiceMock<BalMocker> balMock;
+
+        virtual void SetUp() {
+        }
+
+        virtual void TearDown() {
+        }
+};
+
+// Test 1 - DeleteGroup success case
+TEST_F(TestDeleteGroup, DeleteGroupSuccess) {
+    bcmos_errno group_cfg_get_res = BCM_ERR_OK;
+    bcmos_errno group_cfg_clear_res = BCM_ERR_OK;
+    bcmolt_group_cfg grp_cfg_out;
+    bcmolt_group_key grp_key = {};
+
+    grp_key.id = group_id;
+    BCMOLT_CFG_INIT(&grp_cfg_out, group, grp_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([group_cfg_get_res, &grp_cfg_out] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                     bcmolt_group_cfg* grp_cfg = (bcmolt_group_cfg*)cfg;
+                     grp_cfg->data.state = BCMOLT_GROUP_STATE_CONFIGURED;
+                     memcpy(&grp_cfg_out, grp_cfg, sizeof(bcmolt_group_cfg));
+                     return group_cfg_get_res;
+                 }
+    ));
+
+    EXPECT_CALL(balMock, bcmolt_cfg_clear(_, _)).WillOnce(Return(group_cfg_clear_res));
+
+    Status status = DeleteGroup_(group_id);
+    ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
+}
+
+// Test 2 - DeleteGroup failure case: Group does not exist
+TEST_F(TestDeleteGroup, DeleteGroupFailure_NotFound) {
+    bcmos_errno group_cfg_get_res = BCM_ERR_OK;
+    bcmolt_group_cfg grp_cfg_out;
+    bcmolt_group_key grp_key = {};
+
+    grp_key.id = group_id;
+    BCMOLT_CFG_INIT(&grp_cfg_out, group, grp_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([group_cfg_get_res, &grp_cfg_out] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                                                                   bcmolt_group_cfg* grp_cfg = (bcmolt_group_cfg*)cfg;
+                                                                   grp_cfg->data.state = BCMOLT_GROUP_STATE_NOT_CONFIGURED;
+                                                                   memcpy(&grp_cfg_out, grp_cfg, sizeof(bcmolt_group_cfg));
+                                                                   return group_cfg_get_res;
+                                                               }
+    ));
+
+    Status status = DeleteGroup_(group_id);
+    ASSERT_TRUE( status.error_code() == grpc::StatusCode::NOT_FOUND );
+}
+
+// Test 3 - DeleteGroup failure case: Group exists but cannot be deleted (due to flow association etc.)
+TEST_F(TestDeleteGroup, DeleteGroupFailure_CannotDelete) {
+    bcmos_errno group_cfg_get_res = BCM_ERR_OK;
+    bcmos_errno group_cfg_clear_res = BCM_ERR_INTERNAL;
+    bcmolt_group_cfg grp_cfg_out;
+    bcmolt_group_key grp_key = {};
+
+    grp_key.id = group_id;
+    BCMOLT_CFG_INIT(&grp_cfg_out, group, grp_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([group_cfg_get_res, &grp_cfg_out] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                                                                   bcmolt_group_cfg* grp_cfg = (bcmolt_group_cfg*)cfg;
+                                                                   grp_cfg->data.state = BCMOLT_GROUP_STATE_CONFIGURED;
+                                                                   memcpy(&grp_cfg_out, grp_cfg, sizeof(bcmolt_group_cfg));
+                                                                   return group_cfg_get_res;
+                                                               }
+    ));
+
+    EXPECT_CALL(balMock, bcmolt_cfg_clear(_, _)).WillOnce(Return(group_cfg_clear_res));
+
+    Status status = DeleteGroup_(group_id);
+    ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
+}