Fixing disable issue

Change-Id: I2ff36d15aaf770528ac3f0c207a3944799355acc
diff --git a/xos/synchronizer/model_policies/model_policy_att_workflow_driver_service.py b/xos/synchronizer/model_policies/model_policy_att_workflow_driver_service.py
deleted file mode 100644
index f738c3a..0000000
--- a/xos/synchronizer/model_policies/model_policy_att_workflow_driver_service.py
+++ /dev/null
@@ -1,45 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-from synchronizers.new_base.modelaccessor import AttWorkflowDriverServiceInstance, model_accessor
-from synchronizers.new_base.policy import Policy
-
-class AttWorkflowDriverServicePolicy(Policy):
-    model_name = "AttWorkflowDriverService"
-
-    def handle_update(self, service):
-        self.logger.debug("MODEL_POLICY: handle_update for AttWorkflowDriverService", oss=service)
-
-        sis = AttWorkflowDriverServiceInstance.objects.all()
-
-        # TODO(teone): use the method defined in helpers.py
-
-        whitelist = [x.serial_number.lower() for x in service.whitelist_entries.all()]
-
-        for si in sis:
-            if si.serial_number.lower() in whitelist and not si.valid == "valid":
-                self.logger.debug("MODEL_POLICY: activating AttWorkflowDriverServiceInstance because of change in the whitelist", si=si)
-                si.valid = "valid"
-                si.save(update_fields=["valid", "no_sync", "updated"], always_update_timestamp=True)
-            if si.serial_number.lower() not in whitelist and not si.valid == "invalid":
-                self.logger.debug(
-                    "MODEL_POLICY: disabling AttWorkflowDriverServiceInstance because of change in the whitelist", si=si)
-                si.valid = "invalid"
-                si.save(update_fields=["valid", "no_sync", "updated"], always_update_timestamp=True)
-
-
-    def handle_delete(self, si):
-        pass
diff --git a/xos/synchronizer/model_policies/model_policy_att_workflow_driver_serviceinstance.py b/xos/synchronizer/model_policies/model_policy_att_workflow_driver_serviceinstance.py
index df73f7d..e08d6bd 100644
--- a/xos/synchronizer/model_policies/model_policy_att_workflow_driver_serviceinstance.py
+++ b/xos/synchronizer/model_policies/model_policy_att_workflow_driver_serviceinstance.py
@@ -37,13 +37,16 @@
         self.handle_update(si)
 
     def handle_update(self, si):
-        self.logger.debug("MODEL_POLICY: handle_update for AttWorkflowDriverServiceInstance %s " % (si.id))
+        self.logger.debug("MODEL_POLICY: handle_update for AttWorkflowDriverServiceInstance %s " % (si.id), onu_state=si.onu_state, authentication_state=si.authentication_state)
 
         # validating ONU
         if si.onu_state == "AWAITING" or si.onu_state == "ENABLED":
             # we validate the ONU state only if it is enabled or awaiting,
             # if it's disabled it means someone has disabled it
             self.validate_onu_state(si)
+        else:
+            # but we still verify that the device is actually down
+            self.update_onu(si.serial_number, "DISABLED")
 
         # handling the subscriber status
         subscriber = self.get_subscriber(si.serial_number)
@@ -64,6 +67,7 @@
             self.update_onu(si.serial_number, "DISABLED")
 
     def update_onu(self, serial_number, admin_state):
+        # TODO if the status hasn't changed don't save it again
         self.logger.debug("MODEL_POLICY: setting ONUDevice [%s] admin_state to %s" % (serial_number, admin_state))
         onu = ONUDevice.objects.get(serial_number=serial_number)
         onu.admin_state = admin_state
@@ -78,6 +82,7 @@
             return None
 
     def update_subscriber(self, subscriber, si):
+        # TODO if the status hasn't changed don't save it again
         if si.authentication_state == "AWAITING":
             subscriber.status = "awaiting-auth"
             si.status_message = "Awaiting Authentication"
diff --git a/xos/synchronizer/model_policies/model_policy_att_workflow_driver_whitelistentry.py b/xos/synchronizer/model_policies/model_policy_att_workflow_driver_whitelistentry.py
index 5cb4c23..29f4c89 100644
--- a/xos/synchronizer/model_policies/model_policy_att_workflow_driver_whitelistentry.py
+++ b/xos/synchronizer/model_policies/model_policy_att_workflow_driver_whitelistentry.py
@@ -16,6 +16,13 @@
 
 from synchronizers.new_base.modelaccessor import AttWorkflowDriverServiceInstance, AttWorkflowDriverWhiteListEntry, model_accessor
 from synchronizers.new_base.policy import Policy
+import os
+import sys
+
+sync_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), ".."))
+sys.path.append(sync_path)
+
+from helpers import AttHelpers
 
 class AttWorkflowDriverWhiteListEntryPolicy(Policy):
     model_name = "AttWorkflowDriverWhiteListEntry"
@@ -23,16 +30,22 @@
     def handle_create(self, whitelist):
         self.handle_update(whitelist)
 
+    def validate_onu_state(self, si):
+        [valid, message] = AttHelpers.validate_onu(si)
+        si.status_message = message
+        if valid:
+            si.onu_state = "ENABLED"
+        else:
+            si.onu_state = "DISABLED"
+            si.authentication_state = "AWAITING"
+
+        self.logger.debug(
+            "MODEL_POLICY: activating AttWorkflowDriverServiceInstance because of change in the whitelist", si=si, onu_state=si.onu_state, authentication_state=si.authentication_state)
+        si.save(update_fields=["no_sync", "updated", "onu_state", "status_message", "authentication_state"], always_update_timestamp=True)
+
     def handle_update(self, whitelist):
         self.logger.debug("MODEL_POLICY: handle_update for AttWorkflowDriverWhiteListEntry", whitelist=whitelist)
 
-        # TODO is Django construct '__iexact' available here?
-        # sis = AttWorkflowDriverServiceInstance.objects.filter(
-        #     serial_number = whitelist.serial_number,
-        #     owner_id = whitelist.owner.id)
-
-        # TODO(teone): use the method defined in helpers.py
-
         sis = AttWorkflowDriverServiceInstance.objects.all()
 
         for si in sis:
@@ -41,10 +54,7 @@
                 # NOTE we don't care about this SI as it has a different serial number
                 continue
 
-            if si.valid != "valid":
-                self.logger.debug("MODEL_POLICY: activating AttWorkflowDriverServiceInstance because of change in the whitelist", si=si)
-                si.valid = "valid"
-                si.save(update_fields=["valid", "no_sync", "updated"], always_update_timestamp=True)
+            self.validate_onu_state(si)
 
         whitelist.backend_need_delete_policy=True
         whitelist.save(update_fields=["backend_need_delete_policy"])
@@ -56,15 +66,11 @@
 
         assert(whitelist.owner)
 
-        sis = AttWorkflowDriverServiceInstance.objects.filter(serial_number = whitelist.serial_number,
-                                                   owner_id = whitelist.owner.id)
+        sis = AttWorkflowDriverServiceInstance.objects.all()
+        sis = [si for si in sis if si.serial_number.lower() == whitelist.serial_number.lower()]
 
         for si in sis:
-            if si.valid != "invalid":
-                self.logger.debug(
-                    "MODEL_POLICY: disabling AttWorkflowDriverServiceInstance because of change in the whitelist", si=si)
-                si.valid = "invalid"
-                si.save(update_fields=["valid", "no_sync", "updated"], always_update_timestamp=True)
+            self.validate_onu_state(si)
 
         whitelist.backend_need_reap=True
         whitelist.save(update_fields=["backend_need_reap"])
diff --git a/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_service.py b/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_service.py
deleted file mode 100644
index 576233f..0000000
--- a/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_service.py
+++ /dev/null
@@ -1,130 +0,0 @@
-
-# Copyright 2017-present Open Networking Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-import unittest
-from mock import patch, call, Mock, PropertyMock
-
-import os, sys
-
-test_path=os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
-service_dir=os.path.join(test_path, "../../../..")
-xos_dir=os.path.join(test_path, "../../..")
-if not os.path.exists(os.path.join(test_path, "new_base")):
-    xos_dir=os.path.join(test_path, "../../../../../../orchestration/xos/xos")
-    services_dir=os.path.join(xos_dir, "../../xos_services")
-
-def get_models_fn(service_name, 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
-    raise Exception("Unable to find service=%s xproto=%s" % (service_name, xproto_name))
-
-class TestModelPolicyAttWorkflowDriverService(unittest.TestCase):
-    def setUp(self):
-        self.sys_path_save = sys.path
-        sys.path.append(xos_dir)
-        sys.path.append(os.path.join(xos_dir, 'synchronizers', 'new_base'))
-
-        config = os.path.join(test_path, "../test_config.yaml")
-        from xosconfig import Config
-        Config.clear()
-        Config.init(config, 'synchronizer-config-schema.yaml')
-
-        from synchronizers.new_base.mock_modelaccessor_build import build_mock_modelaccessor
-        build_mock_modelaccessor(xos_dir, services_dir, [
-            get_models_fn("att-workflow-driver", "att-workflow-driver.xproto"),
-            get_models_fn("olt-service", "volt.xproto"),
-            get_models_fn("../profiles/rcord", "rcord.xproto")
-        ])
-
-        import synchronizers.new_base.modelaccessor
-        from model_policy_att_workflow_driver_service import AttWorkflowDriverServicePolicy, model_accessor
-
-        from mock_modelaccessor import MockObjectList
-        self.MockObjectList = MockObjectList
-
-        # import all class names to globals
-        for (k, v) in model_accessor.all_model_classes.items():
-            globals()[k] = v
-
-        # Some of the functions we call have side-effects. For example, creating a VSGServiceInstance may lead to creation of
-        # tags. Ideally, this wouldn't happen, but it does. So make sure we reset the world.
-        model_accessor.reset_all_object_stores()
-
-        self.policy = AttWorkflowDriverServicePolicy()
-
-        self.service = AttWorkflowDriverService(
-            id = 5367,
-            whitelist_entries = [],
-        )
-
-        # needs to be enabled
-        self.si1 = AttWorkflowDriverServiceInstance(
-            valid="awaiting",
-            serial_number="BRCM111"
-        )
-
-        # needs to be enabled
-        self.si2 = AttWorkflowDriverServiceInstance(
-            valid="invalid",
-            serial_number="BRCM222"
-        )
-
-        # remains disabled
-        self.si3 = AttWorkflowDriverServiceInstance(
-            valid="invalid",
-            serial_number="BRCM333"
-        )
-
-        # needs to be disabled
-        self.si4 = AttWorkflowDriverServiceInstance(
-            valid="valid",
-            serial_number="BRCM444"
-        )
-
-    def tearDown(self):
-        sys.path = self.sys_path_save
-        self.service = None
-
-    def test_whitelist_update(self):
-        """
-        When the whitelist is updated, check for added ONU to be enabled and for removed ONU to be disabled
-        """
-        with patch.object(AttWorkflowDriverServiceInstance.objects, "get_items") as oss_si, \
-            patch.object(self.si1, "save") as si1_save, \
-            patch.object(self.si2, "save") as si2_save, \
-            patch.object(self.si3, "save") as si3_save, \
-            patch.object(self.si4, "save") as si4_save:
-            oss_si.return_value = [self.si1, self.si2, self.si3, self.si4]
-
-            wle1 = AttWorkflowDriverWhiteListEntry(owner_id=self.service.id, serial_number="BRCM111")
-            wle2 = AttWorkflowDriverWhiteListEntry(owner_id=self.service.id, serial_number="brcm222")
-            self.service.whitelist_entries = self.MockObjectList([wle1, wle2])
-
-            self.policy.handle_update(self.service)
-
-            self.si1.save.assert_called_with(always_update_timestamp=True, update_fields=['valid', 'no_sync', 'updated'])
-            self.assertEqual(self.si1.valid, "valid")
-            self.si2.save.assert_called_with(always_update_timestamp=True, update_fields=['valid', 'no_sync', 'updated'])
-            self.assertEqual(self.si2.valid, "valid")
-            self.si3.save.assert_not_called()
-            self.assertEqual(self.si3.valid, "invalid")
-            self.si4.save.assert_called_with(always_update_timestamp=True, update_fields=['valid', 'no_sync', 'updated'])
-            self.assertEqual(self.si4.valid, "invalid")
-
-if __name__ == '__main__':
-    unittest.main()
-
diff --git a/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_serviceinstance.py b/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_serviceinstance.py
index 18c8174..d7ba4a2 100644
--- a/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_serviceinstance.py
+++ b/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_serviceinstance.py
@@ -194,6 +194,7 @@
         )
 
         with patch.object(self.policy, "get_subscriber") as get_subscriber, \
+            patch.object(self.policy, "update_onu") as update_onu, \
             patch.object(self.policy, "update_subscriber") as update_subscriber:
 
             get_subscriber.return_value = None
diff --git a/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_whitelistentry.py b/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_whitelistentry.py
index 68e1752..369ef70 100644
--- a/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_whitelistentry.py
+++ b/xos/synchronizer/model_policies/test_model_policy_att_workflow_driver_whitelistentry.py
@@ -73,48 +73,62 @@
         sys.path = self.sys_path_save
         self.service = None
 
+    def test_enable_onu(self):
+        from helpers import AttHelpers
+        si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id, valid="invalid")
+        with patch.object(AttHelpers, "validate_onu") as validate_onu, \
+            patch.object(si, "save") as save_si:
+            validate_onu.return_value = [True, "valid onu"]
+
+            self.policy.validate_onu_state(si)
+
+            save_si.assert_called_once()
+            save_si.assert_called_with(always_update_timestamp=True, update_fields=['no_sync', 'updated', 'onu_state', 'status_message', 'authentication_state'])
+
+            self.assertEqual("valid onu", si.status_message)
+
+    def test_disable_onu(self):
+        from helpers import AttHelpers
+        si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id, valid="invalid")
+        with patch.object(AttHelpers, "validate_onu") as validate_onu, \
+            patch.object(si, "save") as save_si:
+            validate_onu.return_value = [False, "invalid onu"]
+
+            self.policy.validate_onu_state(si)
+
+            save_si.assert_called_once()
+            save_si.assert_called_with(always_update_timestamp=True, update_fields=['no_sync', 'updated', 'onu_state', 'status_message', 'authentication_state'])
+
+            self.assertEqual("invalid onu", si.status_message)
+
     def test_whitelist_update(self):
-        """
-        When a whitelist entry is added, see that the AttWorkflowDriverIServicenstance was set to valid
-        """
-        with patch.object(AttWorkflowDriverServiceInstance.objects, "get_items") as oss_si_items:
-            si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id, valid="invalid")
+        si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id)
+        wle = AttWorkflowDriverWhiteListEntry(serial_number="brcm333", owner_id=self.service.id, owner=self.service)
+        with patch.object(AttWorkflowDriverServiceInstance.objects, "get_items") as oss_si_items, \
+            patch.object(self.policy, "validate_onu_state") as validate_onu_state, \
+            patch.object(wle, "save") as wle_save:
             oss_si_items.return_value = [si]
 
-            wle = AttWorkflowDriverWhiteListEntry(serial_number="BRCM333", owner_id=self.service.id, owner=self.service)
 
             self.policy.handle_update(wle)
 
-            self.assertEqual(si.valid, "valid")
-
-    def test_whitelist_update_case_insensitive(self):
-        """
-        When a whitelist entry is added, see that the AttWorkflowDriverIServicenstance was set to valid
-        """
-        with patch.object(AttWorkflowDriverServiceInstance.objects, "get_items") as oss_si_items:
-            si = AttWorkflowDriverServiceInstance(serial_number="brcm333", owner_id=self.service.id, valid="invalid")
-            oss_si_items.return_value = [si]
-
-            wle = AttWorkflowDriverWhiteListEntry(serial_number="BRCM333", owner_id=self.service.id, owner=self.service)
-
-            self.policy.handle_update(wle)
-
-            self.assertEqual(si.valid, "valid")
+            validate_onu_state.assert_called_with(si)
+            self.assertTrue(wle.backend_need_delete_policy)
+            wle_save.assert_called_with(update_fields=["backend_need_delete_policy"])
 
     def test_whitelist_delete(self):
-        """
-        When a whitelist entry is deleted, see that the AttWorkflowDriverIServicenstance was set to invalid
-        """
-        with patch.object(AttWorkflowDriverServiceInstance.objects, "get_items") as oss_si_items:
-            si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id, valid="valid")
+        si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id)
+        wle = AttWorkflowDriverWhiteListEntry(serial_number="brcm333", owner_id=self.service.id, owner=self.service)
+        with patch.object(AttWorkflowDriverServiceInstance.objects, "get_items") as oss_si_items, \
+                patch.object(self.policy, "validate_onu_state") as validate_onu_state, \
+                patch.object(wle, "save") as wle_save:
             oss_si_items.return_value = [si]
 
-            wle = AttWorkflowDriverWhiteListEntry(serial_number="BRCM333", owner_id=self.service.id, owner=self.service)
-
             self.policy.handle_delete(wle)
 
-            self.assertEqual(si.valid, "invalid")
-
+            validate_onu_state.assert_called_with(si)
+            self.assertTrue(wle.backend_need_reap)
+            wle_save.assert_called_with(update_fields=["backend_need_reap"])
 if __name__ == '__main__':
     unittest.main()