[SEBA-598] Support OLT.mac_address in pull_steps

Change-Id: I464e9f9fd42c83af3f3589b36b7c53be57b99ae7
diff --git a/VERSION b/VERSION
index c043eea..97102b4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.2.1
+2.2.2-dev
diff --git a/xos/synchronizer/pull_steps/pull_olts.py b/xos/synchronizer/pull_steps/pull_olts.py
index 33e89fb..7c2cadf 100644
--- a/xos/synchronizer/pull_steps/pull_olts.py
+++ b/xos/synchronizer/pull_steps/pull_olts.py
@@ -104,15 +104,21 @@
         for olt in olts:
             if olt["type"] == "simulated_olt":
                 [host, port] = ["172.17.0.1", "50060"]
-            else:
+            elif "host_and_port" in olt:
                 [host, port] = olt["host_and_port"].split(":")
+            elif "mac_address" in olt:
+                mac_address = olt["mac_address"]
 
             olt_ports = self.fetch_olt_ports(olt["id"])
 
             try:
-                model = OLTDevice.objects.filter(device_type=olt["type"], host=host, port=port)[0]
+                if "host_and_port" in olt:
+                    model = OLTDevice.objects.filter(device_type=olt["type"], host=host, port=port)[0]
+                    log.debug("[OLT pull step] OLTDevice already exists, updating it", device_type=olt["type"], host=host, port=port)
+                elif "mac_address" in olt:
+                    model = OLTDevice.objects.filter(device_type=olt["type"], mac_address=mac_address)[0]
+                    log.debug("[OLT pull step] OLTDevice already exists, updating it", device_type=olt["type"], mac_address=mac_address)
 
-                log.debug("[OLT pull step] OLTDevice already exists, updating it", device_type=olt["type"], host=host, port=port)
 
                 if model.enacted < model.updated:
                     log.debug("[OLT pull step] Skipping pull on OLTDevice %s as enacted < updated" % model.name, name=model.name, id=model.id, enacted=model.enacted, updated=model.updated)
@@ -130,10 +136,14 @@
                 if olt["type"] == "simulated_olt":
                     model.host = "172.17.0.1"
                     model.port = 50060
-                else:
+                elif "host_and_port" in olt:
                     [host, port] = olt["host_and_port"].split(":")
                     model.host = host
                     model.port = int(port)
+                    log.debug("[OLT pull step] OLTDevice is new, creating it", device_type=olt["type"], host=host, port=port)
+                elif "mac_address" in olt:
+                    model.mac_address = olt["mac_address"]
+                    log.debug("[OLT pull step] OLTDevice is new, creating it", device_type=olt["type"], mac_address=mac_address)
 
                 # there's no name in voltha, so make one up based on the id
                 model.name = "OLT-%s" % olt["id"]
@@ -150,8 +160,6 @@
                 # Initial admin_state
                 model.admin_state = olt["admin_state"]
 
-                log.debug("[OLT pull step] OLTDevice is new, creating it", device_type=olt["type"], host=host, port=port)
-
             # Adding feedback state to the device
             model.device_id = olt["id"]
             model.oper_status = olt["oper_status"]
diff --git a/xos/synchronizer/pull_steps/test_pull_olts.py b/xos/synchronizer/pull_steps/test_pull_olts.py
index 7197f8d..1224646 100644
--- a/xos/synchronizer/pull_steps/test_pull_olts.py
+++ b/xos/synchronizer/pull_steps/test_pull_olts.py
@@ -112,10 +112,10 @@
             self.assertFalse(m.called)
 
     @requests_mock.Mocker()
-    def test_pull(self, m):
+    def test_pull_host_and_port(self, m):
 
         with patch.object(VOLTService.objects, "all") as olt_service_mock, \
-                patch.object(OLTDevice, "save") as mock_olt_save, \
+                patch.object(OLTDevice, "save", autospec=True) as mock_olt_save, \
                 patch.object(PONPort, "save") as mock_pon_save, \
                 patch.object(NNIPort, "save") as mock_nni_save:
             olt_service_mock.return_value = [self.volt_service]
@@ -126,19 +126,77 @@
 
             self.sync_step(model_accessor=self.model_accessor).pull_records()
 
-            # TODO how to asster this?
-            # self.assertEqual(existing_olt.admin_state, "ENABLED")
-            # self.assertEqual(existing_olt.oper_status, "ACTIVE")
-            # self.assertEqual(existing_olt.volt_service_id, "volt_service_id")
-            # self.assertEqual(existing_olt.device_id, "test_id")
-            # self.assertEqual(existing_olt.of_id, "of_id")
-            # self.assertEqual(existing_olt.dp_id, "of:0000000ce2314000")
 
-            mock_olt_save.assert_called()
+            saved_olts = mock_olt_save.call_args_list
+            simulated_olt = saved_olts[0][0][0]
+            self.assertEqual(len(saved_olts), 1)
+
+            self.assertEqual(simulated_olt.admin_state, "ENABLED")
+            self.assertEqual(simulated_olt.oper_status, "ACTIVE")
+            self.assertEqual(simulated_olt.volt_service_id, "volt_service_id")
+            self.assertEqual(simulated_olt.device_id, "test_id")
+            self.assertEqual(simulated_olt.of_id, "of_id")
+            self.assertEqual(simulated_olt.dp_id, "of:0000000ce2314000")
+
+
             mock_pon_save.assert_called()
             mock_nni_save.assert_called()
 
     @requests_mock.Mocker()
+    def test_pull_mac_address(self, m):
+        devices = {
+            "items": [
+                {
+                    'id': 'tibit_id',
+                    'type': 'tibit_olt',
+                    'mac_address': '70:b3:d5:52:30:6f',
+                    'admin_state': 'ENABLED',
+                    'oper_status': 'ACTIVE',
+                    'serial_number': 'OLT-70b3d552306f',
+                }
+            ]
+        }
+
+        logical_devices = {
+            "items": [
+                {
+                    "root_device_id": "tibit_id",
+                    "id": "of_id",
+                    "datapath_id": "55334486017"
+                }
+            ]
+        }
+
+        with patch.object(VOLTService.objects, "all") as olt_service_mock, \
+                patch.object(OLTDevice, "save", autospec=True) as mock_olt_save, \
+                patch.object(PONPort, "save") as mock_pon_save, \
+                patch.object(NNIPort, "save") as mock_nni_save:
+            olt_service_mock.return_value = [self.volt_service]
+
+            m.get("http://voltha_url:1234/api/v1/devices", status_code=200, json=devices)
+            m.get("http://voltha_url:1234/api/v1/devices/tibit_id/ports", status_code=200, json=self.ports)
+            m.get("http://voltha_url:1234/api/v1/logical_devices", status_code=200, json=logical_devices)
+
+
+            self.sync_step(model_accessor=self.model_accessor).pull_records()
+
+
+            saved_olts = mock_olt_save.call_args_list
+            tibit_olt = saved_olts[0][0][0]
+            self.assertEqual(len(saved_olts), 1)
+
+            self.assertEqual(tibit_olt.admin_state, "ENABLED")
+            self.assertEqual(tibit_olt.oper_status, "ACTIVE")
+            self.assertEqual(tibit_olt.volt_service_id, "volt_service_id")
+            self.assertEqual(tibit_olt.device_id, "tibit_id")
+            self.assertEqual(tibit_olt.of_id, "of_id")
+            self.assertEqual(tibit_olt.dp_id, "of:0000000ce2314001")
+
+            mock_pon_save.assert_called()
+            mock_nni_save.assert_called()
+
+
+    @requests_mock.Mocker()
     def test_pull_existing(self, m):
 
         existing_olt = Mock()