VOL-4053: Fix Reenable of OLT following disable OLT and adapter restart.

- If the PON port is already disabled (could happen if a duplicate
  disable command arrives at OLT), return success
- Add unit test cases

Change-Id: I7e35ff81eb80d47743ab94e35655306fc313884d
diff --git a/agent/src/core_api_handler.cc b/agent/src/core_api_handler.cc
index a987540..a4e902f 100644
--- a/agent/src/core_api_handler.cc
+++ b/agent/src/core_api_handler.cc
@@ -427,6 +427,7 @@
 
     Status status;
     int failedCount = 0;
+    OPENOLT_LOG(INFO, openolt_log_id, "Received disable OLT\n");
     for (int i = 0; i < NumPonIf_(); i++) {
         status = DisablePonIf_(i);
         if (!status.ok()) {
@@ -1057,6 +1058,19 @@
     bcmolt_pon_interface_set_pon_interface_state pon_interface_set_state;
 
     BCMOLT_CFG_INIT(&interface_obj, pon_interface, intf_key);
+    BCMOLT_MSG_FIELD_GET(&interface_obj, state);
+
+    err = bcmolt_cfg_get(dev_id, &interface_obj.hdr);
+    if (err != BCM_ERR_OK) {
+        OPENOLT_LOG(ERROR, openolt_log_id, "Failed to fetch pon port status, PON interface %d, err %d err_text=%s \n", intf_id, err, interface_obj.hdr.hdr.err_text);
+        return bcm_to_grpc_err(err, "Failed to fetch pon port state");
+    }
+    if (interface_obj.data.state == BCMOLT_INTERFACE_STATE_INACTIVE) {
+        OPENOLT_LOG(INFO, openolt_log_id, "PON Interface already inactive, PON interface %d\n", intf_id);
+        return Status::OK;
+    }
+
+    BCMOLT_CFG_INIT(&interface_obj, pon_interface, intf_key);
     BCMOLT_OPER_INIT(&pon_interface_set_state, pon_interface, set_pon_interface_state, intf_key);
     BCMOLT_MSG_FIELD_SET(&interface_obj, discovery.control, BCMOLT_CONTROL_STATE_DISABLE);
 
diff --git a/agent/test/src/test_core.cc b/agent/test/src/test_core.cc
index 7f8a4df..bce275e 100644
--- a/agent/test/src/test_core.cc
+++ b/agent/test/src/test_core.cc
@@ -265,10 +265,12 @@
     // This is described in https://github.com/arangodb-helper/gtest/blob/master/googlemock/docs/CookBook.md
     NiceMock<BalMocker> balMock;
     bcmos_errno olt_oper_res = BCM_ERR_OK;
+    bcmos_errno olt_get_res = BCM_ERR_OK;
 
     Status olt_disable_res;
     state.deactivate();
     ON_CALL(balMock, bcmolt_oper_submit(_, _)).WillByDefault(Return(olt_oper_res));
+    ON_CALL(balMock, bcmolt_cfg_get(_, _)).WillByDefault(Return(olt_get_res));
     olt_disable_res = Disable_();
     ASSERT_TRUE( olt_disable_res.error_message() == Status::OK.error_message() );
 
@@ -280,9 +282,11 @@
     // This is described in https://github.com/arangodb-helper/gtest/blob/master/googlemock/docs/CookBook.md
     NiceMock<BalMocker> balMock;
     bcmos_errno olt_oper_res = BCM_ERR_INTERNAL;
+    bcmos_errno pon_cfg_get_res = BCM_ERR_INTERNAL;
 
     Status olt_disable_res;
     state.deactivate();
+    ON_CALL(balMock, bcmolt_cfg_get(_, _)).WillByDefault(Return(pon_cfg_get_res));
     ON_CALL(balMock, bcmolt_oper_submit(_, _)).WillByDefault(Return(olt_oper_res));
     olt_disable_res = Disable_();
     ASSERT_TRUE( olt_disable_res.error_code() == grpc::StatusCode::INTERNAL);
@@ -777,14 +781,26 @@
         }
 };
 
-// Test 1 - DisablePonIf success case
+// Test 1 - DisablePonIf success case - PON port in BCMOLT_INTERFACE_STATE_ACTIVE_WORKING state
 TEST_F(TestDisablePonIf, DisablePonIfSuccess) {
     bcmos_errno olt_oper_res = BCM_ERR_OK;
     bcmos_errno bal_cfg_set_res = BCM_ERR_OK;
     NiceMock<BalMocker> balMock;
     uint32_t pon_id=1;
 
-    //ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(bal_cfg_set_res));
+    bcmos_errno pon_intf_get_res = BCM_ERR_OK;
+    bcmolt_pon_interface_cfg interface_obj;
+
+    bcmolt_pon_interface_key intf_key = {.pon_ni = (bcmolt_interface)pon_id};
+    BCMOLT_CFG_INIT(&interface_obj, pon_interface, intf_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([pon_intf_get_res, &interface_obj] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                                                                   bcmolt_pon_interface_cfg* pon_cfg = (bcmolt_pon_interface_cfg*)cfg;
+                                                                   pon_cfg->data.state = BCMOLT_INTERFACE_STATE_ACTIVE_WORKING;
+                                                                   memcpy(&interface_obj, pon_cfg, sizeof(bcmolt_pon_interface_cfg));
+                                                                   return pon_intf_get_res;
+                                                               }
+    ));
     ON_CALL(balMock, bcmolt_oper_submit(_, _)).WillByDefault(Return(olt_oper_res));
     state.deactivate();
     Status status = DisablePonIf_(pon_id);
@@ -792,12 +808,26 @@
     ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
 }
 
-// Test 2 - DisablePonIf Failure case
-TEST_F(TestDisablePonIf, DisablePonIfFailed) {
+// Test 2 - DisablePonIf Failure case - bcmolt_oper_submit returns BCM_ERR_INTERNAL
+TEST_F(TestDisablePonIf, DisablePonIf_OperSubmitErrInternal) {
     bcmos_errno olt_oper_res = BCM_ERR_INTERNAL;
     NiceMock<BalMocker> balMock;
     uint32_t pon_id=1;
 
+    bcmos_errno pon_intf_get_res = BCM_ERR_OK;
+    bcmolt_pon_interface_cfg interface_obj;
+
+    bcmolt_pon_interface_key intf_key = {.pon_ni = (bcmolt_interface)pon_id};
+    BCMOLT_CFG_INIT(&interface_obj, pon_interface, intf_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([pon_intf_get_res, &interface_obj] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                                                                   bcmolt_pon_interface_cfg* pon_cfg = (bcmolt_pon_interface_cfg*)cfg;
+                                                                   pon_cfg->data.state = BCMOLT_INTERFACE_STATE_ACTIVE_WORKING;
+                                                                   memcpy(&interface_obj, pon_cfg, sizeof(bcmolt_pon_interface_cfg));
+                                                                   return pon_intf_get_res;
+                                                               }
+    ));
+
     ON_CALL(balMock, bcmolt_oper_submit(_, _)).WillByDefault(Return(olt_oper_res));
     state.deactivate();
     Status status = DisablePonIf_(pon_id);
@@ -805,11 +835,27 @@
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
 
-// Test 3 - DisablePonIf ONU discovery failure case
-TEST_F(TestDisablePonIf, DisablePonIfOnuDiscoveryFail) {
+// Test 3 - DisablePonIf Failure case - bcmolt_oper_submit returns BCM_ERR_INTERNAL
+TEST_F(TestDisablePonIf, DisablePonIf_CfgSetErrInternal) {
     NiceMock<BalMocker> balMock;
     uint32_t pon_id=1;
     bcmos_errno bal_cfg_set_res= BCM_ERR_INTERNAL;
+
+    bcmos_errno pon_intf_get_res = BCM_ERR_OK;
+    bcmolt_pon_interface_cfg interface_obj;
+
+    bcmolt_pon_interface_key intf_key = {.pon_ni = (bcmolt_interface)pon_id};
+    BCMOLT_CFG_INIT(&interface_obj, pon_interface, intf_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([pon_intf_get_res, &interface_obj] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                                                                   bcmolt_pon_interface_cfg* pon_cfg = (bcmolt_pon_interface_cfg*)cfg;
+                                                                   pon_cfg->data.state = BCMOLT_INTERFACE_STATE_ACTIVE_WORKING;
+                                                                   memcpy(&interface_obj, pon_cfg, sizeof(bcmolt_pon_interface_cfg));
+                                                                   return pon_intf_get_res;
+                                                               }
+    ));
+
+
     ON_CALL(balMock, bcmolt_cfg_set(_, _)).WillByDefault(Return(bal_cfg_set_res));
     state.deactivate();
     Status status = DisablePonIf_(pon_id);
@@ -817,6 +863,32 @@
     ASSERT_TRUE( status.error_message() != Status::OK.error_message() );
 }
 
+// Test 4 - DisablePonIf success case - PON port in BCMOLT_INTERFACE_STATE_INACTIVE state
+TEST_F(TestDisablePonIf, DisablePonIfSuccess_PonIntfInactive) {
+    bcmos_errno olt_oper_res = BCM_ERR_OK;
+    bcmos_errno bal_cfg_set_res = BCM_ERR_OK;
+    NiceMock<BalMocker> balMock;
+    uint32_t pon_id=1;
+
+    bcmos_errno pon_intf_get_res = BCM_ERR_OK;
+    bcmolt_pon_interface_cfg interface_obj;
+
+    bcmolt_pon_interface_key intf_key = {.pon_ni = (bcmolt_interface)pon_id};
+    BCMOLT_CFG_INIT(&interface_obj, pon_interface, intf_key);
+
+    EXPECT_CALL(balMock, bcmolt_cfg_get(_, _)).WillOnce(Invoke([pon_intf_get_res, &interface_obj] (bcmolt_oltid olt, bcmolt_cfg *cfg) {
+                                                                   bcmolt_pon_interface_cfg* pon_cfg = (bcmolt_pon_interface_cfg*)cfg;
+                                                                   pon_cfg->data.state = BCMOLT_INTERFACE_STATE_INACTIVE;
+                                                                   memcpy(&interface_obj, pon_cfg, sizeof(bcmolt_pon_interface_cfg));
+                                                                   return pon_intf_get_res;
+                                                               }
+    ));
+    state.deactivate();
+    Status status = DisablePonIf_(pon_id);
+
+    ASSERT_TRUE( status.error_message() == Status::OK.error_message() );
+}
+
 ////////////////////////////////////////////////////////////////////////////
 // For testing ActivateOnu functionality
 ////////////////////////////////////////////////////////////////////////////