From 830217bfcb26cff8196efd2b35d7ba4e275b8716 Mon Sep 17 00:00:00 2001
From: Jorrit Schaap <schaap@astron.nl>
Date: Thu, 11 Apr 2019 13:40:51 +0000
Subject: [PATCH] SW-610: SW-516: fixed radb tests. Added task-status-update
 rules. Allow only prescheduled->scheduled. And allow only conflict->approved

---
 .../radb/sql/add_functions_and_triggers.sql   | 11 ++++-
 .../tests/t_radb_functionality.py             | 40 +++++++++++++++----
 .../tests/t_radb_performance.py               |  2 +-
 3 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/radb/sql/add_functions_and_triggers.sql b/SAS/ResourceAssignment/ResourceAssignmentDatabase/radb/sql/add_functions_and_triggers.sql
index b32116dd3e0..1697cb1ccde 100644
--- a/SAS/ResourceAssignment/ResourceAssignmentDatabase/radb/sql/add_functions_and_triggers.sql
+++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/radb/sql/add_functions_and_triggers.sql
@@ -19,11 +19,20 @@ DECLARE
     task_aborted_status_id int  := 1100; --beware: hard coded instead of lookup for performance
 BEGIN
   IF NEW.status_id <> OLD.status_id THEN
+    IF NEW.status_id = task_scheduled_status_id AND OLD.status_id <> task_prescheduled_status_id THEN
+        -- tasks can only be scheduled from the prescheduled state
+        RAISE EXCEPTION 'Cannot update task status from % to %', OLD.status_id, NEW.status_id;
+    END IF;
+
+    IF OLD.status_id = task_conflict_status_id AND NEW.status_id <> task_approved_status_id THEN
+        RAISE EXCEPTION 'When a task has the conflict status it can has to be set to approved status first by making sure all its claims have no conflict status anymore.';
+    END IF;
+
     IF NEW.status_id = task_approved_status_id OR NEW.status_id = task_conflict_status_id THEN
         UPDATE resource_allocation.resource_claim
         SET status_id=claim_tentative_status_id
         WHERE (task_id=NEW.id AND status_id = claim_claimed_status_id);
-    ELSIF OLD.status_id = task_prescheduled_status_id AND NEW.status_id = task_scheduled_status_id THEN
+    ELSIF NEW.status_id = task_scheduled_status_id THEN
         --prevent task status to be scheduled when not all its claims are claimed
         IF EXISTS (SELECT id FROM resource_allocation.resource_claim WHERE task_id = NEW.id AND status_id <> claim_claimed_status_id) THEN
             RAISE EXCEPTION 'Cannot update task status from % to % when not all its claims are claimed', OLD.status_id, NEW.status_id;
diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_functionality.py b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_functionality.py
index b4c69fd9962..fe68c5f5322 100755
--- a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_functionality.py
+++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_functionality.py
@@ -891,6 +891,17 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         self.assertTrue(task1)
         self.assertEqual(task_id1, task1['id'])
 
+        # try to update the task status to scheduled, should not succeed, because it isn't prescheduled yet
+        self.assertFalse(self.radb.updateTask(task_id1, task_status='scheduled'))
+
+        # try to update the task status to scheduled via prescheduled first
+        self.assertTrue(self.radb.updateTask(task_id1, task_status='prescheduled'))
+        self.assertTrue(self.radb.updateTask(task_id1, task_status='scheduled'))
+
+        # ok, that works...
+        # now unscheduled it again so we can add some claims
+        self.assertTrue(self.radb.updateTask(task_id1, task_status='approved'))
+
         t1_claim1 = { 'resource_id': cep4_id,
                       'starttime': task1['starttime'],
                       'endtime': task1['endtime'],
@@ -934,9 +945,14 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         t1_faulty_claim_ids = self.radb.insertResourceClaims(task_id1, [t1_claim2], 'foo', 1, 1)
         self.assertEqual(1, len(self.radb.getResourceClaims(task_ids=task_id1))) #there should still be one (proper/non-faulty) claim for this task
 
-        # try to update the task status to scheduled, should not succeed, since it's claims are not 'claimed' yet.
+        from pprint import pprint
+        pprint(self.radb.getTasks())
+        pprint(self.radb.getResourceClaims())
+
+        # try to update the task status to scheduled (via prescheduled), should not succeed, since it's claims are not 'claimed' yet.
+        self.assertTrue(self.radb.updateTask(task_id1, task_status='prescheduled'))
         self.assertFalse(self.radb.updateTask(task_id1, task_status='scheduled'))
-        self.assertEqual('approved', self.radb.getTask(task_id1)['status'])
+        self.assertEqual('prescheduled', self.radb.getTask(task_id1)['status'])
 
         # try to update the claim status to claimed, should succeed.
         self.assertTrue(self.radb.updateResourceClaims(t1_claim_ids, status='claimed'))
@@ -991,7 +1007,11 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         self.assertFalse(self.radb.updateResourceClaims(t2_claim_ids, resource_id=118))
         self.assertEqual(cep4_id, t2_claims[0]['resource_id'])
 
-        # try to update the task status to scheduled, should not succeed, since it's claims are not 'claimed' yet.
+        # try to update the task status to scheduled (via prescheduled),
+        # should not succeed, since it's claims are not 'claimed' yet.
+        # setting it to prescheduled should not even succeed because of the claims in conflict
+        self.assertFalse(self.radb.updateTask(task_id2, task_status='prescheduled'))
+        self.assertEqual('conflict', self.radb.getTask(task_id2)['status'])
         self.assertFalse(self.radb.updateTask(task_id2, task_status='scheduled'))
         self.assertEqual('conflict', self.radb.getTask(task_id2)['status'])
 
@@ -1014,6 +1034,7 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         self.assertEqual('claimed', self.radb.getResourceClaim(t2_claim_ids[0])['status'])
 
         # and try to update the task status to scheduled, should succeed now
+        self.assertTrue(self.radb.updateTask(task_id2, task_status='prescheduled'))
         self.assertTrue(self.radb.updateTask(task_id2, task_status='scheduled'))
         self.assertEqual('scheduled', self.radb.getTask(task_id2)['status'])
 
@@ -1029,7 +1050,8 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
 
         # again do conflict resolution, shift task and claims
         self.assertTrue(self.radb.updateTaskAndResourceClaims(task_id2, starttime=now+timedelta(hours=2), endtime=now+timedelta(hours=3)))
-        self.assertTrue(self.radb.updateTaskAndResourceClaims(task_id2, claim_status='claimed', task_status='scheduled'))
+        self.assertTrue(self.radb.updateTaskAndResourceClaims(task_id2, claim_status='claimed', task_status='prescheduled'))
+        self.assertTrue(self.radb.updateTaskAndResourceClaims(task_id2, task_status='scheduled'))
         # now the task and claim status should be scheduled/claimed
         self.assertEqual('scheduled', self.radb.getTask(task_id2)['status'])
         self.assertEqual('claimed', self.radb.getResourceClaim(t2_claim_ids[0])['status'])
@@ -1137,6 +1159,7 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         self.assertEqual('claimed', self.radb.getResourceClaim(t3_claim_ids[0])['status'])
 
         # and try to update the task status to scheduled, should succeed now
+        self.assertTrue(self.radb.updateTask(task_id3, task_status='prescheduled'))
         self.assertTrue(self.radb.updateTask(task_id3, task_status='scheduled'))
         self.assertEqual('scheduled', self.radb.getTask(task_id3)['status'])
 
@@ -1466,7 +1489,8 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         for claim in self.radb.getResourceClaims(claim_ids=extra_claim_ids):
             self.assertEqual('claimed', claim['status']) #(used to be conflict before bug of 2017-08-16)
 
-        #and finally, the task should be able to be scheduled as well.
+        #and finally, the task should be able to be scheduled (via prescheduled) as well.
+        self.assertTrue(self.radb.updateTask(task_id, task_status='prescheduled'))
         self.assertTrue(self.radb.updateTask(task_id, task_status='scheduled'))
         self.assertEqual('scheduled', self.radb.getTask(task_id)['status'])
 
@@ -2087,7 +2111,8 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
                                       starttime=task_low['starttime'],
                                       endtime=task_low['endtime'])
 
-        # finally make the task scheduled. Should still work.
+        # finally make the task scheduled (via prescheduled_. Should still work.
+        self.radb.updateTask(task_low_id, task_status='prescheduled')
         self.radb.updateTask(task_low_id, task_status='scheduled')
 
         # so fo so good. Everything should be normal and fine. Let's check.
@@ -2504,7 +2529,8 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
         self.assertEqual(set([claim1_id, claim2_id]), set(c['id'] for c in self.radb.getResourceClaims(task_ids=task_id)))
 
         # claim them, and check it. Should succeed.
-        self.radb.updateTaskAndResourceClaims(task_id, task_status='scheduled', claim_status='claimed')
+        self.radb.updateTaskAndResourceClaims(task_id, task_status='prescheduled', claim_status='claimed')
+        self.radb.updateTaskAndResourceClaims(task_id, task_status='scheduled')
         self.assertEqual('claimed', self.radb.getResourceClaim(claim1_id)['status'])
         self.assertEqual('claimed', self.radb.getResourceClaim(claim2_id)['status'])
         self.assertEqual('scheduled', self.radb.getTask(task_id)['status'])
diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py
index 903a930572e..c3f8febff2b 100755
--- a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py
+++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb_performance.py
@@ -142,7 +142,7 @@ class ResourceAssignmentDatabaseTest(radb_common_testing.RADBCommonTest):
                                                                                  elapsed_status_update, ELAPSED_TRESHOLD, num_tasks, num_claims, num_claims_to_insert, num_claims_per_resource))
 
                         # ... and proceed with cycling through the task status
-                        for task_status in ['scheduled', 'queued', 'active', 'completing', 'finished']:
+                        for task_status in ['prescheduled', 'scheduled', 'queued', 'active', 'completing', 'finished']:
                             # update the task status
                             start = datetime.utcnow()
                             self.radb.updateTaskAndResourceClaims(task_id=task_id, task_status=task_status)
-- 
GitLab