[CORD-3167] If an OSS Service Instance is validate, activate the ONU

Change-Id: Icd0b7be85020713a3e370f22bdd3ed2e9409ca80
diff --git a/.gitignore b/.gitignore
index ee40bb3..a1f2e6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,4 @@
 .idea/
-*.pyc
\ No newline at end of file
+*.pyc
+.coverage
+xos/htmlcov/
\ No newline at end of file
diff --git a/xos/synchronizer/model_policies/model_policy_hippieossserviceinstance.py b/xos/synchronizer/model_policies/model_policy_hippieossserviceinstance.py
index 31c2290..3008a57 100644
--- a/xos/synchronizer/model_policies/model_policy_hippieossserviceinstance.py
+++ b/xos/synchronizer/model_policies/model_policy_hippieossserviceinstance.py
@@ -33,14 +33,35 @@
             onu.save(always_update_timestamp=True)
             return
         if si.valid == "valid":
-            self.logger.debug("MODEL_POLICY: creating RCORDSubscriber for HippieOSSServiceInstance %s" % si.id)
-            subscriber = RCORDSubscriber()
-            subscriber.onu_device = si.serial_number
-            subscriber.uni_port_id = si.uni_port_id
 
-            # If the OSS returns a c_tag use that one
-            if si.c_tag:
-                subscriber.c_tag = si.c_tag
+            # reactivating the ONUDevice
+            onu = ONUDevice.objects.get(serial_number=si.serial_number)
+            if onu.admin_state == "DISABLED":
+                self.logger.debug("MODEL_POLICY: enabling ONUDevice [%s] for HippieOSSServiceInstance %s" % (
+                si.serial_number, si.id))
+                onu.admin_state = "ENABLED"
+                onu.save(always_update_timestamp=True)
+
+            # NOTE this assumes that an ONUDevice has only one Subscriber
+            try:
+                subscriber = RCORDSubscriber.objects.get(onu_device=si.serial_number)
+
+                # If the OSS returns a c_tag and the subscriber doesn't already have his one
+                if si.c_tag and not subscriber.c_tag:
+                    self.logger.debug("MODEL_POLICY: updating c_tag for RCORDSubscriber %s and HippieOSSServiceInstance %s" % (subscriber.id, si.id))
+                    subscriber.c_tag = si.c_tag
+                else:
+                    # if we're not changing anything in the subscriber, we don't need to update it
+                    return
+            except IndexError, e:
+                self.logger.debug("MODEL_POLICY: creating RCORDSubscriber for HippieOSSServiceInstance %s" % si.id)
+
+                subscriber = RCORDSubscriber()
+                subscriber.onu_device = si.serial_number
+
+                # If the OSS returns a c_tag use that one
+                if si.c_tag:
+                    subscriber.c_tag = si.c_tag
 
             subscriber.save()
             return
diff --git a/xos/synchronizer/model_policies/test_model_policy_hippieossserviceinstance.py b/xos/synchronizer/model_policies/test_model_policy_hippieossserviceinstance.py
index 07847b2..65a740f 100644
--- a/xos/synchronizer/model_policies/test_model_policy_hippieossserviceinstance.py
+++ b/xos/synchronizer/model_policies/test_model_policy_hippieossserviceinstance.py
@@ -26,16 +26,10 @@
     xos_dir=os.path.join(test_path, "../../../../../../orchestration/xos/xos")
     services_dir=os.path.join(xos_dir, "../../xos_services")
 
-# While transitioning from static to dynamic load, the path to find neighboring xproto files has changed. So check
-# both possible locations...
 def get_models_fn(service_name, xproto_name):
-    name = os.path.join(service_name, "xos", xproto_name)
+    name = os.path.join(service_name, "xos", "synchronizer", "models", xproto_name)
     if os.path.exists(os.path.join(services_dir, name)):
         return name
-    else:
-        name = os.path.join(service_name, "xos", "synchronizer", "models", xproto_name)
-        if os.path.exists(os.path.join(services_dir, name)):
-            return name
     raise Exception("Unable to find service=%s xproto=%s" % (service_name, xproto_name))
 
 class TestModelPolicyHippieOssServiceInstance(unittest.TestCase):
@@ -59,7 +53,7 @@
         ])
 
         import synchronizers.new_base.modelaccessor
-        from model_policy_hippieossserviceinstance import OSSServiceInstancePolicy, RCORDSubscriber, ONUDevice, model_accessor
+        from model_policy_hippieossserviceinstance import OSSServiceInstancePolicy, model_accessor
 
         from mock_modelaccessor import MockObjectList
 
@@ -97,8 +91,8 @@
         )
 
         with patch.object(ONUDevice.objects, "get_items") as onu_objects, \
-            patch.object(RCORDSubscriber, "save") as subscriber_save, \
-            patch.object(ONUDevice, "save") as onu_save:
+                patch.object(RCORDSubscriber, "save") as subscriber_save, \
+                patch.object(ONUDevice, "save") as onu_save:
 
             onu_objects.return_value = [onu]
 
@@ -107,38 +101,108 @@
             self.assertEqual(onu.admin_state, "DISABLED")
             onu_save.assert_called()
 
+    def test_enable_onu(self):
+        self.si.valid = "valid"
+        self.si.serial_number = "BRCM1234"
+        self.si.c_tag = None
+
+        onu = ONUDevice(
+            serial_number=self.si.serial_number,
+            admin_state="DISABLED"
+        )
+
+        subscriber = RCORDSubscriber(
+            onu_device=self.si.serial_number,
+        )
+
+        with patch.object(ONUDevice.objects, "get_items") as onu_objects, \
+                patch.object(RCORDSubscriber.objects, "get_items") as subscriber_objects, \
+                patch.object(RCORDSubscriber, "save") as subscriber_save, \
+                patch.object(ONUDevice, "save") as onu_save:
+
+            onu_objects.return_value = [onu]
+            subscriber_objects.return_value = [subscriber]
+
+            self.policy.handle_update(self.si)
+            subscriber_save.assert_not_called()
+            self.assertEqual(onu.admin_state, "ENABLED")
+            onu_save.assert_called()
+
     def test_create_subscriber(self):
         self.si.valid = "valid"
         self.si.serial_number = "BRCM1234"
-        self.si.uni_port_id = 16
 
-        with patch.object(RCORDSubscriber, "save", autospec=True) as subscriber_save, \
-            patch.object(ONUDevice, "save") as onu_save:
+        onu = ONUDevice(
+            serial_number=self.si.serial_number,
+            admin_state="ENABLED"
+        )
+
+        with patch.object(ONUDevice.objects, "get_items") as onu_objects, \
+                patch.object(RCORDSubscriber, "save", autospec=True) as subscriber_save, \
+                patch.object(ONUDevice, "save") as onu_save:
+
+            onu_objects.return_value = [onu]
 
             self.policy.handle_update(self.si)
             self.assertEqual(subscriber_save.call_count, 1)
 
             subscriber = subscriber_save.call_args[0][0]
             self.assertEqual(subscriber.onu_device, self.si.serial_number)
-            self.assertEqual(subscriber.uni_port_id, self.si.uni_port_id)
 
             onu_save.assert_not_called()
 
     def test_create_subscriber_with_ctag(self):
         self.si.valid = "valid"
         self.si.serial_number = "BRCM1234"
-        self.si.uni_port_id = 16
         self.si.c_tag = 111
 
-        with patch.object(RCORDSubscriber, "save", autospec=True) as subscriber_save, \
-            patch.object(ONUDevice, "save") as onu_save:
+        onu = ONUDevice(
+            serial_number=self.si.serial_number,
+            admin_state="ENABLED"
+        )
+
+        with patch.object(ONUDevice.objects, "get_items") as onu_objects, \
+                patch.object(RCORDSubscriber, "save", autospec=True) as subscriber_save, \
+                patch.object(ONUDevice, "save") as onu_save:
+
+            onu_objects.return_value = [onu]
 
             self.policy.handle_update(self.si)
             self.assertEqual(subscriber_save.call_count, 1)
 
             subscriber = subscriber_save.call_args[0][0]
             self.assertEqual(subscriber.onu_device, self.si.serial_number)
-            self.assertEqual(subscriber.uni_port_id, self.si.uni_port_id)
+            self.assertEqual(subscriber.c_tag, self.si.c_tag)
+
+            onu_save.assert_not_called()
+
+    def test_add_c_tag_to_pre_provisioned_subscriber(self):
+        self.si.valid = "valid"
+        self.si.serial_number = "BRCM1234"
+        self.si.c_tag = 111
+
+        onu = ONUDevice(
+            serial_number=self.si.serial_number,
+            admin_state="ENABLED"
+        )
+
+        subscriber = RCORDSubscriber(
+            onu_device=self.si.serial_number,
+        )
+
+        with patch.object(ONUDevice.objects, "get_items") as onu_objects, \
+                patch.object(RCORDSubscriber.objects, "get_items") as subscriber_objects, \
+                patch.object(RCORDSubscriber, "save", autospec=True) as subscriber_save, \
+                patch.object(ONUDevice, "save") as onu_save:
+
+            onu_objects.return_value = [onu]
+            subscriber_objects.return_value = [subscriber]
+
+            self.policy.handle_update(self.si)
+            self.assertEqual(subscriber_save.call_count, 1)
+
+            subscriber = subscriber_save.call_args[0][0]
+            self.assertEqual(subscriber.onu_device, self.si.serial_number)
             self.assertEqual(subscriber.c_tag, self.si.c_tag)
 
             onu_save.assert_not_called()
diff --git a/xos/synchronizer/models/hippie-oss.xproto b/xos/synchronizer/models/hippie-oss.xproto
index 671089a..b111e08 100644
--- a/xos/synchronizer/models/hippie-oss.xproto
+++ b/xos/synchronizer/models/hippie-oss.xproto
@@ -14,7 +14,6 @@
 
     required string valid = 1 [default = "awaiting", choices = "(('awaiting', 'Awaiting Validation'), ('valid', 'Valid'), ('invalid', 'Invalid'))", help_text = "Wether this ONU has been validated by the external OSS", null = False, blank = False];
     required string serial_number = 2 [max_length = 254, null = False, db_index = False, blank = False, tosca_key=True, unique = True];
-    required int32 uni_port_id = 3 [null = False, db_index = False, blank = False];
     required string of_dpid = 4 [max_length = 254, null = False, db_index = False, blank = False];
-    optional int32 c_tag = 4 [null = True, db_index = False, blank = False, unique = True, feedback_state = True];
+    optional int32 c_tag = 5 [null = True, db_index = False, blank = False, unique = True, feedback_state = True];
 }
\ No newline at end of file
diff --git a/xos/synchronizer/steps/test_sync_hippie_oss_service_instance.py b/xos/synchronizer/steps/test_sync_hippie_oss_service_instance.py
index c80fa85..508677c 100644
--- a/xos/synchronizer/steps/test_sync_hippie_oss_service_instance.py
+++ b/xos/synchronizer/steps/test_sync_hippie_oss_service_instance.py
@@ -61,7 +61,9 @@
 
         from synchronizers.new_base.mock_modelaccessor_build import build_mock_modelaccessor
         build_mock_modelaccessor(xos_dir, services_dir, [
-            get_models_fn("hippie-oss", "hippie-oss.xproto")
+            get_models_fn("hippie-oss", "hippie-oss.xproto"),
+            get_models_fn("olt-service", "volt.xproto"),
+            get_models_fn("../profiles/rcord", "rcord.xproto")
         ])
         import synchronizers.new_base.modelaccessor
 
diff --git a/xos/synchronizer/test_config.yaml b/xos/synchronizer/test_config.yaml
index 5a70d2d..402dc91 100644
--- a/xos/synchronizer/test_config.yaml
+++ b/xos/synchronizer/test_config.yaml
@@ -28,3 +28,4 @@
     'multistructlog':
       handlers:
           - console
+#      level: DEBUG
diff --git a/xos/unittest.cfg b/xos/unittest.cfg
index 123cb69..fe33100 100644
--- a/xos/unittest.cfg
+++ b/xos/unittest.cfg
@@ -5,3 +5,9 @@
                  steps
                  pull_steps
                  event_steps
+
+[coverage]
+always-on = True
+coverage = synchronizer
+coverage-report = term
+coverage-report = html
\ No newline at end of file