From d897c75e00043a48ce3f988362fd8cde687642be Mon Sep 17 00:00:00 2001
From: Ruud Beukema <beukema@astron.nl>
Date: Thu, 18 May 2017 14:50:23 +0000
Subject: [PATCH] Task #10813: Added about 35 tests. See the ticket (note 6)
 for my remarks.

---
 .../tests/t_radb.py                           | 417 +++++++++++++++++-
 1 file changed, 412 insertions(+), 5 deletions(-)

diff --git a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.py b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.py
index 5f132bb5abb..694fba7a5fb 100755
--- a/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.py
+++ b/SAS/ResourceAssignment/ResourceAssignmentDatabase/tests/t_radb.py
@@ -24,6 +24,7 @@ import psycopg2
 import os
 from dateutil import parser
 import logging
+from datetime import timedelta
 
 logger = logging.getLogger(__name__)
 
@@ -53,8 +54,8 @@ class ResourceAssignmentDatabaseTest(unittest.TestCase):
 
     # These are applied in given order to set up test db
     # Note: cannot use create_and_populate_database.sql since '\i' is not understood by cursor.execute()
-    sql_basepath = os.environ['LOFARROOT'] + "/share/radb/sql/"
-    sql_createdb_paths = [sql_basepath + "create_database.sql",
+    sql_basepath = os.environ['LOFARROOT'] + "/share/radb/sql"
+    sql_createdb_paths = [sql_basepath + "/create_database.sql",
                           sql_basepath + "/add_resource_allocation_statics.sql",
                           sql_basepath + "/add_virtual_instrument.sql",
                           sql_basepath + "/add_notifications.sql",
@@ -258,9 +259,415 @@ class ResourceAssignmentDatabaseTest(unittest.TestCase):
     #
     #
 
-    def test_getTaskStatuses_contains_scheduled(self):
-        stat = self.radb.getTaskStatuses()
-        self.assertTrue('scheduled' in str(stat))
+    def test_getTaskStatuses_succeeds(self):
+        """ Verifies if radb.getTaskStatuses() successfully fetches all expected task statuses """
+
+        expected_statuses = [
+            {'id': 200, 'name': 'prepared'},
+            {'id': 300, 'name': 'approved'},
+            {'id': 320, 'name': 'on_hold'},
+            {'id': 335, 'name': 'conflict'},
+            {'id': 350, 'name': 'prescheduled'},
+            {'id': 400, 'name': 'scheduled'},
+            {'id': 500, 'name': 'queued'},
+            {'id': 600, 'name': 'active'},
+            {'id': 900, 'name': 'completing'},
+            {'id': 1000, 'name': 'finished'},
+            {'id': 1100, 'name': 'aborted'},
+            {'id': 1150, 'name': 'error'},
+            {'id': 1200, 'name': 'obsolete'}]
+
+        statuses = self.radb.getTaskStatuses()
+
+        self.assertEquals(statuses, expected_statuses)
+
+    def test_getTaskStatusNames_succeeds(self):
+        """ Verifies if radb.getTaskStatusNames() successfully fetches all expected task status names  """
+
+        expected_names = ['prepared', 'approved', 'on_hold', 'conflict', 'prescheduled', 'scheduled', 'queued',
+                          'active', 'completing', 'finished', 'aborted', 'error', 'obsolete']
+
+        names = self.radb.getTaskStatusNames()
+
+        self.assertEqual(sorted(expected_names), sorted(names))
+
+    def test_getTaskStatusId_wrong_status_fails(self):
+        """ Verifies if radb.getTaskStatusId() raises an Exception if the idea of an unknown status is requested """
+
+        wrong_status = 'willywonka'
+
+        self.assertRaises(KeyError, self.radb.getTaskStatusId, wrong_status)
+
+    def test_getTaskStatusId_right_status_succeeds(self):
+        """ Verifies if radb.getTaskStatusId() successfully fetches the expected status id for a given status. """
+
+        status = 'scheduled'
+        expected_status_id = 400
+
+        status_id = self.radb.getTaskStatusId(status)
+
+        self.assertEqual(status_id, expected_status_id)
+
+    def test_getTaskTypes_succeeds(self):
+        """ Verifies if radb.getTaskTypes() successfully fetches all expected task types """
+
+        expected_task_types = [
+            {'id': 0, 'name': 'observation'},
+            {'id': 1, 'name': 'pipeline'},
+            {'id': 2, 'name': 'reservation'}]
+
+        task_types = self.radb.getTaskTypes()
+
+        self.assertEqual(task_types, expected_task_types)
+
+    def test_getTaskTypeNames_succeeds(self):
+        """ Verifies if radb.getTaskTypeNames() successfully fetches all expected task type names """
+
+        expected_task_type_names = ['observation', 'pipeline', 'reservation']
+
+        task_type_names = self.radb.getTaskTypeNames()
+
+        self.assertEqual(task_type_names, expected_task_type_names)
+
+    def test_getTaskTypeId_wrong_type_name_fails(self):
+        """ Verifies if radb.getTaskTypeId() raises an exception if a type id is requested for a wrong type name """
+
+        wrong_type_name = 'willywonka'
+
+        self.assertRaises(KeyError, self.radb.getTaskTypeId, wrong_type_name)
+
+    def test_getTaskTypeId_right_type_name_succeeds(self):
+        """ Verifies if radb.getTaskTypeId() successfully fetches the type id for a given type name. """
+
+        type_name = 'reservation'
+        expected_type_id = 2
+
+        type_id = self.radb.getTaskTypeId(type_name)
+
+        self.assertEqual(type_id, expected_type_id)
+
+    # TODO: once merged with RT-Task10811 replace the old claim statuses by the new ones
+    def test_getResourceClaimStatuses_succeeds(self):
+        """ Verifies if radb.getResourceClaimStatuses() successfully fetches all expected claim statuses. """
+
+        expected_claim_statuses = [
+            {'id': 0, 'name': 'claimed'},
+            {'id': 1, 'name': 'allocated'},
+            {'id': 2, 'name': 'conflict'}]
+        # expected_claim_statuses = [
+        #     {'id': 0, 'name': 'tentative'},
+        #     {'id': 1, 'name': 'claimed'},
+        #     {'id': 2, 'name': 'conflict'}]
+
+        claim_statuses = self.radb.getResourceClaimStatuses()
+
+        self.assertEqual(claim_statuses, expected_claim_statuses)
+
+    # TODO: once merged with RT-Task10811 replace the old claim statuses by the new ones
+    def test_getResourceClaimStatusNames_succeeds(self):
+        """ Verifies if radb.getResourceClaimStatusNames() successfully fetches all expected claim status names. """
+
+        expected_claim_status_names = ['claimed', 'allocated', 'conflict']
+        #expected_claim_status_names = ['tentative', 'claimed', 'conflict']
+
+        claim_status_names = self.radb.getResourceClaimStatusNames()
+
+        self.assertEqual(claim_status_names, expected_claim_status_names)
+
+    def test_getResourceClaimStatusId_wrong_claim_name_fails(self):
+        """ Verifies if radb.getResourceClaimStatusId() raises an exception if a claim status id is requested for wrong
+        claim name. """
+
+        wrong_claim_name = 'willywonka'
+
+        self.assertRaises(KeyError, self.radb.getResourceClaimStatusId, wrong_claim_name)
+
+    def test_getResourceClaimStatusId_right_claim_name_succeeds(self):
+        """ Verifies if radb.getResourceClaimStatusId() successfully fetches the expected claim ID for a given claim
+        name. """
+
+        claim_name = 'conflict'
+        expected_claim_id = 2
+
+        claim_id = self.radb.getResourceClaimStatusId(claim_name)
+
+        self.assertEqual(claim_id, expected_claim_id)
+
+    def test_getTasksTimeWindow_no_ids_fails(self):
+        """ Verify if radb.getTasksTimeWindow() raises an exception when called with an empty ID lists for every ID
+        type. """
+
+        self.assertRaises(KeyError, self.radb.getTasksTimeWindow, task_ids=[], mom_ids=[], otdb_ids=[])
+
+    def test_getTasksTimeWindow_multiple_kinds_of_ids_fails(self):
+        """ Verify if radb.getTasksTimeWindow() raises an exception when called with IDs of more than one type. """
+
+        task_ids = [0, 1, 2, 3]
+        mom_ids = [4, 5, 6, 7]
+        otdb_ids = [8, 9, 10, 11]
+
+        self.assertRaises(KeyError, self.radb.getTasksTimeWindow, task_ids, mom_ids, otdb_ids)
+
+    def test_getTasksTimeWindow_empty_ids_list_succeeds(self):
+        """ Verify if radb.getTasksTimeWindow() returns an empty list when requesting a time window for an empty list
+        of IDs. """
+
+        time_windows = [self.radb.getTasksTimeWindow([], None, None),
+                        self.radb.getTasksTimeWindow(None, [], None),
+                        self.radb.getTasksTimeWindow(None, None, [])]
+
+        expected_time_windows = [[], [], []]
+        self.assertItemsEqual(time_windows, expected_time_windows)
+
+    def test_getTasksTimeWindow_empty_db_returns_no_time_window_succeeds(self):
+        """ Verify if radb.getTasksTimeWindow() returns an invalid time window when requesting a time window for a
+        non-existing task. """
+
+        # Ask time window for a non-existing task id
+        time_window = self.radb.getTasksTimeWindow([0], None, None)
+
+        time_window = [time_window['min_starttime'], time_window['max_endtime']]
+        expected_time_window = [None, None]
+        self.assertItemsEqual(time_window, expected_time_window)
+
+    def test_getTasksTimeWindow_normal_use_succeeds(self):
+        """ Verify if radb.getTasksTimeWindow() successfully return the expected time window when requesting a time
+        window for an existing task. """
+
+        # Shoot a task into RADB which time window can later be queried
+        starttime = '2017-05-10 10:00:00'
+        endtime = '2017-05-10 12:00:00'
+        mom_id = 1
+        otdb_id = 2
+        task_id = self.radb.insertSpecificationAndTask(mom_id=mom_id, otdb_id=otdb_id, task_status="prescheduled",
+                                                       task_type="observation", starttime=starttime, endtime=endtime,
+                                                       content="", cluster="CEP4")['task_id']
+
+        # Now query RADB for time_window based on task_id, mom_id, and otdb_id
+        time_windows = [self.radb.getTasksTimeWindow([task_id], None, None),
+                        self.radb.getTasksTimeWindow(None, [mom_id], None),
+                        self.radb.getTasksTimeWindow(None, None, [otdb_id])]
+
+        # The time_window based on task_id, mom_id, and otdb_id should be the same
+        expected_time_windows = 3*[{'max_endtime': parser.parse(endtime), 'min_starttime': parser.parse(starttime)}]
+        self.assertItemsEqual(time_windows, expected_time_windows)
+
+    def test_getTasks_no_ids_fails(self):
+        """ Verify if radb.getTasks() raises an exception when called with an empty ID lists for every ID type. """
+
+        self.assertRaises(KeyError, self.radb.getTasks, task_ids=[], mom_ids=[], otdb_ids=[])
+
+    def test_getTasks_multiple_kinds_of_ids_fails(self):
+        """ Verify if radb.getTasks() raises an exception when called with filled ID lists for multiple ID types. """
+
+        task_ids = [0, 1, 2, 3]
+        mom_ids = [4, 5, 6, 7]
+        otdb_ids = [8, 9, 10, 11]
+
+        self.assertRaises(KeyError, self.radb.getTasks, task_ids=task_ids, mom_ids=mom_ids, otdb_ids=otdb_ids)
+
+    def test_getTasks_empty_ids_list_succeeds(self):
+        tasks = [self.radb.getTasks(task_ids=[], mom_ids=None, otdb_ids=None),
+                 self.radb.getTasks(task_ids=None, mom_ids=[], otdb_ids=None),
+                 self.radb.getTasks(task_ids=None, mom_ids=None, otdb_ids=[])]
+
+        expected_tasks = [[], [], []]
+        self.assertItemsEqual(tasks, expected_tasks)
+
+    def test_getTasks_empty_db_returns_empty_list_succeeds(self):
+        """ Verify if radb.getTasks() successfully returns an empty list when called with a task ID that is non-existing
+        in RADB. """
+
+        tasks = self.radb.getTasks(task_ids=[0])
+
+        self.assertEqual(tasks, [])
+
+    def test_getTasks_normal_use_succeeds(self):
+        """ Verify if radb.getTasks() successfully returns the expected tasks when requesting tasks related to an
+        existing task. """
+
+        # Shoot a task into RADB which can later be fetched
+        task_id = self.radb.insertSpecificationAndTask(mom_id=1, otdb_id=2, task_status="prescheduled",
+                                                       task_type="observation", starttime='2017-05-10 10:00:00',
+                                                       endtime='2017-05-10 12:00:00',
+                                                       content="", cluster="CEP4")['task_id']
+
+        # Now query RADB for the task based on task_id
+        task = self.radb.getTasks(task_ids=[task_id])[0]
+
+        # The task's task ID should be the same to pass this test
+        self.assertEqual(task['id'], task_id)
+
+    def test_getTask_no_ids_fails(self):
+        """ Verify if radb.getTask() raises an exception when called without arguments. """
+
+        self.assertRaises(KeyError, self.radb.getTask)
+
+    def test_getTask_multiple_kinds_of_ids_fails(self):
+        """ Verify if radb.getTask() raises an exception when called with multiple ID types defined. """
+        self.assertRaises(KeyError, self.radb.getTask, 1, 2, 3, 4)
+
+    def test_getTask_empty_db_returns_none_succeeds(self):
+        """ Verify if radb.getTask() successfully returns an None when called with a task ID that doesn't exist in
+        RADB. """
+
+        task = self.radb.getTask(id=0)
+
+        self.assertIsNone(task)
+
+
+    def test_getTask_normal_use_succeeds(self):
+        """ Verify if radb.getTask() successfully returns the expected task when requested to. """
+
+        # Shoot a task into RADB which fetched
+        task_id = self.radb.insertSpecificationAndTask(mom_id=1, otdb_id=2, task_status="prescheduled",
+                                                       task_type="observation", starttime='2017-05-10 10:00:00',
+                                                       endtime='2017-05-10 12:00:00',
+                                                       content="", cluster="CEP4")['task_id']
+
+        task = self.radb.getTask(id=task_id)
+
+        self.assertEqual(task['id'], task_id)
+
+    def test_insertTask_with_invalid_specification_id_raises_exception(self):
+        """ Verify if radb.insertTask() raises an exception when called with non-existing specification ID """
+
+        self.assertRaises(Exception, self.radb.insertTask, 0, 0, 'conflict', 'observation', 1)
+
+    def test_insertTask_with_invalid_id_type_raises_exception(self):
+        """ Verify if radb.insertTask() raises an exception when called with illegal mom_id and otdb_id types """
+
+        # Insert a specification in order to be sure we use a valid specification_id
+        spec_id = self.radb.insertSpecification(starttime='2017-05-10 10:00:00', endtime='2017-05-10 12:00:00',
+                                                         content="", cluster="CEP4")
+
+        self.assertRaises(Exception, self.radb.insertTask, 'monkey see', 'is monkey do', 'conflict', 'observation',
+                          spec_id)
+
+    # TODO : discuss with Jorrit whether this test covers the intent of the insertTask() function. Should it pass?
+    def test_insertTask_with_invalid_id_value_raises_exception(self):
+        """ Verify if radb.insertTask() raises an exception when called with invalid mom_id and otdb_id values """
+
+        # Insert a specification in order to be sure we use a valid specification_id
+        spec_id = self.radb.insertSpecification(starttime='2017-05-10 10:00:00', endtime='2017-05-10 12:00:00',
+                                                content="", cluster="CEP4")
+
+        self.assertRaises(Exception, self.radb.insertTask, -1, -1, 'conflict', 'observation', spec_id)
+
+    def test_insertTask_with_invalid_task_status_raises_exception(self):
+        """ Verify if radb.insertTask() raises an exception when called with invalid task status """
+
+        # Insert a specification in order to be sure we use a valid specification_id
+        specification_id = self.radb.insertSpecification(starttime='2017-05-10 10:00:00',
+                                                         endtime='2017-05-10 12:00:00',
+                                                         content="", cluster="CEP4")
+
+        self.assertRaises(Exception, self.radb.insertTask, 0, 0, 'willywonka', 'observation', specification_id)
+
+    def test_insertTask_with_invalid_task_type_raises_exception(self):
+        """ Verify if radb.insertTask() raises an exception when called with invalid task type """
+
+        # Insert a specification in order to be sure we use a valid specification_id
+        specification_id = self.radb.insertSpecification(starttime='2017-05-10 10:00:00',
+                                                         endtime='2017-05-10 12:00:00',
+                                                         content="", cluster="CEP4")
+
+        self.assertRaises(Exception, self.radb.insertTask, 0, 0, 'conflict', 'willywonka', specification_id)
+
+    def test_insertTask_normal_use_succeeds(self):
+        """ Verify if radb.insertTask() successfully inserts a task when called with valid arguments. """
+
+        sample_starttime = '2017-05-10 10:00:00'
+        sample_endtime = '2017-05-10 12:00:00'
+        sample_task = {
+            'id': 1,
+            'starttime': parser.parse(sample_starttime),
+            'endtime': parser.parse(sample_endtime),
+            'cluster': 'CEP4',
+            'status': 'conflict',
+            'status_id': 335,
+            'type': 'observation',
+            'type_id': 0,
+            'mom_id': 0,
+            'otdb_id': 0,
+            'blocked_by_ids': [],
+            'predecessor_ids': [],
+            'successor_ids': [],
+            'duration': (parser.parse(sample_endtime) - parser.parse(sample_starttime)).seconds,
+        }
+
+        # Insert a specification in order to be sure we use a valid specification_id
+        sample_task['specification_id'] = self.radb.insertSpecification(starttime=sample_starttime,
+                                                                        endtime=sample_endtime,
+                                                                        cluster=sample_task['cluster'],
+                                                                        content='',)
+
+        task_id = self.radb.insertTask(sample_task['mom_id'], sample_task['otdb_id'], sample_task['status'],
+                                       sample_task['type'], sample_task['specification_id'])
+        task = self.radb.getTask(id=task_id)
+
+        self.assertEqual(task, sample_task)
+
+    def test_deleteTask_with_non_excisting_task_id_fails(self):
+        """ Verify if radb.deleteTask() fails when called with a non-excisting task ID. """
+
+        successfully_deleted = self.radb.deleteTask(0)
+
+        self.assertFalse(successfully_deleted)
+
+    # TODO: discuss with Jorrit whether one would expect radb.getSpecification() to NOT return a specification once the
+    # TODO: task has been deleted, since changes to the task table cascades onto that of the specifications?
+    def test_deleteTask_removes_task_and_specification_successfully(self):
+        """ Verify if radb.deleteTask() successfully deletes the expected task and specification when given a task 
+        ID. """
+
+        # Shoot a task and corresponding specification into RADB which can later be deleted
+        task = self.radb.insertSpecificationAndTask(mom_id=1, otdb_id=2, task_status="prescheduled",
+                                                    task_type="observation", starttime='2017-05-10 10:00:00',
+                                                    endtime='2017-05-10 12:00:00', content="", cluster="CEP4")
+        task_id = task['task_id']
+        spec_id = task['specification_id']
+
+        successfully_deleted = self.radb.deleteTask(task_id)
+
+        self.assertTrue(successfully_deleted)
+        self.assertIsNone(self.radb.getTask(id=task_id))
+        # self.assertEqual(self.radb.getSpecification(spec_id), [])
+
+
+
+    # ------------ tests below may overlap with Jorrit's tests in RT-TAsk10811
+
+    def test_insertResourceClaim_when_radb_empty_succeeds(self):
+        spec_and_task_dict = self.radb.insertSpecificationAndTask(mom_id=0, otdb_id=0, task_status="prescheduled",
+                                                       task_type="observation", starttime='2017-05-10 10:00:00',
+                                                       endtime='2017-05-10 12:00:00', content="", cluster="CEP4")
+
+        claim_id = self.radb.insertResourceClaim(resource_id=0, task_id=spec_and_task_dict.get('task_id'),
+                                                 starttime='2017-05-10 10:00:00',
+                                                 endtime='2017-05-10 12:00:00',
+                                                 status="claimed", # <-- change to "tentative" before merging!
+                                                 session_id=1, claim_size=1, username="", user_id=0)
+
+        self.assertIsNotNone(claim_id)
+
+    def test_insertResourceClaim_when_out_of_storage_fails(self):
+        spec_and_task_dict = self.radb.insertSpecificationAndTask(mom_id=0, otdb_id=0, task_status="prescheduled",
+                                                       task_type="observation", starttime='2017-05-10 10:00:00',
+                                                       endtime='2017-05-10 12:00:00', content="", cluster="CEP4")
+        abnormally_huge_claim_size = 1000000000000000000000000000000000000000000000000000000000000000000000000000000000
+
+        claim = {'resource_id': 0,
+                 'starttime': '2017-05-10 10:00:00',
+                 'endtime': '2017-05-10 12:00:00',
+                 'status': 'claimed', # <-- should become tentative before merging!
+                 'claim_size': abnormally_huge_claim_size,
+                 'used_rcus': None}
+
+        claim_ids = self.radb.insertResourceClaims(spec_and_task_dict.get('task_id'), [claim],
+                                                   session_id=1, username="", user_id=0)
+
+        self.assertEqual(claim_ids, [])
 
 
 if __name__ == "__main__":
-- 
GitLab