Skip to content

Commit

Permalink
Merge a8fd200 into fcdbd8c
Browse files Browse the repository at this point in the history
  • Loading branch information
jnation3406 committed Oct 14, 2019
2 parents fcdbd8c + a8fd200 commit b3e0933
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 87 deletions.
8 changes: 4 additions & 4 deletions observation_portal/common/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def create_simple_requestgroup(user, proposal, state='PENDING', request=None, wi
location.save()

if not configuration:
configuration = mixer.blend(Configuration, request=request)
configuration = mixer.blend(Configuration, request=request, priority=1)
else:
configuration.request = request
configuration.save()
Expand All @@ -94,8 +94,8 @@ def create_simple_many_requestgroup(user, proposal, n_requests, state='PENDING')
return rg


def create_simple_configuration(request, instrument_type='1M0-SCICAM-SBIG', instrument_config=None):
configuration = mixer.blend(Configuration, request=request, instrument_type=instrument_type)
def create_simple_configuration(request, instrument_type='1M0-SCICAM-SBIG', instrument_config=None, priority=1):
configuration = mixer.blend(Configuration, request=request, instrument_type=instrument_type, priority=priority)
fill_in_configuration_structures(configuration, instrument_config=instrument_config)
return configuration

Expand Down Expand Up @@ -127,7 +127,7 @@ def fill_in_configuration_structures(configuration, instrument_config=None, cons
acquisition_config.save()

if not target:
mixer.blend(Target, configuration=configuration)
mixer.blend(Target, configuration=configuration, ra=11.1, dec=11.1)
else:
target.configuration = configuration
target.save()
31 changes: 30 additions & 1 deletion observation_portal/observations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
from django.contrib.postgres.fields import JSONField
from django.forms.models import model_to_dict
from django.utils import timezone
from django.core.cache import cache
from datetime import timedelta

from observation_portal.requestgroups.models import Request, Configuration
from observation_portal.requestgroups.models import Request, RequestGroup, Configuration
import logging

logger = logging.getLogger()
Expand Down Expand Up @@ -75,6 +76,34 @@ def cancel(observations):

return deleted_observations.get('observations.Observation', 0) + canceled + aborted

def update_end_time(self, new_end_time):
if new_end_time > self.start:
# Only update the end time if it is > start time
old_end_time = self.end
self.end = new_end_time
self.save()
# Cancel observations that used to be under this observation
if new_end_time > old_end_time:
observations = Observation.objects.filter(
site=self.site,
enclosure=self.enclosure,
telescope=self.telescope,
start__lte=self.end,
start__gte=old_end_time,
state='PENDING'
)
if self.request.request_group.observation_type != RequestGroup.RAPID_RESPONSE:
observations = observations.exclude(
request__request_group__observation_type=RequestGroup.RAPID_RESPONSE
)
num_canceled = Observation.cancel(observations)
logger.info(
f"updated end time for observation {self.id} to {self.end}. "
f"Canceled {num_canceled} overlapping observations."
)
cache.set('observation_portal_last_change_time', timezone.now(), None)
return self

@staticmethod
def delete_old_observations(cutoff):
observations = Observation.objects.filter(start__lt=cutoff, end__lt=cutoff, state='CANCELED').exclude(
Expand Down
40 changes: 12 additions & 28 deletions observation_portal/observations/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import logging

from datetime import timedelta

logger = logging.getLogger()


Expand All @@ -27,6 +29,7 @@ class ConfigurationStatusSerializer(serializers.ModelSerializer):
summary = SummarySerializer(required=False)
instrument_name = serializers.CharField(required=False)
guide_camera_name = serializers.CharField(required=False)
end = serializers.DateTimeField(required=False)

class Meta:
model = ConfigurationStatus
Expand All @@ -35,7 +38,9 @@ class Meta:
def validate(self, data):
data = super().validate(data)
if self.context.get('request').method == 'PATCH':
# For a partial update, don't try to validate the field set
# For a partial update, only validate the end time if its set
if 'end' in data and data['end'] <= timezone.now():
raise serializers.ValidationError(_('Updated end time must be in the future'))
return data

if ('guide_camera_name' in data and
Expand Down Expand Up @@ -66,6 +71,11 @@ def update(self, instance, validated_data):
}
)

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))
instance.observation.update_end_time(obs_end_time)

return instance


Expand Down Expand Up @@ -359,33 +369,7 @@ def validate(self, data):
return data

def update(self, instance, validated_data):
if validated_data['end'] > instance.start:
# Only update the end time if it is > start time
old_end_time = instance.end
instance.end = validated_data['end']
instance.save()
# Cancel observations that used to be under this observation
if instance.end > old_end_time:
observations = Observation.objects.filter(
site=instance.site,
enclosure=instance.enclosure,
telescope=instance.telescope,
start__lte=instance.end,
start__gte=old_end_time,
state='PENDING'
)
if instance.request.request_group.observation_type != RequestGroup.RAPID_RESPONSE:
observations = observations.exclude(
request__request_group__observation_type=RequestGroup.RAPID_RESPONSE
)
num_canceled = Observation.cancel(observations)
logger.info(
f"updated end time for observation {instance.id} to {instance.end}. "
f"Canceled {num_canceled} overlapping observations."
)
cache.set('observation_portal_last_change_time', timezone.now(), None)

return instance
return instance.update_end_time(validated_data['end'])

def create(self, validated_data):
configuration_statuses = validated_data.pop('configuration_statuses')
Expand Down
66 changes: 66 additions & 0 deletions observation_portal/observations/test/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,72 @@ def test_update_summary_triggers_request_status_without_completing(self):
self.requestgroup.refresh_from_db()
self.assertEqual(self.requestgroup.state, 'PENDING')

def test_update_configuration_status_end_time_succeeds(self):
original_end = datetime(2016, 9, 5, 23, 35, 40).replace(tzinfo=timezone.utc)
observation = self._generate_observation_data(
self.requestgroup.requests.first().id, [self.requestgroup.requests.first().configurations.first().id]
)
self._create_observation(observation)
configuration_status = ConfigurationStatus.objects.first()

new_end = datetime(2016, 9, 5, 23, 47, 22).replace(tzinfo=timezone.utc)
update_data = {"end": datetime.strftime(new_end, '%Y-%m-%dT%H:%M:%SZ')}
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_status.id,)), update_data)
observation = Observation.objects.first()
self.assertEqual(observation.end, new_end)

def test_lengthen_first_configuration_status_end_time_with_multiple_configs(self):
original_end = datetime(2016, 9, 5, 23, 35, 40).replace(tzinfo=timezone.utc)
create_simple_configuration(self.requestgroup.requests.first(), priority=2)
create_simple_configuration(self.requestgroup.requests.first(), priority=3)
configuration_ids = [config.id for config in self.requestgroup.requests.first().configurations.all()]
observation = self._generate_observation_data(self.requestgroup.requests.first().id, configuration_ids)
self._create_observation(observation)
configuration_status = ConfigurationStatus.objects.first()

new_end = datetime(2016, 9, 5, 23, 47, 22).replace(tzinfo=timezone.utc)
update_data = {"end": datetime.strftime(new_end, '%Y-%m-%dT%H:%M:%SZ')}
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_status.id,)), update_data)
observation = Observation.objects.first()
new_obs_end = new_end + timedelta(seconds=self.requestgroup.requests.first().get_remaining_duration(
configuration_status.configuration.priority))
self.assertEqual(observation.end, new_obs_end)

def test_shorten_first_configuration_status_end_time_with_multiple_configs(self):
original_end = datetime(2016, 9, 5, 23, 35, 40).replace(tzinfo=timezone.utc)
create_simple_configuration(self.requestgroup.requests.first(), priority=2)
create_simple_configuration(self.requestgroup.requests.first(), priority=3)
configuration_ids = [config.id for config in self.requestgroup.requests.first().configurations.all()]
observation = self._generate_observation_data(self.requestgroup.requests.first().id, configuration_ids)
self._create_observation(observation)
configuration_status = ConfigurationStatus.objects.first()

new_end = datetime(2016, 9, 5, 23, 13, 31).replace(tzinfo=timezone.utc)
update_data = {"end": datetime.strftime(new_end, '%Y-%m-%dT%H:%M:%SZ')}
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_status.id,)), update_data)
observation = Observation.objects.first()
new_obs_end = new_end + timedelta(seconds=self.requestgroup.requests.first().get_remaining_duration(
configuration_status.configuration.priority))
self.assertEqual(observation.end, new_obs_end)

def test_update_last_configuration_status_end_time_is_same_as_obs_end(self):
original_end = datetime(2016, 9, 5, 23, 35, 40).replace(tzinfo=timezone.utc)
create_simple_configuration(self.requestgroup.requests.first(), priority=2)
create_simple_configuration(self.requestgroup.requests.first(), priority=3)
configuration_ids = [config.id for config in self.requestgroup.requests.first().configurations.all()]
observation = self._generate_observation_data(self.requestgroup.requests.first().id, configuration_ids)
self._create_observation(observation)
configuration_status = ConfigurationStatus.objects.last()

new_end = datetime(2016, 9, 5, 23, 47, 22).replace(tzinfo=timezone.utc)
update_data = {"end": datetime.strftime(new_end, '%Y-%m-%dT%H:%M:%SZ')}
self.client.patch(reverse('api:configurationstatus-detail', args=(configuration_status.id,)), update_data)
observation = Observation.objects.first()
new_obs_end = new_end + timedelta(seconds=self.requestgroup.requests.first().get_remaining_duration(
configuration_status.configuration.priority))
self.assertEqual(new_obs_end, new_end)
self.assertEqual(observation.end, new_obs_end)


class TestUpdateObservationApi(TestObservationApiBase):
def setUp(self):
Expand Down

0 comments on commit b3e0933

Please sign in to comment.