Commit support Device Management- Self Test on Device
https://jira.opencord.org/browse/VOL-27
Addressed review comments
Change-Id: I9f70e476b28ee40f90b312744a4c44fc8e7f7481
diff --git a/cli/main.py b/cli/main.py
index 0adee54..327f122 100755
--- a/cli/main.py
+++ b/cli/main.py
@@ -324,6 +324,20 @@
         except Exception, e:
             self.poutput('Error rebooting {}.  Error:{}'.format(device_id, e))
 
+    def do_self_test(self, line):
+        """
+        Self Test a device. ID of the device needs to be provided
+        """
+        device_id = line or self.default_device_id
+        self.poutput('Self Testing {}'.format(device_id))
+        try:
+            stub = voltha_pb2.VolthaLocalServiceStub(self.get_channel())
+            res = stub.SelfTest(voltha_pb2.ID(id=device_id))
+            self.poutput('Self Tested {}'.format(device_id))
+            self.poutput(dumps(pb2dict(res), indent=4))
+        except Exception, e:
+            self.poutput('Error in self test {}.  Error:{}'.format(device_id, e))
+
     def do_delete(self, line):
         """
         Deleting a device. ID of the device needs to be provided
diff --git a/voltha/adapters/adtran_olt/adtran_olt.py b/voltha/adapters/adtran_olt/adtran_olt.py
index 2567aa1..3f23288 100644
--- a/voltha/adapters/adtran_olt/adtran_olt.py
+++ b/voltha/adapters/adtran_olt/adtran_olt.py
@@ -200,6 +200,15 @@
         log.info('reboot_device', device=device)
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         """
         This is called to delete a device from the PON based on a NBI call.
diff --git a/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py b/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
index 94ce1c3..3569d36 100644
--- a/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
+++ b/voltha/adapters/asfvolt16_olt/asfvolt16_olt.py
@@ -34,3 +34,64 @@
                                                version='0.1')
         # register for adapter messages
         self.adapter_agent.register_for_inter_adapter_messages()
+<<<<<<< 29dd1987b0e63d3ba500b8cb92aafd0b0a1b13c9
+=======
+
+class Asfvolt16Handler(object):
+    def __init__(self, adapter, device_id):
+        raise NotImplementedError()
+
+    def __del__(self):
+        raise NotImplementedError()
+
+    def get_channel(self):
+        raise NotImplementedError()
+
+    def _get_nni_port(self):
+        raise NotImplementedError()
+
+    def activate(self, device):
+        raise NotImplementedError()
+
+    def reconcile(self, device):
+        raise NotImplementedError()
+
+    def rcv_io(self, port, frame):
+        raise NotImplementedError()
+
+    def update_flow_table(self, flows):
+        raise NotImplementedError()
+
+    def update_pm_config(self, device, pm_config):
+        raise NotImplementedError()
+
+    def send_proxied_message(self, proxy_address, msg):
+        raise NotImplementedError()
+
+    def packet_out(self, egress_port, msg):
+        raise NotImplementedError()
+
+    def self_test_req(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-req', device=device.id)
+        raise NotImplementedError()
+
+    def reboot(self):
+        raise NotImplementedError()
+
+    def disable(self):
+        raise NotImplementedError()
+
+    def reenable(self):
+        raise NotImplementedError()
+
+    def delete(self):
+        raise NotImplementedError()
+
+    def start_kpi_collection(self, device_id):
+        raise NotImplementedError()
+>>>>>>> Commit support Device Management- Self Test on Device
diff --git a/voltha/adapters/broadcom_onu/broadcom_onu.py b/voltha/adapters/broadcom_onu/broadcom_onu.py
index 5531978..f852220 100644
--- a/voltha/adapters/broadcom_onu/broadcom_onu.py
+++ b/voltha/adapters/broadcom_onu/broadcom_onu.py
@@ -112,6 +112,15 @@
     def reboot_device(self, device):
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/dpoe_onu/dpoe_onu.py b/voltha/adapters/dpoe_onu/dpoe_onu.py
index 94bceb5..9fd1a9f 100644
--- a/voltha/adapters/dpoe_onu/dpoe_onu.py
+++ b/voltha/adapters/dpoe_onu/dpoe_onu.py
@@ -217,6 +217,15 @@
     def reboot_device(self, device):
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/iadapter.py b/voltha/adapters/iadapter.py
index b0b1aaa..a85913b 100644
--- a/voltha/adapters/iadapter.py
+++ b/voltha/adapters/iadapter.py
@@ -99,6 +99,11 @@
         reactor.callLater(0, self.devices_handlers[device.id].reboot)
         return device
 
+    def self_test_device(self, device):
+        log.info('self-test-req', device_id=device.id)
+        result = reactor.callLater(0, self.devices_handlers[device.id].self_test_device)
+        return result
+
     def delete_device(self, device):
         log.info('delete-device', device_id=device.id)
         #  TODO: Update the logical device mapping
diff --git a/voltha/adapters/interface.py b/voltha/adapters/interface.py
index 1b6881f..1158a4d 100644
--- a/voltha/adapters/interface.py
+++ b/voltha/adapters/interface.py
@@ -127,6 +127,13 @@
         :return: (Deferred) Shall be fired to acknowledge the reboot.
         """
 
+    def self_test_device(device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+
     def delete_device(device):
         """
         This is called to delete a device from the PON based on a NBI call.
diff --git a/voltha/adapters/maple_olt/maple_olt.py b/voltha/adapters/maple_olt/maple_olt.py
index 85430b0..a690985 100644
--- a/voltha/adapters/maple_olt/maple_olt.py
+++ b/voltha/adapters/maple_olt/maple_olt.py
@@ -445,6 +445,15 @@
     def reboot_device(self, device):
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/microsemi_olt/microsemi_olt.py b/voltha/adapters/microsemi_olt/microsemi_olt.py
index 03783fb..b50bbeb 100644
--- a/voltha/adapters/microsemi_olt/microsemi_olt.py
+++ b/voltha/adapters/microsemi_olt/microsemi_olt.py
@@ -123,6 +123,15 @@
     def reboot_device(self, device):
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/pmcs_onu/pmcs_onu.py b/voltha/adapters/pmcs_onu/pmcs_onu.py
index c1c8437..fb27220 100644
--- a/voltha/adapters/pmcs_onu/pmcs_onu.py
+++ b/voltha/adapters/pmcs_onu/pmcs_onu.py
@@ -114,6 +114,15 @@
     def reboot_device(self, device):
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         raise NotImplementedError()
 
diff --git a/voltha/adapters/ponsim_olt/ponsim_olt.py b/voltha/adapters/ponsim_olt/ponsim_olt.py
index 7fffac8..6111eb1 100644
--- a/voltha/adapters/ponsim_olt/ponsim_olt.py
+++ b/voltha/adapters/ponsim_olt/ponsim_olt.py
@@ -492,6 +492,15 @@
 
         self.log.info('rebooted', device_id=self.device_id)
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def disable(self):
         self.log.info('disabling', device_id=self.device_id)
 
diff --git a/voltha/adapters/ponsim_onu/ponsim_onu.py b/voltha/adapters/ponsim_onu/ponsim_onu.py
index 79aea55..f34d6ed 100644
--- a/voltha/adapters/ponsim_onu/ponsim_onu.py
+++ b/voltha/adapters/ponsim_onu/ponsim_onu.py
@@ -215,6 +215,15 @@
         self.adapter_agent.update_device(device)
         self.log.info('rebooted', device_id=self.device_id)
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def disable(self):
         self.log.info('disabling', device_id=self.device_id)
 
diff --git a/voltha/adapters/simulated_olt/simulated_olt.py b/voltha/adapters/simulated_olt/simulated_olt.py
index d5f206e..4de3f0f 100644
--- a/voltha/adapters/simulated_olt/simulated_olt.py
+++ b/voltha/adapters/simulated_olt/simulated_olt.py
@@ -22,6 +22,7 @@
 import arrow
 import structlog
 import datetime
+import random
 from klein import Klein
 from scapy.layers.l2 import Ether, EAPOL, Padding
 from twisted.internet import endpoints
@@ -38,6 +39,7 @@
 from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
 from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Device, Port, \
 PmConfigs, PmConfig, PmGroupConfig, Image
+from voltha.protos.voltha_pb2 import SelfTestResponse
 from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
 from voltha.protos.health_pb2 import HealthStatus
 from voltha.protos.common_pb2 import LogLevel, OperStatus, ConnectStatus, \
@@ -241,7 +243,14 @@
         log.info("adapter-update-pm-config", device=device, pm_config=pm_config)
         self.pm_metrics.update(pm_config)
 
-
+    def self_test_device(self, device):
+        log.info("run-self-test-on-device", device=device.id)
+        result = SelfTestResponse(result = random.choice([
+            SelfTestResponse.SUCCESS,
+            SelfTestResponse.FAILURE,
+            SelfTestResponse.NOT_SUPPORTED,
+            SelfTestResponse.UNKNOWN_ERROR]))
+        return result
 
     def _tmp_populate_stuff(self):
         """
diff --git a/voltha/adapters/simulated_onu/simulated_onu.py b/voltha/adapters/simulated_onu/simulated_onu.py
index 4509852..9fc9288 100644
--- a/voltha/adapters/simulated_onu/simulated_onu.py
+++ b/voltha/adapters/simulated_onu/simulated_onu.py
@@ -21,6 +21,7 @@
 
 import structlog
 import datetime
+import random
 from twisted.internet import reactor
 from twisted.internet.defer import inlineCallbacks, DeferredQueue
 from zope.interface import implementer
@@ -33,6 +34,7 @@
 from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Device, Port, \
      Image
 from voltha.protos.health_pb2 import HealthStatus
+from voltha.protos.voltha_pb2 import SelfTestResponse
 from voltha.protos.common_pb2 import LogLevel, OperStatus, ConnectStatus, \
     AdminState
 from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
@@ -116,6 +118,15 @@
     def update_pm_config(self, device, pm_configs):
         raise NotImplementedError()
 
+    def self_test_device(self, device):
+        log.info("run-self-test-on-device", device=device.id)
+        result = SelfTestResponse(result = random.choice([
+            SelfTestResponse.SUCCESS,
+            SelfTestResponse.FAILURE,
+            SelfTestResponse.NOT_SUPPORTED,
+            SelfTestResponse.UNKNOWN_ERROR]))
+        return result
+
     @inlineCallbacks
     def _simulate_device_activation(self, device):
 
diff --git a/voltha/adapters/tibit_olt/tibit_olt.py b/voltha/adapters/tibit_olt/tibit_olt.py
index c9e9e4e..4bf40c9 100644
--- a/voltha/adapters/tibit_olt/tibit_olt.py
+++ b/voltha/adapters/tibit_olt/tibit_olt.py
@@ -778,6 +778,14 @@
                                                       connect_status=ConnectStatus.REACHABLE)
         log.info('OLT Rebooted: {}'.format(device.mac_address))
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
 
     def delete_device(self, device):
         raise NotImplementedError()
diff --git a/voltha/adapters/tibit_onu/tibit_onu.py b/voltha/adapters/tibit_onu/tibit_onu.py
index 62148e1..7ee421f 100644
--- a/voltha/adapters/tibit_onu/tibit_onu.py
+++ b/voltha/adapters/tibit_onu/tibit_onu.py
@@ -276,6 +276,15 @@
 
         log.info('ONU Rebooted: {}'.format(device.mac_address))
 
+    def self_test_device(self, device):
+        """
+        This is called to Self a device based on a NBI call.
+        :param device: A Voltha.Device object.
+        :return: Will return result of self test
+        """
+        log.info('self-test-device', device=device.id)
+        raise NotImplementedError()
+
     def delete_device(self, device):
         raise NotImplementedError()
 
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index c6e2191..dff4695 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -168,6 +168,9 @@
     def reboot_device(self, device):
         return self.adapter.reboot_device(device)
 
+    def self_test(self, device):
+        return self.adapter.self_test_device(device)
+
     def delete_device(self, device):
         return self.adapter.delete_device(device)
 
diff --git a/voltha/core/device_agent.py b/voltha/core/device_agent.py
index 9f7c8cf..479ec6f 100644
--- a/voltha/core/device_agent.py
+++ b/voltha/core/device_agent.py
@@ -98,7 +98,6 @@
             CallbackType.POST_UPDATE, self._process_update)
         self.log.info('stopped')
 
-
     @inlineCallbacks
     def reboot_device(self, device, dry_run=False):
         self.log.debug('reboot-device', device=device, dry_run=dry_run)
@@ -106,6 +105,13 @@
             yield self.adapter_agent.reboot_device(device)
 
     @inlineCallbacks
+    def self_test(self, device, dry_run=False):
+        self.log.debug('self-test-device', device=device, dry_run=dry_run)
+        if not dry_run:
+            result = yield self.adapter_agent.self_test(device)
+            returnValue(result)
+
+    @inlineCallbacks
     def get_device_details(self, device, dry_run=False):
         self.log.debug('get-device-details', device=device, dry_run=dry_run)
         if not dry_run:
diff --git a/voltha/core/global_handler.py b/voltha/core/global_handler.py
index 63e2c60..6979de3 100644
--- a/voltha/core/global_handler.py
+++ b/voltha/core/global_handler.py
@@ -23,7 +23,7 @@
 from voltha.protos.voltha_pb2 import \
     add_VolthaGlobalServiceServicer_to_server, VolthaLocalServiceStub, \
     VolthaGlobalServiceServicer, Voltha, VolthaInstances, VolthaInstance, \
-    LogicalDevice, Ports, Flows, FlowGroups, Device
+    LogicalDevice, Ports, Flows, FlowGroups, Device, SelfTestResponse
 from voltha.registry import registry
 from google.protobuf.empty_pb2 import Empty
 
@@ -576,3 +576,24 @@
             'GetImages',
             request,
             context)
+
+    @twisted_async
+    def SelfTest(self, request, context):
+        log.info('grpc-request', request=request)
+
+        try:
+            instance_id = self.dispatcher.instance_id_by_device_id(
+                request.id
+            )
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not found'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return SelfTestResponse()
+
+        return self.dispatcher.dispatch(
+            instance_id,
+            VolthaLocalServiceStub,
+            'SelfTest',
+            request,
+            context)
diff --git a/voltha/core/local_handler.py b/voltha/core/local_handler.py
index 60a519f..63efcef 100644
--- a/voltha/core/local_handler.py
+++ b/voltha/core/local_handler.py
@@ -29,7 +29,7 @@
     VolthaInstance, Adapters, LogicalDevices, LogicalDevice, Ports, \
     LogicalPorts, Devices, Device, DeviceType, \
     DeviceTypes, DeviceGroups, DeviceGroup, AdminState, OperStatus, ChangeEvent, \
-    AlarmFilter, AlarmFilters
+    AlarmFilter, AlarmFilters, SelfTestResponse
 from voltha.protos.device_pb2 import PmConfigs, Images
 from voltha.registry import registry
 
@@ -708,3 +708,27 @@
                 'Device \'{}\' not found'.format(request.id))
             context.set_code(StatusCode.NOT_FOUND)
             return Images()
+
+    @twisted_async
+    def SelfTest(self, request, context):
+        log.info('grpc-request', request=request)
+
+        if '/' in request.id:
+            context.set_details(
+                'Malformed device id \'{}\''.format(request.id))
+            context.set_code(StatusCode.INVALID_ARGUMENT)
+            return SelfTestResponse()
+
+        try:
+            path = '/devices/{}'.format(request.id)
+            device = self.root.get(path)
+
+            agent = self.core.get_device_agent(device.id)
+            resp = agent.self_test(device)
+            return resp.result
+
+        except KeyError:
+            context.set_details(
+                'Device \'{}\' not found'.format(request.id))
+            context.set_code(StatusCode.NOT_FOUND)
+            return SelfTestResponse()
diff --git a/voltha/protos/voltha.proto b/voltha/protos/voltha.proto
index 3315d94..1500bf1 100644
--- a/voltha/protos/voltha.proto
+++ b/voltha/protos/voltha.proto
@@ -117,6 +117,18 @@
 
 }
 
+// Device Self Test Response
+message SelfTestResponse {
+    option (yang_child_rule) = MOVE_TO_PARENT_LEVEL;
+
+	enum SelfTestResult  {
+	    SUCCESS = 0;
+	    FAILURE = 1;
+	    NOT_SUPPORTED = 2;
+	    UNKNOWN_ERROR = 3;
+    }
+    SelfTestResult result = 1;
+}
 
 /*
  * Cluster-wide Voltha APIs
@@ -370,6 +382,12 @@
             get: "/api/v1/devices/{id}/images"
         };
     }
+
+    rpc SelfTest(ID) returns(SelfTestResponse) {
+        option (google.api.http) = {
+            post: "/api/v1/devices/{id}/self_test"
+        };
+    }
 }
 
 /*
@@ -640,4 +658,10 @@
             get: "/api/v1/local/devices/{id}/images"
         };
     }
+
+    rpc SelfTest(ID) returns(SelfTestResponse) {
+        option (google.api.http) = {
+            post: "/api/v1/local/devices/{id}/self_test"
+        };
+    }
 }