Skip to content

Commit

Permalink
more unit tests on observation side of configuration repeats and some…
Browse files Browse the repository at this point in the history
… fixes to go along with is
  • Loading branch information
Jon committed Apr 7, 2022
1 parent 68fc3c0 commit d473e7b
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.0.2 on 2022-04-05 23:26

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('observations', '0006_alter_summary_events'),
]

operations = [
migrations.AlterUniqueTogether(
name='configurationstatus',
unique_together=set(),
),
]
11 changes: 10 additions & 1 deletion observation_portal/observations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ def delete_old_observations(cutoff):
def as_dict(self, no_request=False):
return import_string(settings.AS_DICT['observations']['Observation'])(self, no_request=no_request)

# Returns the current configuration repeat we are within the request for this configuration status
def get_current_repeat(self, configuration_status_id):
num_configurations = self.request.configurations.count()
configuration_status_index = 0
for cs in self.configuration_statuses.all():
if cs.id == configuration_status_id:
break
configuration_status_index += 1
return (configuration_status_index // num_configurations) + 1

@property
def instrument_types(self):
return set(self.request.configurations.values_list('instrument_type', flat=True))
Expand Down Expand Up @@ -234,7 +244,6 @@ def as_dict(self):
return import_string(settings.AS_DICT['observations']['ConfigurationStatus'])(self)

class Meta:
unique_together = ('configuration', 'observation')
verbose_name_plural = 'Configuration statuses'
ordering = ['id']

Expand Down
5 changes: 2 additions & 3 deletions observation_portal/observations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,6 @@ def validate(self, data):
raise serializers.ValidationError(_('Updated exposure start time must be after the observation start time'))
if 'end' in data and 'exposures_start_at' in data:
raise serializers.ValidationError(_('Cannot specify both an end time and an exposures_start_at time'))
if 'current_repeat' in data and (data['current_repeat'] < 1 or data['current_repeat'] > self.instance.observation.request.configuration_repeats):
raise serializers.ValidationError(_(f'The current configuration repeat must be between 1 and {self.instance.observation.request.configuration_repeats}'))
return data

if ('guide_camera_name' in data and
Expand Down Expand Up @@ -78,7 +76,8 @@ def update(self, instance, validated_data):
}
)

current_repeat = validated_data.get('current_repeat', 1)
current_repeat = instance.observation.get_current_repeat(instance.id)

if 'end' in validated_data:
obs_end_time = validated_data['end']
obs_end_time += timedelta(seconds=instance.observation.request.get_remaining_duration(instance.configuration.priority, current_repeat=current_repeat))
Expand Down
157 changes: 157 additions & 0 deletions observation_portal/observations/test/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,6 +993,64 @@ def test_guide_camera_doesnt_match_science_camera_rejected(self):
self.assertEqual(response.status_code, 400)
self.assertIn('xx03 is not a valid guide camera for xx01', str(response.content))

def test_get_current_repeat_from_configuration_status_id(self):
requestgroup = self._generate_requestgroup()
request = requestgroup.requests.first()
create_simple_configuration(request, priority=request.configurations.first().priority + 1)
create_simple_configuration(request, priority=request.configurations.first().priority + 2)
request.configuration_repeats = 5
request.save()
configurations = list(request.configurations.all())

observation = self._generate_observation_data(
request.id,
[
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id
]
)
self._create_observation(observation)
observation = Observation.objects.first()
configuration_statuses = observation.configuration_statuses.all()
self.assertEqual(observation.get_current_repeat(configuration_statuses[2].id), 1)
self.assertEqual(observation.get_current_repeat(configuration_statuses[3].id), 2)
self.assertEqual(observation.get_current_repeat(configuration_statuses[7].id), 3)
self.assertEqual(observation.get_current_repeat(configuration_statuses[10].id), 4)
self.assertEqual(observation.get_current_repeat(configuration_statuses[14].id), 5)

def test_get_all_configurations_from_schedule_endpoint_with_repeat_configurations(self):
requestgroup = self._generate_requestgroup()
request = requestgroup.requests.first()
create_simple_configuration(request, priority=request.configurations.first().priority + 1)
create_simple_configuration(request, priority=request.configurations.first().priority + 2)
request.configuration_repeats = 5
request.save()
configurations = list(request.configurations.all())
expected_configuration_ids = [
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id,
configurations[0].id, configurations[1].id, configurations[2].id
]
observation = self._generate_observation_data(
request.id,
expected_configuration_ids
)
self._create_observation(observation)
response = self.client.get(reverse('api:schedule-list'))
observation = response.json()['results'][0]

# Ensure configurations are repeated, and configuration statuses are ascending
previous_configuration_status_id = 0
for i, configuration in enumerate(observation['request']['configurations']):
self.assertEqual(expected_configuration_ids[i], configuration['id'])
self.assertGreater(configuration['configuration_status'], previous_configuration_status_id)
previous_configuration_status_id = configuration['configuration_status']


class TestUpdateConfigurationStatusApi(TestObservationApiBase):
def setUp(self):
Expand Down Expand Up @@ -1176,6 +1234,80 @@ def test_update_configuration_status_end_time_succeeds(self):
observation = Observation.objects.first()
self.assertEqual(observation.end, new_end)

def test_update_configuration_status_end_time_with_repeat_configurations_succeeds(self):
requestgroup = self._generate_requestgroup()
request = requestgroup.requests.first()
create_simple_configuration(request, priority=request.configurations.first().priority + 1)
request.configuration_repeats = 3
request.save()
configurations = list(request.configurations.all())
configuration_1_duration = configurations[0].duration
configuration_2_duration = configurations[1].duration

observation = self._generate_observation_data(
request.id,
[configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id]
)
self._create_observation(observation)
configuration_statuses = ConfigurationStatus.objects.all()
new_config_end = datetime(2016, 9, 5, 23, 47, 22).replace(tzinfo=timezone.utc)
update_data = {"end": datetime.strftime(new_config_end, '%Y-%m-%dT%H:%M:%SZ')}
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_statuses[0].id,)), update_data)
observation = Observation.objects.first()
slew_and_oe_switching_time = 10 # 3 * minimum slew of 2s + 2 * oe change time of 2s
new_observation_end = new_config_end + timedelta(seconds=(configuration_1_duration*2 + configuration_2_duration*3 + slew_and_oe_switching_time))
self.assertEqual(observation.end, new_observation_end)

def test_update_configuration_status_end_time_with_repeat_configurations_mid_repeat_succeeds(self):
requestgroup = self._generate_requestgroup()
request = requestgroup.requests.first()
create_simple_configuration(request, priority=request.configurations.first().priority + 1)
request.configuration_repeats = 3
request.save()
configurations = list(request.configurations.all())
configuration_1_duration = configurations[0].duration
configuration_2_duration = configurations[1].duration

observation = self._generate_observation_data(
request.id,
[configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id]
)
self._create_observation(observation)
configuration_statuses = ConfigurationStatus.objects.all()
new_config_end = datetime(2016, 9, 5, 23, 47, 22).replace(tzinfo=timezone.utc)
update_data = {"end": datetime.strftime(new_config_end, '%Y-%m-%dT%H:%M:%SZ')}
# Updating configuration status 2, so there should be 3 left to add to end time
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_statuses[2].id,)), update_data)
observation = Observation.objects.first()
slew_and_oe_switching_time = 6 # 2 * minimum slew of 2s + 1 * oe change time of 2s
new_observation_end = new_config_end + timedelta(seconds=(configuration_1_duration*1 + configuration_2_duration*2 + slew_and_oe_switching_time))
self.assertEqual(observation.end, new_observation_end)

def test_update_configuration_status_update_start_time_with_repeat_configurations_last_repeat_succeeds(self):
requestgroup = self._generate_requestgroup()
request = requestgroup.requests.first()
create_simple_configuration(request, priority=request.configurations.first().priority + 1)
request.configuration_repeats = 3
request.save()
configurations = list(request.configurations.all())
configuration_1_duration = configurations[0].duration
configuration_2_duration = configurations[1].duration

observation = self._generate_observation_data(
request.id,
[configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id]
)
self._create_observation(observation)
configuration_statuses = ConfigurationStatus.objects.all()
new_config_start = datetime(2016, 9, 5, 23, 47, 22).replace(tzinfo=timezone.utc)
update_data = {"exposures_start_at": datetime.strftime(new_config_start, '%Y-%m-%dT%H:%M:%SZ')}
# Updating configuration status 2, so there should be 3 left to add to end time
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_statuses[4].id,)), update_data)
observation = Observation.objects.first()
config_front_padding = 14 # not used for the current configuration 16s front padding - 2s oe change time
new_observation_end = new_config_start + timedelta(seconds=(configuration_1_duration*1 + configuration_2_duration*1 - config_front_padding))
self.assertEqual(observation.end, new_observation_end)

def test_update_configuration_status_exposure_start_time_succeeds(self):
observation = self._generate_observation_data(
self.requestgroup.requests.first().id, [self.requestgroup.requests.first().configurations.first().id]
Expand Down Expand Up @@ -1254,6 +1386,31 @@ def test_shorten_first_configuration_status_exposure_start_with_multiple_configs
configuration_status.configuration.priority, include_current=True))
self.assertEqual(observation.end, new_obs_end)

def test_shorten_first_configuration_status_exposure_start_with_repeat_configurations_multiple_configs(self):
requestgroup = self._generate_requestgroup()
request = requestgroup.requests.first()
create_simple_configuration(request, priority=request.configurations.first().priority + 1)
request.configuration_repeats = 3
request.save()
configurations = list(request.configurations.all())
configuration_1_duration = configurations[0].duration
configuration_2_duration = configurations[1].duration

observation = self._generate_observation_data(
request.id,
[configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id, configurations[0].id, configurations[1].id]
)
self._create_observation(observation)
configuration_statuses = ConfigurationStatus.objects.all()
new_config_start = datetime(2016, 9, 5, 22, 35, 45).replace(tzinfo=timezone.utc)
update_data = {"exposures_start_at": datetime.strftime(new_config_start, '%Y-%m-%dT%H:%M:%SZ')}
# Updating configuration status 1, so there should be 4 left to add to end time
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_statuses[1].id,)), update_data)
observation = Observation.objects.first()
config_front_padding = 8 # not used for the current configuration 16s front padding - 2*2s minimum slew and 2*2s oe change time
new_observation_end = new_config_start + timedelta(seconds=(configuration_1_duration*2 + configuration_2_duration*3 - config_front_padding))
self.assertEqual(observation.end, new_observation_end)

def test_configuration_status_exposure_start_cant_be_before_observation_start(self):
observation = self._generate_observation_data(self.requestgroup.requests.first().id,
[self.requestgroup.requests.first().configurations.first().id]
Expand Down

0 comments on commit d473e7b

Please sign in to comment.