Example #1
0
def test_determine_event_status_far_with_ramp_up():
    active_period = {
        'dtstart': datetime.now(timezone.utc) + timedelta(seconds=10),
        'duration': timedelta(seconds=5),
        'ramp_up_period': timedelta(seconds=5)
    }
    assert utils.determine_event_status(active_period) == 'far'
Example #2
0
 async def _event_cleanup(self):
     """
     Periodic task that will clean up completed and cancelled events in our memory.
     """
     for event in self.received_events:
         if event['event_descriptor']['event_status'] == 'cancelled' or \
                 utils.determine_event_status(event['active_period']) == 'completed':
             logger.info(f"Removing event {event} because it is no longer relevant.")
             self.received_events.pop(self.received_events.index(event))
Example #3
0
 def __post_init__(self):
     if self.active_period is None:
         dtstart = min([
             i['dtstart'] if isinstance(i, dict) else i.dtstart
             for s in self.event_signals for i in s.intervals
         ])
         duration = max([
             i['dtstart'] + i['duration']
             if isinstance(i, dict) else i.dtstart + i.duration
             for s in self.event_signals for i in s.intervals
         ]) - dtstart
         self.active_period = ActivePeriod(dtstart=dtstart,
                                           duration=duration)
     if self.targets is None and self.targets_by_type is None:
         raise ValueError(
             "You must supply either 'targets' or 'targets_by_type'.")
     elif self.targets_by_type is None:
         list_of_targets = [
             asdict(target) if is_dataclass(target) else target
             for target in self.targets
         ]
         self.targets_by_type = utils.group_targets_by_type(list_of_targets)
     elif self.targets is None:
         self.targets = [
             Target(**target) for target in utils.ungroup_targets_by_type(
                 self.targets_by_type)
         ]
     elif self.targets is not None and self.targets_by_type is not None:
         list_of_targets = [
             asdict(target) if is_dataclass(target) else target
             for target in self.targets
         ]
         if utils.group_targets_by_type(
                 list_of_targets) != self.targets_by_type:
             raise ValueError(
                 "You assigned both 'targets' and 'targets_by_type' in your event, "
                 "but the two were not consistent with each other. "
                 f"You supplied 'targets' = {self.targets} and "
                 f"'targets_by_type' = {self.targets_by_type}")
     # Set the event status
     self.event_descriptor.event_status = utils.determine_event_status(
         self.active_period)
Example #4
0
def test_determine_event_status_active():
    active_period = {
        'dtstart': datetime.now(timezone.utc) - timedelta(seconds=10),
        'duration': timedelta(seconds=15)
    }
    assert utils.determine_event_status(active_period) == 'active'
Example #5
0
    async def _on_event(self, message):
        logger.debug("The VEN received an event")
        events = message['events']
        try:
            results = []
            for event in message['events']:
                event_id = event['event_descriptor']['event_id']
                event_status = event['event_descriptor']['event_status']
                modification_number = event['event_descriptor']['modification_number']
                received_event = utils.find_by(self.received_events, 'event_descriptor.event_id', event_id)
                if received_event:
                    if received_event['event_descriptor']['modification_number'] == modification_number:
                        # Re-submit the same opt type as we already had previously
                        result = self.responded_events[event_id]
                    else:
                        # Replace the event with the fresh copy
                        utils.pop_by(self.received_events, 'event_descriptor.event_id', event_id)
                        self.received_events.append(event)
                        # Wait for the result of the on_update_event handler
                        result = await utils.await_if_required(self.on_update_event(event))
                else:
                    # Wait for the result of the on_event
                    self.received_events.append(event)
                    result = self.on_event(event)
                if asyncio.iscoroutine(result):
                    result = await result
                results.append(result)
                if event_status in (enums.EVENT_STATUS.COMPLETED, enums.EVENT_STATUS.CANCELLED) and event_id in self.responded_events:
                    self.responded_events.pop(event_id)
                else:
                    self.responded_events[event_id] = result
            for i, result in enumerate(results):
                if result not in ('optIn', 'optOut') and events[i]['response_required'] == 'always':
                    logger.error("Your on_event or on_update_event handler must return 'optIn' or 'optOut'; "
                                 f"you supplied {result}. Please fix your on_event handler.")
                    results[i] = 'optOut'
        except Exception as err:
            logger.error("Your on_event handler encountered an error. Will Opt Out of the event. "
                         f"The error was {err.__class__.__name__}: {str(err)}")
            results = ['optOut'] * len(events)

        event_responses = [{'response_code': 200,
                            'response_description': 'OK',
                            'opt_type': results[i],
                            'request_id': message['request_id'],
                            'modification_number': events[i]['event_descriptor']['modification_number'],
                            'event_id': events[i]['event_descriptor']['event_id']}
                           for i, event in enumerate(events)
                           if event['response_required'] == 'always'
                           and not utils.determine_event_status(event['active_period']) == 'completed']

        if len(event_responses) > 0:
            logger.info(f"Total event_responses: {len(event_responses)}")
            response = {'response_code': 200,
                        'response_description': 'OK',
                        'request_id': message['request_id']}
            message = self._create_message('oadrCreatedEvent',
                                           response=response,
                                           event_responses=event_responses,
                                           ven_id=self.ven_id)
            service = 'EiEvent'
            response_type, response_payload = await self._perform_request(service, message)
            logger.info(response_type, response_payload)
        else:
            logger.info("Not sending any event responses, because a response was not required/allowed by the VTN.")