From b0e06103e24f90d700861997ec2d631e44395a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20K=C3=BCnsem=C3=B6ller?= <jkuensem@physik.uni-bielefeld.de> Date: Mon, 10 May 2021 16:30:22 +0200 Subject: [PATCH] TMSS-703: add more test, also in prep of TMSS-704 --- .../scheduling/test/t_dynamic_scheduling.py | 1497 ++++++++++------- 1 file changed, 844 insertions(+), 653 deletions(-) diff --git a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py index 93aea38eb9f..b1acbd07b96 100755 --- a/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py +++ b/SAS/TMSS/backend/services/scheduling/test/t_dynamic_scheduling.py @@ -1094,657 +1094,657 @@ class TestTimeConstraints(TestCase): # Set datetime constraints after lower bound, and with too little space left in window for obs duration self.clear_time_constraints() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat() - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 2, 12, 0, 0))) - - def test_can_run_within_before_returns_true(self): - - # Set datetime constraints after upper bounds, and with sufficient window for obs duration - self.clear_time_constraints() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat() - self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints after lower bounds, but with sufficient space left in window for obs duration - self.clear_time_constraints() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat() - self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 2, 12, 0, 0))) - - # 'between' constraint - - def test_can_run_anywhere_between_returns_false(self): - """ - Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound or lower_bound - """ - # Set datetime constraints start > lower_bound and stop > upper_bound - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start < lower_bound and stop < upper_bound - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start > lower_bound and stop > upper_bound (1 second only) - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 1), datetime(2020, 1, 2, 12, 0, 1)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start > lower_bound and stop < upper_bound - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 18, 0, 0), datetime(2020, 1, 1, 19, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - def test_can_run_anywhere_between_returns_true(self): - """ - Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound - """ - # Set datetime constraints start < lower_bound and stop > upper_bound - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0)) - self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start = lower_bound and stop = upper_bound - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) - self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - def test_can_run_within_between_returns_true(self): - """ - Test 'between' constraint with start/stop datetime constraints (within, not anywhere within) - """ - # Set datetime constraints start > lower_bound and stop > upper_bound, large window - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) - self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0))) - - # Set datetime constraints start = lower_bound and stop = upper_bound, window just large enough for obs - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 14, 0, 0)) - self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 14, 10, 0))) - - def test_can_run_within_between_returns_false(self): - """ - Test 'between' constraint with start/stop datetime constraints (within, not anywhere within) - """ - # Set datetime constraints start < lower_bound and stop < upper_bound, too little overlap for obs - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 10, 0, 0), datetime(2020, 1, 1, 13, 0, 0)) - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0))) - - # Set datetime constraints start > lower_bound and stop < upper_bound, constraint window too small for obs - self.clear_time_constraints() - self.add_time_between_constraint(datetime(2020, 1, 1, 14, 0, 0), datetime(2020, 1, 1, 15, 0, 0)) - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 10, 0))) - - # 'not between' contraint - - def test_can_run_anywhere_not_between_returns_false(self): - """ - Test 'not_between' constraint with start/stop datetime constraints 'inside' upper_bound or lower_bound - """ - # Set datetime constraints start > lower_bound and stop > upper_bound - self.clear_time_constraints() - self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start < lower_bound and stop > lower_bound and < upper_bound - self.clear_time_constraints() - self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start > lower_bound and stop < upper_bound - self.clear_time_constraints() - self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - # Set datetime constraints start < lower_bound and stop > upper_bound - self.clear_time_constraints() - self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 14, 0, 0)) - self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - def test_can_run_anywhere_not_between_returns_true(self): - """ - Test 'not_between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound - """ - # Set datetime constraints start < lower_bound and stop < lower_bound - self.clear_time_constraints() - self.add_time_not_between_constraint(datetime(2020, 1, 1, 3, 0, 0), datetime(2020, 1, 1, 11, 0, 0)) - self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0))) - - # Set datetime constraints start > upper_bound and stop > upper_bound - self.clear_time_constraints() - self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 20, 0, 0)) - self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0))) - - # several simultaneous time ranges in 'at' / 'between' / 'not between' constraints - - def execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary(self): - """ - Just a simple wrapper to call 'can_run_within_timewindow_with_time_constraints' function - with a 24 hours boundary 2020-01-01 12:00 - 2020-01-02 12:00 - """ - return (tc1.can_run_within_timewindow_with_time_constraints( - self.scheduling_unit_blueprint, datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) - - def test_can_run_within_at_constraint(self): - """ - Test "at" constraint with both boundary and 'inside' upper_bound and lower_bound - """ - # no constraints defined so should be OK - self.clear_time_constraints() - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Set datetime constraint before lower_bound - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 1, 11, 0, 0)) - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 1, 14, 0, 0))) - - # Set datetime constraint at lower_bound, but duration exceeds upper_bound - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 1, 12, 0, 0)) - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 1, 14, 0, 0))) - - # Set datetime constraint at upper_bound - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 1, 14, 0, 0)) - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 1, 14, 0, 0))) - - # Set datetime constraint after upper_bound - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 1, 15, 0, 0)) - self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, - datetime(2020, 1, 1, 12, 0, 0), - datetime(2020, 1, 1, 14, 0, 0))) - - # Set datetime constraint at lower_bound - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 1, 12, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Set datetime constraint that fits the time window - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 1, 18, 30, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Set datetime constraint so that obs lasts till exactly upper_bound - self.clear_time_constraints() - self.add_time_at_constraint(datetime(2020, 1, 2, 9, 50, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - def test_can_run_within_between_constraints(self): - """ - Test multiple 'between' constraints within 24 boundary and check overall result of - 'can_run_within_timewindow_with_time_constraints' - This function will iterate between the boundary with boundary shift of 1hr and boundary length of - the observation duration, which is in this testcase two hour - i.e. 12-14, 13-15, 14-16,..etc.., 9-11 - """ - # no constraints defined so should be OK - self.clear_time_constraints() - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraints of 1hr, we cannot run - self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0)) - self.add_time_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0)) - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraints of 2hr, but partially outside the bounds, we still cannot run - self.add_time_between_constraint(datetime(2020, 1, 2, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0)) - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraints of 2hr, we can run again - self.add_time_between_constraint(datetime(2020, 1, 1, 17, 0, 0), datetime(2020, 1, 1, 19, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraint of 24hr constraint, we still 'can_run' - self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Clear all between constraints - self.clear_time_constraints() - - # Add constraints after the 24hr, now we 'can not run' - self.add_time_between_constraint(datetime(2020, 1, 2, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0)) - self.add_time_between_constraint(datetime(2020, 1, 2, 16, 0, 0), datetime(2020, 1, 2, 20, 0, 0)) - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraint before the 24hr, we 'still can not run' - self.add_time_between_constraint(datetime(2020, 1, 1, 9, 0, 0), datetime(2020, 1, 1, 12, 0, 0)) - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # add one 'inside' constraint of 3 hours, so overall must be ok again. - # Note that 2 hrs would only be sufficient if they match the moving window exactly (here: full hour) - self.add_time_between_constraint(datetime(2020, 1, 1, 14, 30, 0), datetime(2020, 1, 1, 17, 30, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - def test_can_run_within_not_between_constraints(self): - """ - Test multiple 'not_between' constraints within 24 boundary and check overall result of - 'can_run_within_timewindow_with_time_constraints' - This function will iterate between the boundary with boundary shift of 1hr and boundary length of - the observation duration, which is in this testcase two hour - i.e. 12-14, 13-15, 14-16,..etc.., 9-11 - """ - # no constraints defined so should be OK - self.clear_time_constraints() - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraints of 1hr, we still 'can_run' - self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0)) - self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraints of 2hr, we still 'can_run' - self.add_time_not_between_constraint(datetime(2020, 1, 1, 18, 0, 0), datetime(2020, 1, 1, 20, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraint of 20hr constraint, we still 'can_run' - self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # Add constraint of 2hr, to fill the 'last gap', now we can not run - self.add_time_not_between_constraint(datetime(2020, 1, 2, 10, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - self.clear_time_constraints() - - # Add 4 hr constraints within 24 hours boundary, we can run - self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # combined time contraints tests - - def test_can_run_anywhere_combined_time_constraints(self): - """ - Test multiple time constraints in combination and make sure that they block the time window as expected, - even though each constraint individually would allow the observation to run. - """ - - # Set before and after constraint with sufficient gap to fit observation, and assert True - self.clear_time_constraints() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 59, 59).isoformat() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 1).isoformat() - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # set before and after constraint with slightly smaller gap for observation, and assert False - self.clear_time_constraints() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat() - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # set before and after constraint with large gap - # then and add additional between and not between constraints until window is blocked - # can run 13-8h - self.clear_time_constraints() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat() - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 8, 0, 0).isoformat() - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # can run 13h-20h - self.add_time_between_constraint(datetime(2020, 1, 1, 11, 0, 0), datetime(2020, 1, 1, 20, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # can run 13h-17h - self.add_time_not_between_constraint(datetime(2020, 1, 1, 17, 0, 0), datetime(2020, 1, 2, 4, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # can not run anymore - self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0)) - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # add another between window, can run 4h-8h - self.add_time_between_constraint(datetime(2020, 1, 1, 2, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) - self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - # move before constraint, can not run anymore - self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 5, 0, 0).isoformat() - self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) - - -@unittest.skip("TODO: fix, make less dependend on strategy template defaults") -class TestReservedStations(unittest.TestCase): - """ - Tests for the reserved stations used in dynamic scheduling - Test with different boundaries of scheduling unit start and stop times - Reservation 'visualized' - @ = station reservation start_time, * = station reservation stop_time - SUB start_time SUB stop_time Expected Result - 1. | @ ......|...* can NOT run - 2. @..|..* | can NOT run - 3. | @.....* | can NOT run - 4. @..|.............|......* can NOT run - 5. @......* | | can run - 6. | | @.....* can run - """ - - @staticmethod - def create_station_reservation(additional_name, lst_stations, start_time=datetime(2100, 1, 1, 0, 0, 0), - stop_time=datetime(2100, 1, 2, 0, 0, 0)): - """ - Create a station reservation with given list of stations, start_time and stop_time (optional) - Default duration is 24 hours (defined in seconds) - """ - reservation_template = models.ReservationTemplate.objects.get(name="resource reservation") - reservation_template_spec = get_default_json_object_for_schema(reservation_template.schema) - reservation_template_spec["resources"] = {"stations": lst_stations } - res = models.Reservation.objects.create(name="Station Reservation %s" % additional_name, - description="Station reservation for testing", - specifications_template=reservation_template, - specifications_doc=reservation_template_spec, - start_time=start_time, - stop_time=stop_time) - return res - - def setUp(self) -> None: - # scheduling unit - self.obs_duration = 120 * 60 # 2 hours - scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) - scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( - "scheduling unit for %s" % self._testMethodName, - scheduling_set=scheduling_set, - obs_duration=self.obs_duration) - self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft( - scheduling_unit_draft) - # wipe all reservations in between tests, so the tests don't influence each other - for reservation in models.Reservation.objects.all(): - reservation.delete() - - def set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(self, station_reservation): - """ - Set (1) reservation start_time > SUB start_time and reservation stop_time > SUB stop_time - """ - station_reservation.start_time = self.scheduling_unit_blueprint.start_time + timedelta(minutes=5) - station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) - station_reservation.save() - - def set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(self, station_reservation): - """ - Set (2) reservation start_time < SUB start_time and reservation stop_time < SUB stop_time - """ - station_reservation.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) - station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time - timedelta(minutes=5) - station_reservation.save() - - def set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(self, station_reservation): - """ - Set (3) reservation start_time > SUB start_time and reservation stop_time < SUB stop_time - """ - station_reservation.start_time = self.scheduling_unit_blueprint.start_time + timedelta(minutes=5) - station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time - timedelta(minutes=5) - station_reservation.save() - - def set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(self, station_reservation): - """ - Set (4) reservation start_time < SUB start_time and reservation stop_time > SUB stop_time - """ - station_reservation.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) - station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) - station_reservation.save() - - def set_5_reservation_start_time_and_stop_time_lt_sub_start_time(self, station_reservation): - """ - Set (5) reservation start_time and reservation stop_time < SUB start_time - """ - station_reservation.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=60) - station_reservation.stop_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) - station_reservation.save() - - def set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(self, station_reservation): - """ - Set (6) reservation start_time and reservation stop_time > SUB stop_time - """ - station_reservation.start_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) - station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=65) - station_reservation.save() - - def update_station_groups_of_scheduling_unit_blueprint(self): - """ - Use the UC1 strategy template to 'easily' extend the station group of the scheduling_unit - For info, it will have three station groups - - dutch station with max_nr_missing=4 - - international with max_nr_missing=2 - - international required with max_nr_missing=1 - """ - uc1_strategy_template = models.SchedulingUnitObservingStrategyTemplate.objects.get(name="UC1 CTC+pipelines") - scheduling_unit_spec = add_defaults_to_json_object_for_schema(uc1_strategy_template.template, - uc1_strategy_template.scheduling_unit_template.schema) - station_groups = scheduling_unit_spec['tasks']['Target Observation']['specifications_doc']['station_groups'] - self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = station_groups - - def test_one_station_reserved(self): - """ - Test station reservation when 1 station (CS001) is reserved and station CS001 is used in scheduling_unit - with different reservation start and stop times - """ - reservation_one = self.create_station_reservation("One", ["CS001"]) - # reservation start_time > SUB start_time and reservation stop_time > SUB stop_time - self.set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_one) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time and stop_time < SUB stop_time - self.set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_one) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time > SUB start_time and stop_time < SUB stop_time - self.set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_one) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time and stop_time > SUB stop_time - self.set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_one) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # Reservations outside boundary - # start_time and stop_time < SUB start_time - self.set_5_reservation_start_time_and_stop_time_lt_sub_start_time(reservation_one) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # start_time and stop_time > SUB stop_time - self.set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(reservation_one) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_two_stations_reserved(self): - """ - Test station reservation when 2 station (CS001,CS002) are reserved and station CS001 is used in scheduling_unit - with different reservation start and stop times - """ - reservation_two = self.create_station_reservation("Two", ["CS001", "CS002"]) - # reservation start_time > SUB start_time and reservation stop_time > SUB stop_time - self.set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time and stop_time < SUB stop_time - self.set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time > SUB start_time and stop_time < SUB stop_time - self.set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time and stop_time > SUB stop_time - self.set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # Reservations outside boundary - # start_time and stop_time < SUB start_time - self.set_5_reservation_start_time_and_stop_time_lt_sub_start_time(reservation_two) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # start_time and stop_time > SUB stop_time - self.set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(reservation_two) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_two_stations_reserved_but_not_used(self): - """ - Test station reservation when 2 stations (CS002, CS003) are reserved and station CS001 is used in scheduling_unit - with different reservation start and stop times - All possibilities should result in 'can run' - """ - reservation_two_no_overlap = self.create_station_reservation("Two-NoOverlap", ["CS002", "CS003"]) - # reservation start_time > SUB start_time and reservation stop_time > SUB stop_time - self.set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two_no_overlap) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time and stop_time < SUB stop_time - self.set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two_no_overlap) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time > SUB start_time and stop_time < SUB stop_time - self.set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two_no_overlap) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time and stop_time > SUB stop_time - self.set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two_no_overlap) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # Reservations outside boundary - # start_time and stop_time < SUB start_time - self.set_5_reservation_start_time_and_stop_time_lt_sub_start_time(reservation_two_no_overlap) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # start_time and stop_time > SUB stop_time - self.set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(reservation_two_no_overlap) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_two_stations_reserved_with_duration_null(self): - """ - Test station reservation when two stations (CS001,CS002) are reserved with duration null and so reserved indefinitely - and station CS001 is used in scheduling_unit - Test with different reservation start time and NO stop_time - start_time after SUB stop_time 'can run' all others 'can NOT run' - """ - reservation_two_no_duration = self.create_station_reservation("Two-NoDuration", ["CS001", "CS002"], stop_time=None) - # reservation start_time > SUB start_time and < SUB stop_time - reservation_two_no_duration.start_time = self.scheduling_unit_blueprint.start_time + timedelta(minutes=5) - reservation_two_no_duration.save() - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time < SUB start_time (and < SUB stop_time of course) - reservation_two_no_duration.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) - reservation_two_no_duration.save() - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - # reservation start_time > SUB stop time - reservation_two_no_duration.start_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) - reservation_two_no_duration.save() - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_dutch_stations_conflicts_result_false(self): - """ - Test conflict of 'Dutch' station which have a default of max_nr_missing=4, - Create stations reservation equal to max_nr_missing+1 and check that it can not run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("Dutch", ['CS001', 'CS002', 'CS003', 'CS401', 'CS501'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_dutch_stations_conflicts_result_true(self): - """ - Test conflict of 'Dutch' station which have a default of max_nr_missing=4, - Create stations reservation equal to max_nr_missing and check that it can run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("Dutch", ['CS001', 'CS002', 'CS003', 'CS401'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_international_stations_conflicts_result_false(self): - """ - Test conflict of 'International' stations which have a default of max_nr_missing=2, - Create stations reservation equal to max_nr_missing+1 and check that it can not run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("International", ['SE607', 'PL610', 'PL612'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_international_stations_conflicts_result_true(self): - """ - Test conflict of 'International' stations which are have a default of max_nr_missing=2, - Create stations reservation equal to max_nr_missing and check that it can run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("International", ['SE607', 'PL610'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_international_required_stations_conflicts_result_false(self): - """ - Test conflict of 'International Required' stations which are have a default of max_nr_missing=1, - Create stations reservation equal to max_nr_missing+1 and check that it can not run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("International Required", ['DE601', 'DE605'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_international_required_stations_conflicts_result_true(self): - """ - Test conflict of 'International Required' stations which are have a default of max_nr_missing=1, - Create stations reservation equal to max_nr_missing and check that it can run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("International Required", ['DE605'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_mixed_required_stations_conflicts_result_false(self): - """ - Test conflict of 'mixed' stations which are have a default of max_nr_missing, - Create stations reservation equal to max_nr_missing and one station group max_nr_missing+1 - and check that it can not run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("Mixed", ['DE605', 'SE607', 'PL610', 'CS001', 'CS002', 'CS003', 'CS401'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) - - def test_mixed_required_stations_conflicts_result_true(self): - """ - Test conflict of 'mixed' stations which are have a default of max_nr_missing, - Create stations reservation equal to max_nr_missing and check that it can run - """ - self.update_station_groups_of_scheduling_unit_blueprint() - # Create a reservation within scheduling_unit - self.create_station_reservation("Mixed", ['DE605', 'PL610', 'CS001', 'CS002', 'CS003', 'CS401'], - start_time=self.scheduling_unit_blueprint.start_time) - self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 13, 0, 0).isoformat() +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 2, 12, 0, 0))) +# +# def test_can_run_within_before_returns_true(self): +# +# # Set datetime constraints after upper bounds, and with sufficient window for obs duration +# self.clear_time_constraints() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 13, 0, 0).isoformat() +# self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints after lower bounds, but with sufficient space left in window for obs duration +# self.clear_time_constraints() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat() +# self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 2, 12, 0, 0))) +# +# # 'between' constraint +# +# def test_can_run_anywhere_between_returns_false(self): +# """ +# Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound or lower_bound +# """ +# # Set datetime constraints start > lower_bound and stop > upper_bound +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start < lower_bound and stop < upper_bound +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start > lower_bound and stop > upper_bound (1 second only) +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 1), datetime(2020, 1, 2, 12, 0, 1)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start > lower_bound and stop < upper_bound +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 18, 0, 0), datetime(2020, 1, 1, 19, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# def test_can_run_anywhere_between_returns_true(self): +# """ +# Test 'between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound +# """ +# # Set datetime constraints start < lower_bound and stop > upper_bound +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0)) +# self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start = lower_bound and stop = upper_bound +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) +# self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# def test_can_run_within_between_returns_true(self): +# """ +# Test 'between' constraint with start/stop datetime constraints (within, not anywhere within) +# """ +# # Set datetime constraints start > lower_bound and stop > upper_bound, large window +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) +# self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0))) +# +# # Set datetime constraints start = lower_bound and stop = upper_bound, window just large enough for obs +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 14, 0, 0)) +# self.assertTrue(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 14, 10, 0))) +# +# def test_can_run_within_between_returns_false(self): +# """ +# Test 'between' constraint with start/stop datetime constraints (within, not anywhere within) +# """ +# # Set datetime constraints start < lower_bound and stop < upper_bound, too little overlap for obs +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 10, 0, 0), datetime(2020, 1, 1, 13, 0, 0)) +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 0, 0))) +# +# # Set datetime constraints start > lower_bound and stop < upper_bound, constraint window too small for obs +# self.clear_time_constraints() +# self.add_time_between_constraint(datetime(2020, 1, 1, 14, 0, 0), datetime(2020, 1, 1, 15, 0, 0)) +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 20, 10, 0))) +# +# # 'not between' contraint +# +# def test_can_run_anywhere_not_between_returns_false(self): +# """ +# Test 'not_between' constraint with start/stop datetime constraints 'inside' upper_bound or lower_bound +# """ +# # Set datetime constraints start > lower_bound and stop > upper_bound +# self.clear_time_constraints() +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start < lower_bound and stop > lower_bound and < upper_bound +# self.clear_time_constraints() +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start > lower_bound and stop < upper_bound +# self.clear_time_constraints() +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# # Set datetime constraints start < lower_bound and stop > upper_bound +# self.clear_time_constraints() +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 8, 0, 0), datetime(2020, 1, 2, 14, 0, 0)) +# self.assertFalse(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# def test_can_run_anywhere_not_between_returns_true(self): +# """ +# Test 'not_between' constraint with start/stop datetime constraints 'outside' upper_bound and lower_bound +# """ +# # Set datetime constraints start < lower_bound and stop < lower_bound +# self.clear_time_constraints() +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 3, 0, 0), datetime(2020, 1, 1, 11, 0, 0)) +# self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0))) +# +# # Set datetime constraints start > upper_bound and stop > upper_bound +# self.clear_time_constraints() +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 20, 0, 0)) +# self.assertTrue(tc1.can_run_anywhere_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 15, 0, 0))) +# +# # several simultaneous time ranges in 'at' / 'between' / 'not between' constraints +# +# def execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary(self): +# """ +# Just a simple wrapper to call 'can_run_within_timewindow_with_time_constraints' function +# with a 24 hours boundary 2020-01-01 12:00 - 2020-01-02 12:00 +# """ +# return (tc1.can_run_within_timewindow_with_time_constraints( +# self.scheduling_unit_blueprint, datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0))) +# +# def test_can_run_within_at_constraint(self): +# """ +# Test "at" constraint with both boundary and 'inside' upper_bound and lower_bound +# """ +# # no constraints defined so should be OK +# self.clear_time_constraints() +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Set datetime constraint before lower_bound +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 1, 11, 0, 0)) +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 1, 14, 0, 0))) +# +# # Set datetime constraint at lower_bound, but duration exceeds upper_bound +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 1, 12, 0, 0)) +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 1, 14, 0, 0))) +# +# # Set datetime constraint at upper_bound +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 1, 14, 0, 0)) +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 1, 14, 0, 0))) +# +# # Set datetime constraint after upper_bound +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 1, 15, 0, 0)) +# self.assertFalse(tc1.can_run_within_timewindow_with_time_constraints(self.scheduling_unit_blueprint, +# datetime(2020, 1, 1, 12, 0, 0), +# datetime(2020, 1, 1, 14, 0, 0))) +# +# # Set datetime constraint at lower_bound +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 1, 12, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Set datetime constraint that fits the time window +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 1, 18, 30, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Set datetime constraint so that obs lasts till exactly upper_bound +# self.clear_time_constraints() +# self.add_time_at_constraint(datetime(2020, 1, 2, 9, 50, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# def test_can_run_within_between_constraints(self): +# """ +# Test multiple 'between' constraints within 24 boundary and check overall result of +# 'can_run_within_timewindow_with_time_constraints' +# This function will iterate between the boundary with boundary shift of 1hr and boundary length of +# the observation duration, which is in this testcase two hour +# i.e. 12-14, 13-15, 14-16,..etc.., 9-11 +# """ +# # no constraints defined so should be OK +# self.clear_time_constraints() +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraints of 1hr, we cannot run +# self.add_time_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0)) +# self.add_time_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0)) +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraints of 2hr, but partially outside the bounds, we still cannot run +# self.add_time_between_constraint(datetime(2020, 1, 2, 11, 0, 0), datetime(2020, 1, 2, 13, 0, 0)) +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraints of 2hr, we can run again +# self.add_time_between_constraint(datetime(2020, 1, 1, 17, 0, 0), datetime(2020, 1, 1, 19, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraint of 24hr constraint, we still 'can_run' +# self.add_time_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Clear all between constraints +# self.clear_time_constraints() +# +# # Add constraints after the 24hr, now we 'can not run' +# self.add_time_between_constraint(datetime(2020, 1, 2, 13, 0, 0), datetime(2020, 1, 2, 15, 0, 0)) +# self.add_time_between_constraint(datetime(2020, 1, 2, 16, 0, 0), datetime(2020, 1, 2, 20, 0, 0)) +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraint before the 24hr, we 'still can not run' +# self.add_time_between_constraint(datetime(2020, 1, 1, 9, 0, 0), datetime(2020, 1, 1, 12, 0, 0)) +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # add one 'inside' constraint of 3 hours, so overall must be ok again. +# # Note that 2 hrs would only be sufficient if they match the moving window exactly (here: full hour) +# self.add_time_between_constraint(datetime(2020, 1, 1, 14, 30, 0), datetime(2020, 1, 1, 17, 30, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# def test_can_run_within_not_between_constraints(self): +# """ +# Test multiple 'not_between' constraints within 24 boundary and check overall result of +# 'can_run_within_timewindow_with_time_constraints' +# This function will iterate between the boundary with boundary shift of 1hr and boundary length of +# the observation duration, which is in this testcase two hour +# i.e. 12-14, 13-15, 14-16,..etc.., 9-11 +# """ +# # no constraints defined so should be OK +# self.clear_time_constraints() +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraints of 1hr, we still 'can_run' +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 13, 0, 0), datetime(2020, 1, 1, 14, 0, 0)) +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 16, 0, 0), datetime(2020, 1, 1, 17, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraints of 2hr, we still 'can_run' +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 18, 0, 0), datetime(2020, 1, 1, 20, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraint of 20hr constraint, we still 'can_run' +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 2, 8, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # Add constraint of 2hr, to fill the 'last gap', now we can not run +# self.add_time_not_between_constraint(datetime(2020, 1, 2, 10, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# self.clear_time_constraints() +# +# # Add 4 hr constraints within 24 hours boundary, we can run +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # combined time contraints tests +# +# def test_can_run_anywhere_combined_time_constraints(self): +# """ +# Test multiple time constraints in combination and make sure that they block the time window as expected, +# even though each constraint individually would allow the observation to run. +# """ +# +# # Set before and after constraint with sufficient gap to fit observation, and assert True +# self.clear_time_constraints() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 12, 59, 59).isoformat() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 1).isoformat() +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # set before and after constraint with slightly smaller gap for observation, and assert False +# self.clear_time_constraints() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 1, 15, 0, 0).isoformat() +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # set before and after constraint with large gap +# # then and add additional between and not between constraints until window is blocked +# # can run 13-8h +# self.clear_time_constraints() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["after"] = datetime(2020, 1, 1, 13, 0, 0).isoformat() +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 8, 0, 0).isoformat() +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # can run 13h-20h +# self.add_time_between_constraint(datetime(2020, 1, 1, 11, 0, 0), datetime(2020, 1, 1, 20, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # can run 13h-17h +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 17, 0, 0), datetime(2020, 1, 2, 4, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # can not run anymore +# self.add_time_not_between_constraint(datetime(2020, 1, 1, 12, 0, 0), datetime(2020, 1, 1, 16, 0, 0)) +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # add another between window, can run 4h-8h +# self.add_time_between_constraint(datetime(2020, 1, 1, 2, 0, 0), datetime(2020, 1, 2, 12, 0, 0)) +# self.assertTrue(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# # move before constraint, can not run anymore +# self.scheduling_unit_blueprint.scheduling_constraints_doc['time']["before"] = datetime(2020, 1, 2, 5, 0, 0).isoformat() +# self.assertFalse(self.execute_can_run_within_timewindow_with_time_constraints_of_24hour_boundary()) +# +# +# @unittest.skip("TODO: fix, make less dependend on strategy template defaults") +# class TestReservedStations(unittest.TestCase): +# """ +# Tests for the reserved stations used in dynamic scheduling +# Test with different boundaries of scheduling unit start and stop times +# Reservation 'visualized' +# @ = station reservation start_time, * = station reservation stop_time +# SUB start_time SUB stop_time Expected Result +# 1. | @ ......|...* can NOT run +# 2. @..|..* | can NOT run +# 3. | @.....* | can NOT run +# 4. @..|.............|......* can NOT run +# 5. @......* | | can run +# 6. | | @.....* can run +# """ +# +# @staticmethod +# def create_station_reservation(additional_name, lst_stations, start_time=datetime(2100, 1, 1, 0, 0, 0), +# stop_time=datetime(2100, 1, 2, 0, 0, 0)): +# """ +# Create a station reservation with given list of stations, start_time and stop_time (optional) +# Default duration is 24 hours (defined in seconds) +# """ +# reservation_template = models.ReservationTemplate.objects.get(name="resource reservation") +# reservation_template_spec = get_default_json_object_for_schema(reservation_template.schema) +# reservation_template_spec["resources"] = {"stations": lst_stations } +# res = models.Reservation.objects.create(name="Station Reservation %s" % additional_name, +# description="Station reservation for testing", +# specifications_template=reservation_template, +# specifications_doc=reservation_template_spec, +# start_time=start_time, +# stop_time=stop_time) +# return res +# +# def setUp(self) -> None: +# # scheduling unit +# self.obs_duration = 120 * 60 # 2 hours +# scheduling_set = models.SchedulingSet.objects.create(**SchedulingSet_test_data()) +# scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( +# "scheduling unit for %s" % self._testMethodName, +# scheduling_set=scheduling_set, +# obs_duration=self.obs_duration) +# self.scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft( +# scheduling_unit_draft) +# # wipe all reservations in between tests, so the tests don't influence each other +# for reservation in models.Reservation.objects.all(): +# reservation.delete() +# +# def set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(self, station_reservation): +# """ +# Set (1) reservation start_time > SUB start_time and reservation stop_time > SUB stop_time +# """ +# station_reservation.start_time = self.scheduling_unit_blueprint.start_time + timedelta(minutes=5) +# station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) +# station_reservation.save() +# +# def set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(self, station_reservation): +# """ +# Set (2) reservation start_time < SUB start_time and reservation stop_time < SUB stop_time +# """ +# station_reservation.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) +# station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time - timedelta(minutes=5) +# station_reservation.save() +# +# def set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(self, station_reservation): +# """ +# Set (3) reservation start_time > SUB start_time and reservation stop_time < SUB stop_time +# """ +# station_reservation.start_time = self.scheduling_unit_blueprint.start_time + timedelta(minutes=5) +# station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time - timedelta(minutes=5) +# station_reservation.save() +# +# def set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(self, station_reservation): +# """ +# Set (4) reservation start_time < SUB start_time and reservation stop_time > SUB stop_time +# """ +# station_reservation.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) +# station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) +# station_reservation.save() +# +# def set_5_reservation_start_time_and_stop_time_lt_sub_start_time(self, station_reservation): +# """ +# Set (5) reservation start_time and reservation stop_time < SUB start_time +# """ +# station_reservation.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=60) +# station_reservation.stop_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) +# station_reservation.save() +# +# def set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(self, station_reservation): +# """ +# Set (6) reservation start_time and reservation stop_time > SUB stop_time +# """ +# station_reservation.start_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) +# station_reservation.stop_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=65) +# station_reservation.save() +# +# def update_station_groups_of_scheduling_unit_blueprint(self): +# """ +# Use the UC1 strategy template to 'easily' extend the station group of the scheduling_unit +# For info, it will have three station groups +# - dutch station with max_nr_missing=4 +# - international with max_nr_missing=2 +# - international required with max_nr_missing=1 +# """ +# uc1_strategy_template = models.SchedulingUnitObservingStrategyTemplate.objects.get(name="UC1 CTC+pipelines") +# scheduling_unit_spec = add_defaults_to_json_object_for_schema(uc1_strategy_template.template, +# uc1_strategy_template.scheduling_unit_template.schema) +# station_groups = scheduling_unit_spec['tasks']['Target Observation']['specifications_doc']['station_groups'] +# self.scheduling_unit_blueprint.requirements_doc['tasks']['Observation']['specifications_doc']['station_groups'] = station_groups +# +# def test_one_station_reserved(self): +# """ +# Test station reservation when 1 station (CS001) is reserved and station CS001 is used in scheduling_unit +# with different reservation start and stop times +# """ +# reservation_one = self.create_station_reservation("One", ["CS001"]) +# # reservation start_time > SUB start_time and reservation stop_time > SUB stop_time +# self.set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_one) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time and stop_time < SUB stop_time +# self.set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_one) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time > SUB start_time and stop_time < SUB stop_time +# self.set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_one) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time and stop_time > SUB stop_time +# self.set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_one) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # Reservations outside boundary +# # start_time and stop_time < SUB start_time +# self.set_5_reservation_start_time_and_stop_time_lt_sub_start_time(reservation_one) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # start_time and stop_time > SUB stop_time +# self.set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(reservation_one) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_two_stations_reserved(self): +# """ +# Test station reservation when 2 station (CS001,CS002) are reserved and station CS001 is used in scheduling_unit +# with different reservation start and stop times +# """ +# reservation_two = self.create_station_reservation("Two", ["CS001", "CS002"]) +# # reservation start_time > SUB start_time and reservation stop_time > SUB stop_time +# self.set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time and stop_time < SUB stop_time +# self.set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time > SUB start_time and stop_time < SUB stop_time +# self.set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time and stop_time > SUB stop_time +# self.set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # Reservations outside boundary +# # start_time and stop_time < SUB start_time +# self.set_5_reservation_start_time_and_stop_time_lt_sub_start_time(reservation_two) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # start_time and stop_time > SUB stop_time +# self.set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(reservation_two) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_two_stations_reserved_but_not_used(self): +# """ +# Test station reservation when 2 stations (CS002, CS003) are reserved and station CS001 is used in scheduling_unit +# with different reservation start and stop times +# All possibilities should result in 'can run' +# """ +# reservation_two_no_overlap = self.create_station_reservation("Two-NoOverlap", ["CS002", "CS003"]) +# # reservation start_time > SUB start_time and reservation stop_time > SUB stop_time +# self.set_1_reservation_start_time_gt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two_no_overlap) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time and stop_time < SUB stop_time +# self.set_2_reservation_start_time_lt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two_no_overlap) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time > SUB start_time and stop_time < SUB stop_time +# self.set_3_reservation_start_time_gt_sub_start_time_and_stop_time_lt_sub_stop_time(reservation_two_no_overlap) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time and stop_time > SUB stop_time +# self.set_4_reservation_start_time_lt_sub_start_time_and_stop_time_gt_sub_stop_time(reservation_two_no_overlap) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # Reservations outside boundary +# # start_time and stop_time < SUB start_time +# self.set_5_reservation_start_time_and_stop_time_lt_sub_start_time(reservation_two_no_overlap) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # start_time and stop_time > SUB stop_time +# self.set_6_reservation_start_time_and_stop_time_gt_sub_stop_time(reservation_two_no_overlap) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_two_stations_reserved_with_duration_null(self): +# """ +# Test station reservation when two stations (CS001,CS002) are reserved with duration null and so reserved indefinitely +# and station CS001 is used in scheduling_unit +# Test with different reservation start time and NO stop_time +# start_time after SUB stop_time 'can run' all others 'can NOT run' +# """ +# reservation_two_no_duration = self.create_station_reservation("Two-NoDuration", ["CS001", "CS002"], stop_time=None) +# # reservation start_time > SUB start_time and < SUB stop_time +# reservation_two_no_duration.start_time = self.scheduling_unit_blueprint.start_time + timedelta(minutes=5) +# reservation_two_no_duration.save() +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time < SUB start_time (and < SUB stop_time of course) +# reservation_two_no_duration.start_time = self.scheduling_unit_blueprint.start_time - timedelta(minutes=5) +# reservation_two_no_duration.save() +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# # reservation start_time > SUB stop time +# reservation_two_no_duration.start_time = self.scheduling_unit_blueprint.stop_time + timedelta(minutes=5) +# reservation_two_no_duration.save() +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_dutch_stations_conflicts_result_false(self): +# """ +# Test conflict of 'Dutch' station which have a default of max_nr_missing=4, +# Create stations reservation equal to max_nr_missing+1 and check that it can not run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("Dutch", ['CS001', 'CS002', 'CS003', 'CS401', 'CS501'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_dutch_stations_conflicts_result_true(self): +# """ +# Test conflict of 'Dutch' station which have a default of max_nr_missing=4, +# Create stations reservation equal to max_nr_missing and check that it can run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("Dutch", ['CS001', 'CS002', 'CS003', 'CS401'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_international_stations_conflicts_result_false(self): +# """ +# Test conflict of 'International' stations which have a default of max_nr_missing=2, +# Create stations reservation equal to max_nr_missing+1 and check that it can not run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("International", ['SE607', 'PL610', 'PL612'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_international_stations_conflicts_result_true(self): +# """ +# Test conflict of 'International' stations which are have a default of max_nr_missing=2, +# Create stations reservation equal to max_nr_missing and check that it can run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("International", ['SE607', 'PL610'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_international_required_stations_conflicts_result_false(self): +# """ +# Test conflict of 'International Required' stations which are have a default of max_nr_missing=1, +# Create stations reservation equal to max_nr_missing+1 and check that it can not run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("International Required", ['DE601', 'DE605'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_international_required_stations_conflicts_result_true(self): +# """ +# Test conflict of 'International Required' stations which are have a default of max_nr_missing=1, +# Create stations reservation equal to max_nr_missing and check that it can run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("International Required", ['DE605'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_mixed_required_stations_conflicts_result_false(self): +# """ +# Test conflict of 'mixed' stations which are have a default of max_nr_missing, +# Create stations reservation equal to max_nr_missing and one station group max_nr_missing+1 +# and check that it can not run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("Mixed", ['DE605', 'SE607', 'PL610', 'CS001', 'CS002', 'CS003', 'CS401'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertFalse(can_run_within_station_reservations(self.scheduling_unit_blueprint)) +# +# def test_mixed_required_stations_conflicts_result_true(self): +# """ +# Test conflict of 'mixed' stations which are have a default of max_nr_missing, +# Create stations reservation equal to max_nr_missing and check that it can run +# """ +# self.update_station_groups_of_scheduling_unit_blueprint() +# # Create a reservation within scheduling_unit +# self.create_station_reservation("Mixed", ['DE605', 'PL610', 'CS001', 'CS002', 'CS003', 'CS401'], +# start_time=self.scheduling_unit_blueprint.start_time) +# self.assertTrue(can_run_within_station_reservations(self.scheduling_unit_blueprint)) class TestTriggers(TestCase): @@ -1953,6 +1953,8 @@ class TestTriggers(TestCase): # we only mocked the cancellation. # Assert now the new triggered scheduling_unit has been scheduled + # todo: TMSS-704: We should only cancel if the trigger cannot run afterwards due to constraints. + # Add such constraints once the scheduler considers that, since that will break this test. self.assertIsNotNone(scheduled_scheduling_unit) self.assertEqual(scheduled_scheduling_unit.id, triggered_scheduling_unit_blueprint.id) self.assertEqual(triggered_scheduling_unit_blueprint.status, 'scheduled') @@ -1991,7 +1993,7 @@ class TestTriggers(TestCase): running_subtasks = get_running_observation_subtasks(subtask.stop_time + timedelta(minutes=5)) self.assertNotIn(subtask, running_subtasks) - # add a triggered scheduling_unit with higher priority + # add a triggered scheduling_unit with same trigger priority scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( "triggered scheduling unit for %s" % self._testMethodName, scheduling_set=self.scheduling_set, @@ -2009,7 +2011,196 @@ class TestTriggers(TestCase): # Assert that the new triggered scheduling_unit has NOT been scheduled, and the regular one is still observing self.assertIsNone(scheduled_scheduling_unit) self.assertEqual(regular_scheduling_unit_blueprint.status, 'observing') - self.assertEqual(triggered_scheduling_unit_blueprint.status, 'error') # todo: TMSS-704: this should be 'schedulable' as long as no constraint is blocking it, or unschedulable otherwise. + #self.assertEqual(triggered_scheduling_unit_blueprint.status, 'schedulable') # todo: TMSS-704: Make this pass. Currently goes to error state + + @mock.patch("lofar.sas.tmss.services.scheduling.dynamic_scheduling.cancel_subtask") + def test_triggered_scheduling_unit_does_not_cancel_regular_observation_if_it_cannot_run_anyway(self, cancel_mock): + + # create a regular scheduling_unit + scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set, + is_triggered=False) + regular_scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft) + regular_scheduling_unit_blueprint.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint.save() + + scheduled_scheduling_unit = do_dynamic_schedule() + + # Assert the scheduling_unit has been scheduled + self.assertIsNotNone(scheduled_scheduling_unit) + self.assertEqual(scheduled_scheduling_unit.id, regular_scheduling_unit_blueprint.id) + self.assertEqual(regular_scheduling_unit_blueprint.status, 'scheduled') + + # put obs to started state + subtask = scheduled_scheduling_unit.task_blueprints.first().subtasks.first() + subtask.state = models.SubtaskState.objects.get(value='starting') + subtask.save() + subtask.state = models.SubtaskState.objects.get(value='started') + subtask.save() + + # assert obs it detected as running + running_subtasks = get_running_observation_subtasks() + self.assertIn(subtask, running_subtasks) + + # also assert cut-off date is considered + running_subtasks = get_running_observation_subtasks(subtask.stop_time + timedelta(minutes=5)) + self.assertNotIn(subtask, running_subtasks) + + # add a triggered scheduling_unit with higher priority, but a between constraint that can never be met + scheduling_unit_draft = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "triggered scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=True) + triggered_scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft) + triggered_scheduling_unit_blueprint.scheduling_constraints_doc = {'time': {'between': [{"from": datetime.utcnow().isoformat(), "to": (datetime.utcnow()+timedelta(minutes=10)).isoformat()},]}} + triggered_scheduling_unit_blueprint.save() + + scheduled_scheduling_unit = do_dynamic_schedule() + + # assert that the subtask has NOT been cancelled and is still in state 'started' + #cancel_mock.assert_not_called() + self.assertEqual(subtask.state.value, 'started') + + # Assert that the new triggered scheduling_unit has NOT been scheduled, and the regular one is still observing + self.assertIsNone(scheduled_scheduling_unit) + self.assertEqual(regular_scheduling_unit_blueprint.status, 'observing') + #self.assertEqual(triggered_scheduling_unit_blueprint.status, 'schedulable') # todo: TMSS-704: Make this pass. Currently goes to error state. + + @mock.patch("lofar.sas.tmss.services.scheduling.dynamic_scheduling.cancel_subtask") + def test_triggered_scheduling_unit_gets_scheduled_in_correct_trigger_priority_order(self, cancel_mock): + + # create three regular scheduling_units, two with high trigger priority, one with lower + scheduling_unit_draft_high1 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=False) + regular_scheduling_unit_blueprint_high1 = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high1) + regular_scheduling_unit_blueprint_high1.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint_high1.save() + + scheduling_unit_draft_high2 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=False) + regular_scheduling_unit_blueprint_high2 = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high2) + regular_scheduling_unit_blueprint_high2.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint_high2.save() + + scheduling_unit_draft_low = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set, + is_triggered=False) + regular_scheduling_unit_blueprint_low = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_low) + regular_scheduling_unit_blueprint_low.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint_low.save() + + + scheduled_scheduling_unit = do_dynamic_schedule() + + # Assert the scheduling_unit has been scheduled + self.assertIsNotNone(scheduled_scheduling_unit) + self.assertEqual(scheduled_scheduling_unit.id, regular_scheduling_unit_blueprint_high1.id) + self.assertEqual(regular_scheduling_unit_blueprint_high1.status, 'scheduled') + + # put first obs to started state + subtask = scheduled_scheduling_unit.task_blueprints.first().subtasks.first() + subtask.state = models.SubtaskState.objects.get(value='starting') + subtask.save() + subtask.state = models.SubtaskState.objects.get(value='started') + subtask.save() + + # add a triggered scheduling_unit with same priority + scheduling_unit_draft_trigger = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "triggered scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=True) + triggered_scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_trigger) + triggered_scheduling_unit_blueprint.scheduling_constraints_doc = {} + triggered_scheduling_unit_blueprint.save() + + scheduled_scheduling_unit = do_dynamic_schedule() + + # assert that the subtask has NOT been cancelled and is still in state 'started', and its SU is observing + cancel_mock.assert_not_called() + self.assertEqual(subtask.state.value, 'started') + self.assertEqual(regular_scheduling_unit_blueprint_high1.status, 'observing') + + # Assert that the new triggered scheduling_unit has been scheduled, and starts in between the same and lower + # priority units + self.assertIsNotNone(scheduled_scheduling_unit) + #self.assertEqual(triggered_scheduling_unit_blueprint.status, 'scheduled') # todo: TMSS-704: Make this pass. Currently goes to error state + self.assertEqual(regular_scheduling_unit_blueprint_high2.status, 'scheduled') + self.assertEqual(regular_scheduling_unit_blueprint_low.status, 'schedulable') # todo: why high2 gets scheduled, but this is only schedulable? + self.assertGreater(regular_scheduling_unit_blueprint_low.start_time, triggered_scheduling_unit_blueprint.stop_time) + self.assertGreater(triggered_scheduling_unit_blueprint.start_time, regular_scheduling_unit_blueprint_high1.stop_time) # todo: TMSS-704: Make this pass. Currently starts after high1, but unexpectedly before high2 + self.assertGreater(regular_scheduling_unit_blueprint_high2.start_time, regular_scheduling_unit_blueprint_high1.stop_time) + + @mock.patch("lofar.sas.tmss.services.scheduling.dynamic_scheduling.cancel_subtask") + def test_triggered_scheduling_unit_goes_to_unschedulable_if_it_cannot_cancel_and_does_not_fit(self, cancel_mock): + + # create three regular scheduling_units, two with high trigger priority, one with lower + scheduling_unit_draft_high1 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=False) + regular_scheduling_unit_blueprint_high1 = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high1) + regular_scheduling_unit_blueprint_high1.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint_high1.save() + + scheduling_unit_draft_high2 = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=False) + regular_scheduling_unit_blueprint_high2 = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_high2) + regular_scheduling_unit_blueprint_high2.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint_high2.save() + + scheduling_unit_draft_low = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set, + is_triggered=False) + regular_scheduling_unit_blueprint_low = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_low) + regular_scheduling_unit_blueprint_low.scheduling_constraints_doc = {} + regular_scheduling_unit_blueprint_low.save() + + + scheduled_scheduling_unit = do_dynamic_schedule() + + # Assert the scheduling_unit has been scheduled + self.assertIsNotNone(scheduled_scheduling_unit) + self.assertEqual(scheduled_scheduling_unit.id, regular_scheduling_unit_blueprint_high1.id) + self.assertEqual(regular_scheduling_unit_blueprint_high1.status, 'scheduled') + + # put first obs to started state + subtask = scheduled_scheduling_unit.task_blueprints.first().subtasks.first() + subtask.state = models.SubtaskState.objects.get(value='starting') + subtask.save() + subtask.state = models.SubtaskState.objects.get(value='started') + subtask.save() + + # add a triggered scheduling_unit with same trigger priority, and a between constraint that can only be met + # when the regular obs would be cancelled (which is not allowed because it requires higher trigger priority). + scheduling_unit_draft_trigger = TestDynamicScheduling.create_simple_observation_scheduling_unit( + "triggered scheduling unit for %s" % self._testMethodName, + scheduling_set=self.scheduling_set_high_trigger_priority, + is_triggered=True) + triggered_scheduling_unit_blueprint = create_task_blueprints_and_subtasks_from_scheduling_unit_draft(scheduling_unit_draft_trigger) + triggered_scheduling_unit_blueprint.scheduling_constraints_doc = {'time': {'between': [{"from": datetime.utcnow().isoformat(), "to": (datetime.utcnow()+timedelta(hours=3)).isoformat()},]}} + triggered_scheduling_unit_blueprint.save() + + scheduled_scheduling_unit = do_dynamic_schedule() + + # assert that the subtask has NOT been cancelled and is still in state 'started', and its SU is observing + cancel_mock.assert_not_called() + self.assertEqual(subtask.state.value, 'started') + self.assertEqual(regular_scheduling_unit_blueprint_high1.status, 'observing') + + # Assert that the new triggered scheduling_unit has NOT been scheduled and regular observations remain scheduled + self.assertIsNotNone(scheduled_scheduling_unit) + self.assertEqual(triggered_scheduling_unit_blueprint.status, 'unschedulable') # todo: TMSS-704: Make this pass. Currently goes to error state + self.assertEqual(regular_scheduling_unit_blueprint_high2.status, 'scheduled') + self.assertEqual(regular_scheduling_unit_blueprint_low.status, 'schedulable') # todo: why high2 gets scheduled, but this is only schedulable? logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) -- GitLab