SEBA-467 Fix or note potential concurrency issues

Change-Id: I76c2b012e26b1fd8247d3f60aafd31ba25f368b1
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 8e591cb..5172830 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
@@ -72,6 +72,12 @@
                 si.status_message = "ONU has been disabled"
             self.update_onu(si.serial_number, "DISABLED")
 
+    # If the ONU has been disabled then we force re-authentication when it
+    # is re-enabled.
+    # Setting si.authentication_state = AWAITING:
+    #   -> subscriber status = "awaiting_auth"
+    #   -> service chain deleted
+    #   -> need authentication to restore connectivity after ONU enabled
     def process_auth_state(self, si):
         auth_msgs = {
             "AWAITING": " - Awaiting Authentication",
@@ -85,6 +91,16 @@
         else:
             si.status_message += auth_msgs[si.authentication_state]
 
+    # The DhcpL2Relay ONOS app generates events that update the fields below.
+    # It only sends events when it processes DHCP packets.  It keeps no internal state.
+    # We reset dhcp_state when:
+    # si.authentication_state in ["AWAITING", "REQUESTED", "STARTED"]
+    #   -> subscriber status = "awaiting_auth"
+    #   -> service chain not present
+    #   -> subscriber's OLT flow rules, xconnect not present
+    #   -> DHCP packets won't go through
+    # Note, however, that the DHCP state at the endpoints is not changed.
+    # A previously issued DHCP lease may still be valid.
     def process_dhcp_state(self, si):
         if si.authentication_state in ["AWAITING", "REQUESTED", "STARTED"]:
             si.ip_address = ""
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 f063cc4..2cb0b97 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
@@ -29,14 +29,14 @@
     def handle_create(self, whitelist):
         self.handle_update(whitelist)
 
+    # Update the SI if the onu_state has changed.
+    # The SI model policy will take care of updating other state.
     def validate_onu_state(self, si):
         [valid, message] = AttHelpers.validate_onu(self.model_accessor, self.logger, 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)
@@ -56,7 +56,7 @@
             self.validate_onu_state(si)
 
         whitelist.backend_need_delete_policy=True
-        whitelist.save(update_fields=["backend_need_delete_policy"])
+        whitelist.save_changed_fields()
 
     def handle_delete(self, whitelist):
         self.logger.debug("MODEL_POLICY: handle_delete for AttWorkflowDriverWhiteListEntry", serial_number=whitelist.serial_number, pon_port=whitelist.pon_port_id, device=whitelist.device_id)
@@ -72,4 +72,4 @@
             self.validate_onu_state(si)
 
         whitelist.backend_need_reap=True
-        whitelist.save(update_fields=["backend_need_reap"])
+        whitelist.save_changed_fields()
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 0c8028a..9477258 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,9 +73,7 @@
             self.policy.validate_onu_state(si)
 
             save_si.assert_called_once()
-            save_si.assert_called_with(always_update_timestamp=True, update_fields=['onu_state', 'serial_number', 'status_message', 'updated'])
-
-            self.assertEqual("valid onu", si.status_message)
+            save_si.assert_called_with(always_update_timestamp=True, update_fields=['onu_state', 'serial_number', 'updated'])
 
     def test_disable_onu(self):
         si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id, valid="invalid")
@@ -86,9 +84,7 @@
             self.policy.validate_onu_state(si)
 
             save_si.assert_called_once()
-            save_si.assert_called_with(always_update_timestamp=True, update_fields=['authentication_state', 'onu_state', 'serial_number', 'status_message', 'updated'])
-
-            self.assertEqual("invalid onu", si.status_message)
+            save_si.assert_called_with(always_update_timestamp=True, update_fields=['onu_state', 'serial_number', 'updated'])
 
     def test_whitelist_update(self):
         si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id)
@@ -103,7 +99,7 @@
 
             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"])
+            wle_save.assert_called_with(always_update_timestamp=False, update_fields=['backend_need_delete_policy', 'owner', 'serial_number'])
 
     def test_whitelist_delete(self):
         si = AttWorkflowDriverServiceInstance(serial_number="BRCM333", owner_id=self.service.id)
@@ -117,7 +113,7 @@
 
             validate_onu_state.assert_called_with(si)
             self.assertTrue(wle.backend_need_reap)
-            wle_save.assert_called_with(update_fields=["backend_need_reap"])
+            wle_save.assert_called_with(always_update_timestamp=False, update_fields=['backend_need_reap', 'owner', 'serial_number'])
 if __name__ == '__main__':
     unittest.main()