Example #1
0
def test_conflict_override_success_running_agent():
    print('Test conflicting requests: Agent2 overrides running Agent1', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1',
           (['campus/building/rtu1', parse('2013-11-27 12:00:00'),
             parse('2013-11-27 12:35:00')],),
           PRIORITY_LOW_PREEMPT,
           now)
    now2 = now + timedelta(minutes=45)
    ag2 = ('Agent2', 'Task2',
           (['campus/building/rtu1', parse('2013-11-27 12:05:00'),
             parse('2013-11-27 13:00:00')],),
           PRIORITY_HIGH,
           now2)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert success2
    assert data2 == {('Agent1', 'Task1')}
    assert info_string2 == ''
    assert event_time2 == parse('2013-11-27 12:16:00')

    state = sch_man.get_schedule_state(now2 + timedelta(seconds=30))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 30.0)}
    state = sch_man.get_schedule_state(now2 + timedelta(seconds=60))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent2', 'Task2', 2640.0)}
Example #2
0
def test_touching_requests():
    print('Test touching requests: Two agents', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 12:30:00')
    ], ), PRIORITY_HIGH, now)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_HIGH, now)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert all((success2, not data2, not info_string2,
                event_time2 == parse('2013-11-27 12:00:00')))

    state = sch_man.get_schedule_state(now + timedelta(minutes=30))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 1800.0)
    }
    state = sch_man.get_schedule_state(now + timedelta(minutes=60))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent2', 'Task2', 1800.0)
    }
Example #3
0
def test_conflict_override_success_running_agent():
    print('Test conflicting requests: Agent2 overrides running Agent1', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 12:35:00')
    ], ), PRIORITY_LOW_PREEMPT, now)
    now2 = now + timedelta(minutes=45)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:05:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_HIGH, now2)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert success2
    assert data2 == {('Agent1', 'Task1')}
    assert info_string2 == ''
    assert event_time2 == parse('2013-11-27 12:16:00')

    state = sch_man.get_schedule_state(now2 + timedelta(seconds=30))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 30.0)
    }
    state = sch_man.get_schedule_state(now2 + timedelta(seconds=60))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent2', 'Task2', 2640.0)
    }
Example #4
0
def test_touching_requests():
    print('Test touching requests: Two agents', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1',
           (['campus/building/rtu1', parse('2013-11-27 12:00:00'),
             parse('2013-11-27 12:30:00')],),
           PRIORITY_HIGH,
           now)
    ag2 = ('Agent2', 'Task2',
           (['campus/building/rtu1', parse('2013-11-27 12:30:00'),
             parse('2013-11-27 13:00:00')],),
           PRIORITY_HIGH,
           now)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert all((success2, not data2, not info_string2,
                event_time2 == parse('2013-11-27 12:00:00')))

    state = sch_man.get_schedule_state(now + timedelta(minutes=30))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 1800.0)}
    state = sch_man.get_schedule_state(now + timedelta(minutes=60))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent2', 'Task2', 1800.0)}
Example #5
0
def test_two_devices():
    print('Basic Test: Two devices', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 13:00:00')
    ], [
        'campus/building/rtu2',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 13:00:00')
    ]), PRIORITY_HIGH, now)
    result1, event_time1 = verify_add_task(sch_man, *ag)
    success, data, info_string = result1
    assert all((success, not data, not info_string,
                event_time1 == parse('2013-11-27 12:00:00')))

    state = sch_man.get_schedule_state(now + timedelta(minutes=30))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 3600.0),
        'campus/building/rtu2': DeviceState('Agent1', 'Task1', 3600.0)
    }
    state = sch_man.get_schedule_state(now + timedelta(minutes=60))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 1800.0),
        'campus/building/rtu2': DeviceState('Agent1', 'Task1', 1800.0)
    }
Example #6
0
        def setup_schedule(self):
            now = datetime.datetime.now()
            self._schedule_manager = ScheduleManager(
                preempt_grace_time,
                now=now,
                state_file_name=schedule_state_file)

            self.update_device_state_and_schedule(now)
Example #7
0
def test_conflict_override_error():
    print(
        'Test conflicting requests: '
        'Agent2 fails to override running Agent1 '
        'because of non high priority.', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 12:35:00')
    ], ), PRIORITY_LOW_PREEMPT, now)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_LOW, now)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    conflicts2 = data2
    assert not success2
    assert conflicts2 == {
        'Agent1': {
            'Task1': [[
                'campus/building/rtu1', '2013-11-27 12:00:00',
                '2013-11-27 12:35:00'
            ]]
        }
    }
Example #8
0
def test_conflict_override_fail_on_running_agent():
    print('Test conflicting requests: Agent2 fails to override running Agent1',
          now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 12:35:00')
    ], ), PRIORITY_LOW, now)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_HIGH, now + timedelta(minutes=45))
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1

    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    conflicts2 = data2
    assert not success2
    assert conflicts2 == {
        'Agent1': {
            'Task1': [[
                'campus/building/rtu1', '2013-11-27 12:00:00',
                '2013-11-27 12:35:00'
            ]]
        }
    }
Example #9
0
def test_malformed_schedule():
    print('Testing malformed schedule: Empty', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1', (), PRIORITY_HIGH, now)

    result1, event_time1 = verify_add_task(sch_man, *ag)
    success1, data1, info_string1 = result1
    assert all((not success1, data1 == {},
                info_string1.startswith('MALFORMED_REQUEST')))
Example #10
0
def test_malformed_bad_device():
    print('Testing malformed schedule: Bad device', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1',
          ([1, parse('2013-11-27 12:00:00'),
            parse('2013-11-27 12:35:00')], ), PRIORITY_HIGH, now)
    result1, event_time1 = verify_add_task(sch_man, *ag)
    success1, data1, info_string1 = result1
    assert all((not success1, data1 == {},
                info_string1.startswith('MALFORMED_REQUEST')))
Example #11
0
def test_malformed_schdeule_bad_timestr():
    print('Testing malformed schedule: Bad time strings', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1', ([
        'campus/building/rtu1', 'fdhkdfyug', 'Twinkle, twinkle, little bat...'
    ], ), PRIORITY_HIGH, now)

    result1, event_time1 = verify_add_task(sch_man, *ag)
    success1, data1, info_string1 = result1
    assert all((not success1, data1 == {},
                info_string1.startswith('MALFORMED_REQUEST')))
Example #12
0
def test_basic():
    print('Basic Test', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1',
          (['campus/building/rtu1', parse('2013-11-27 12:00:00'),
            parse('2013-11-27 13:00:00')],),
          PRIORITY_HIGH,
          now)
    result1, event_time1 = verify_add_task(sch_man, *ag)
    success, data, info_string = result1
    # success1, data1, info_string1 = result1
    assert all((success, not data, not info_string,
                event_time1 == parse('2013-11-27 12:00:00')))

    state = sch_man.get_schedule_state(now + timedelta(minutes=30))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 3600.0)}
    state = sch_man.get_schedule_state(now + timedelta(minutes=60))
    assert state == {
        'campus/building/rtu1': DeviceState('Agent1', 'Task1', 1800.0)}
Example #13
0
def test_schedule_self_conflict():
    print('Testing self conflicting schedule', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 12:45:00')
    ], [
        'campus/building/rtu1',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ]), PRIORITY_HIGH, now)

    result1, event_time1 = verify_add_task(sch_man, *ag)
    success1, data1, info_string1 = result1
    print(not success1)
    print(data1 == {})
    print(info_string1.startswith('REQUEST_CONFLICTS_WITH_SELF'))
    assert all((not success1, data1 == {},
                info_string1.startswith('REQUEST_CONFLICTS_WITH_SELF')))
Example #14
0
def test_conflict_override_success_running_agent2():
    print(
        'Test conflicting requests: '
        'Agent2 overrides running Agent1 which has more than one device', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', (
        [
            'campus/building/rtu1',
            parse('2013-11-27 12:00:00'),
            parse('2013-11-27 12:15:00')
        ],
        [
            'campus/building/rtu2',
            parse('2013-11-27 12:00:00'),
            parse('2013-11-27 13:00:00')
        ],
        [
            'campus/building/rtu3',
            parse('2013-11-27 12:45:00'),
            parse('2013-11-27 13:00:00')
        ],
    ), PRIORITY_LOW_PREEMPT, now)
    now2 = now + timedelta(minutes=55)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu3',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_HIGH, now2)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert success2
    assert data2 == {('Agent1', 'Task1')}
    assert info_string2 == ''
    assert event_time2 == parse('2013-11-27 12:26:00')
Example #15
0
def test_conflict_override():
    print('Test conflicting requests: Agent2 overrides Agent1', now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:00:00'),
        parse('2013-11-27 12:35:00')
    ], ), PRIORITY_LOW, now)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_HIGH, now)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert success2
    assert data2 == {('Agent1', 'Task1')}
    assert not info_string2
    assert event_time2 == parse('2013-11-27 12:30:00')
Example #16
0
def test_non_conflict_schedule():
    print('Test non-conflicting requests: Agent2 and Agent1 live in harmony',
          now)
    sch_man = ScheduleManager(60, now=now)
    ag1 = ('Agent1', 'Task1', (
        [
            'campus/building/rtu1',
            parse('2013-11-27 12:00:00'),
            parse('2013-11-27 12:15:00')
        ],
        [
            'campus/building/rtu2',
            parse('2013-11-27 12:00:00'),
            parse('2013-11-27 13:00:00')
        ],
        [
            'campus/building/rtu3',
            parse('2013-11-27 12:45:00'),
            parse('2013-11-27 13:00:00')
        ],
    ), PRIORITY_LOW_PREEMPT, now)
    now2 = now + timedelta(minutes=55)
    ag2 = ('Agent2', 'Task2', ([
        'campus/building/rtu1',
        parse('2013-11-27 12:30:00'),
        parse('2013-11-27 13:00:00')
    ], ), PRIORITY_HIGH, now2)
    result1, event_time1 = verify_add_task(sch_man, *ag1)
    success1, data1, info_string1 = result1
    assert all((success1, not data1, not info_string1,
                event_time1 == parse('2013-11-27 12:00:00')))
    result2, event_time2 = verify_add_task(sch_man, *ag2)
    success2, data2, info_string2 = result2
    assert success2
    assert not data2
    assert info_string2 == ''
    assert event_time2 == parse('2013-11-27 12:30:00')
Example #17
0
         print
         print '**************************'
         print name
         print 'Start time:', time
         print '**************************'
         print
     else:
         print name
     
 
 
 now = datetime(year=2013, month=11, day=27, hour=11, minute=30)
 
 
 print_test_header('Basic Test', now)
 sch_man = ScheduleManager(timedelta(seconds=60), now=now)
 ag = ('Agent1',
       (['/campus/building/rtu1','2013-11-27 12:00:00','2013-11-27 13:00:00'],),
       PRIORITY_HIGH,
       now)    
 result1 = test_add_task(sch_man, *ag)
 event_time1, preempted1, state1 = result1.data
 assert all((result1.success, not preempted1, not state1, event_time1 == parse('2013-11-27 12:00:00')))
 
 state = sch_man.get_schedule_state(now + timedelta(minutes=30))
 assert state == {'/campus/building/rtu1': DeviceState('Agent1', result1.task_id, 3600.0)}
 state = sch_man.get_schedule_state(now + timedelta(minutes=60))
 assert state == {'/campus/building/rtu1': DeviceState('Agent1', result1.task_id, 1800.0)}
     
 
 print_test_header('Basic Test: Two devices', now)
Example #18
0
    class Agent(PublishMixin, BaseAgent):
        '''Agent to listen for requests to talk to the sMAP driver.'''
        def __init__(self, **kwargs):
            super(Agent, self).__init__(**kwargs)

            self._update_event = None
            self._update_event_time = None
            self._device_states = {}

            self.setup_schedule()

            self.setup_heartbeats()

        def setup_heartbeats(self):
            for point in points:
                heartbeat_point = points[point].get("heartbeat_point")
                if heartbeat_point is None:
                    continue

                heartbeat_handler = self.heartbeat_factory(
                    point, heartbeat_point)
                self.periodic_timer(heartbeat_interval, heartbeat_handler)

        def heartbeat_factory(self, point, actuator):
            #Stupid lack on nonlocal in 2.x
            value = [False]
            request_url = '/'.join([url, point, ACTUATOR_COLLECTION, actuator])

            publish_topic = '/'.join([point, actuator])

            def update_heartbeat_value():
                value[0] = not value[0]
                payload = {'state': str(int(value[0]))}
                try:
                    r = requests.put(request_url, params=payload)
                    self.process_smap_request_result(r, publish_topic, None)
                except requests.exceptions.ConnectionError:
                    print "Warning: smap driver not running."

            return update_heartbeat_value

        def setup_schedule(self):
            now = datetime.datetime.now()
            self._schedule_manager = ScheduleManager(
                preempt_grace_time,
                now=now,
                state_file_name=schedule_state_file)

            self.update_device_state_and_schedule(now)

        def update_device_state_and_schedule(self, now):
            self._device_states = self._schedule_manager.get_schedule_state(
                now)
            schedule_next_event_time = self._schedule_manager.get_next_event_time(
                now)
            new_update_event_time = self._get_ajusted_next_event_time(
                now, schedule_next_event_time)

            for device, state in self._device_states.iteritems():
                header = self.get_headers(state.agent_id,
                                          time=str(now),
                                          task_id=state.task_id)
                header['window'] = state.time_remaining
                topic = topics.ACTUATOR_SCHEDULE_ANNOUNCE_RAW.replace(
                    '{device}', device)
                self.publish_json(topic, header, {})

            if self._update_event is not None:
                #This won't hurt anything if we are canceling ourselves.
                self._update_event.cancel()
            self._update_event_time = new_update_event_time
            self._update_event = EventWithTime(self._update_schedule_state)
            self.schedule(self._update_event_time, self._update_event)

        def _get_ajusted_next_event_time(self, now, next_event_time):
            latest_next = now + datetime.timedelta(
                seconds=schedule_publish_interval)
            #Round to the next second to fix timer goofyness in agent timers.
            if latest_next.microsecond:
                latest_next = latest_next.replace(
                    microsecond=0) + datetime.timedelta(seconds=1)
            if next_event_time is None or latest_next < next_event_time:
                return latest_next
            return next_event_time

        def _update_schedule_state(self, unix_time):
            #Find the current slot and update the state
            now = datetime.datetime.fromtimestamp(unix_time)

            self.update_device_state_and_schedule(now)

        @matching.match_regex(topics.ACTUATOR_GET() + '/(.+)')
        def handle_get(self, topic, headers, message, match):
            point = match.group(1)
            collection_tokens, point_name = point.rsplit('/', 1)
            requester = headers.get('requesterID')
            if self.check_lock(collection_tokens, requester):
                request_url = '/'.join(
                    [url, collection_tokens, ACTUATOR_COLLECTION, point_name])
                try:
                    r = requests.get(request_url)
                    self.process_smap_request_result(r, point, requester)
                except (requests.exceptions.ConnectionError) as ex:
                    error = {'type': ex.__class__.__name__, 'value': str(ex)}
                    self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                                headers, error)
            else:
                error = {
                    'type': 'LockError',
                    'value': 'does not have this lock'
                }
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                            headers, error)

        @matching.match_regex(topics.ACTUATOR_SET() + '/(.+)')
        def handle_set(self, topic, headers, message, match):
            point = match.group(1)
            collection_tokens, point_name = point.rsplit('/', 1)
            requester = headers.get('requesterID')
            headers = self.get_headers(requester)
            if not message:
                error = {'type': 'ValueError', 'value': 'missing argument'}
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                            headers, error)
                return
            else:
                try:
                    message = jsonapi.loads(message[0])
                    if isinstance(message, bool):
                        message = int(message)
                except ValueError as ex:
                    # Could be ValueError of JSONDecodeError depending
                    # on if simplesjson was used.  JSONDecodeError
                    # inherits from ValueError
                    error = {'type': 'ValueError', 'value': str(ex)}
                    self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                                headers, error)
                    return

            if self.check_lock(collection_tokens, requester):
                request_url = '/'.join(
                    [url, collection_tokens, ACTUATOR_COLLECTION, point_name])
                payload = {'state': str(message)}
                try:
                    r = requests.put(request_url, params=payload)
                    self.process_smap_request_result(r, point, requester)
                except (requests.exceptions.ConnectionError) as ex:
                    error = {'type': ex.__class__.__name__, 'value': str(ex)}
                    self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                                headers, error)
            else:
                error = {
                    'type': 'LockError',
                    'value': 'does not have this lock'
                }
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                            headers, error)

        def check_lock(self, device, requester):
            device = device.strip('/')
            if device in self._device_states:
                device_state = self._device_states[device]
                return device_state.agent_id == requester
            return False

        @matching.match_exact(topics.ACTUATOR_SCHEDULE_REQUEST())
        def handle_schedule_request(self, topic, headers, message, match):
            request_type = headers.get('type')
            now = datetime.datetime.now()

            if request_type == SCHEDULE_ACTION_NEW:
                self.handle_new(headers, message, now)

            elif request_type == SCHEDULE_ACTION_CANCEL:
                self.handle_cancel(headers, now)

            else:
                self.publish_json(
                    topics.ACTUATOR_SCHEDULE_RESULT(), headers, {
                        'result': SCHEDULE_RESPONSE_FAILURE,
                        'data': {},
                        'info': 'INVALID_REQUEST_TYPE'
                    })

        def handle_new(self, headers, message, now):
            requester = headers.get('requesterID')
            taskID = headers.get('taskID')
            priority = headers.get('priority')

            try:
                requests = jsonapi.loads(message[0])
            except (ValueError, IndexError) as ex:
                # Could be ValueError of JSONDecodeError depending
                # on if simplesjson was used.  JSONDecodeError
                # inherits from ValueError

                #We let the schedule manager tell us this is a bad request.
                requests = []

            result = self._schedule_manager.request_slots(
                requester, taskID, requests, priority, now)
            success = SCHEDULE_RESPONSE_SUCCESS if result.success else SCHEDULE_RESPONSE_FAILURE

            #If we are successful we do something else with the real result data
            data = result.data if not result.success else {}

            topic = topics.ACTUATOR_SCHEDULE_RESULT()
            headers = self.get_headers(requester, task_id=taskID)
            headers['type'] = SCHEDULE_ACTION_NEW
            self.publish_json(topic, headers, {
                'result': success,
                'data': data,
                'info': result.info_string
            })

            #Dealing with success and other first world problems.
            if result.success:
                self.update_device_state_and_schedule(now)
                for preempted_task in result.data:
                    topic = topics.ACTUATOR_SCHEDULE_RESULT()
                    headers = self.get_headers(preempted_task[0],
                                               task_id=preempted_task[1])
                    headers['type'] = SCHEDULE_ACTION_CANCEL
                    self.publish_json(
                        topic, headers, {
                            'result': SCHEDULE_CANCEL_PREEMPTED,
                            'info': '',
                            'data': {
                                'agentID': requester,
                                'taskID': taskID
                            }
                        })

        def handle_cancel(self, headers, now):
            requester = headers.get('requesterID')
            taskID = headers.get('taskID')

            result = self._schedule_manager.cancel_task(requester, taskID, now)
            success = SCHEDULE_RESPONSE_SUCCESS if result.success else SCHEDULE_RESPONSE_FAILURE

            topic = topics.ACTUATOR_SCHEDULE_RESULT()
            self.publish_json(topic, headers, {
                'result': success,
                'info': result.info_string,
                'data': {}
            })

            if result.success:
                self.update_device_state_and_schedule(now)

        def get_headers(self, requester, time=None, task_id=None):
            headers = {}
            if time is not None:
                headers['time'] = time
            else:
                headers = {'time': str(datetime.datetime.utcnow())}
            if requester is not None:
                headers['requesterID'] = requester
            if task_id is not None:
                headers['taskID'] = task_id
            return headers

        def process_smap_request_result(self, request, point, requester):
            headers = self.get_headers(requester)
            try:
                request.raise_for_status()
                results = request.json()
                readings = results['Readings']
                reading = readings[0][1]
                self.push_result_topic_pair(VALUE_RESPONSE_PREFIX, point,
                                            headers, reading)
            except requests.exceptions.HTTPError as ex:
                error = {
                    'type': ex.__class__.__name__,
                    'value': str(request.text)
                }
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                            headers, error)
            except (ValueError, IndexError, KeyError,
                    requests.exceptions.ConnectionError) as ex:
                error = {'type': ex.__class__.__name__, 'value': str(ex)}
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point,
                                            headers, error)

        def push_result_topic_pair(self, prefix, point, headers, *args):
            topic = normtopic('/'.join([prefix, point]))
            self.publish_json(topic, headers, *args)
Example #19
0
            print
            print '**************************'
            print name
            print 'Start time:', time
            print '**************************'
            print
        else:
            print name
        
    
    
    now = datetime(year=2013, month=11, day=27, hour=11, minute=30)
    
    
    print_test_header('Basic Test', now)
    sch_man = ScheduleManager(60, now=now)
    ag = ('Agent1', 'Task1',
          (['campus/building/rtu1','2013-11-27 12:00:00','2013-11-27 13:00:00'],),
          PRIORITY_HIGH,
          now)    
    result1, event_time1= test_add_task(sch_man, *ag)
    success, data, info_string = result1
#     success1, data1, info_string1 = result1
    assert all((success, not data, not info_string, event_time1 == parse('2013-11-27 12:00:00')))
#   dict: {'campus/building/rtu1': DeviceState(agent_id='Agent1', task_id='Task1', time_remaining=3600.0)}    
    
    state = sch_man.get_schedule_state(now + timedelta(minutes=30))
    assert state == {'campus/building/rtu1': DeviceState('Agent1', 'Task1', 3600.0)}
    state = sch_man.get_schedule_state(now + timedelta(minutes=60))
    assert state == {'campus/building/rtu1': DeviceState('Agent1', 'Task1', 1800.0)}
        
Example #20
0
        def setup_schedule(self):
            now = datetime.datetime.now()
            self._schedule_manager = ScheduleManager(preempt_grace_time, now=now, state_file_name=schedule_state_file)

            self.update_device_state_and_schedule(now)
Example #21
0
    class Agent(PublishMixin, BaseAgent):
        """Agent to listen for requests to talk to the sMAP driver."""

        def __init__(self, **kwargs):
            super(Agent, self).__init__(**kwargs)

            self._update_event = None
            self._update_event_time = None
            self._device_states = {}

            self.setup_schedule()

            self.setup_heartbeats()

        def setup_heartbeats(self):
            for point in points:
                heartbeat_point = points[point].get("heartbeat_point")
                if heartbeat_point is None:
                    continue

                heartbeat_handler = self.heartbeat_factory(point, heartbeat_point)
                self.periodic_timer(heartbeat_interval, heartbeat_handler)

        def heartbeat_factory(self, point, actuator):
            # Stupid lack on nonlocal in 2.x
            value = [False]
            request_url = "/".join([url, point, ACTUATOR_COLLECTION, actuator])

            publish_topic = "/".join([point, actuator])

            def update_heartbeat_value():
                _log.debug("update_heartbeat")
                value[0] = not value[0]
                payload = {"state": str(int(value[0]))}
                try:
                    _log.debug("About to publish actuation")
                    r = requests.put(request_url, params=payload, timeout=connection_timeout)
                    self.process_smap_request_result(r, publish_topic, None)
                except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as ex:
                    print "Warning: smap driver not running."
                    _log.error("Connection error: " + str(ex))

            return update_heartbeat_value

        def setup_schedule(self):
            now = datetime.datetime.now()
            self._schedule_manager = ScheduleManager(preempt_grace_time, now=now, state_file_name=schedule_state_file)

            self.update_device_state_and_schedule(now)

        def update_device_state_and_schedule(self, now):
            _log.debug("update_device_state_and schedule")
            self._device_states = self._schedule_manager.get_schedule_state(now)
            schedule_next_event_time = self._schedule_manager.get_next_event_time(now)
            new_update_event_time = self._get_ajusted_next_event_time(now, schedule_next_event_time)

            for device, state in self._device_states.iteritems():
                header = self.get_headers(state.agent_id, time=str(now), task_id=state.task_id)
                header["window"] = state.time_remaining
                topic = topics.ACTUATOR_SCHEDULE_ANNOUNCE_RAW.replace("{device}", device)
                self.publish_json(topic, header, {})

            if self._update_event is not None:
                # This won't hurt anything if we are canceling ourselves.
                self._update_event.cancel()
            self._update_event_time = new_update_event_time
            self._update_event = EventWithTime(self._update_schedule_state)
            self.schedule(self._update_event_time, self._update_event)

        def _get_ajusted_next_event_time(self, now, next_event_time):
            _log.debug("_get_adjusted_next_event_time")
            latest_next = now + datetime.timedelta(seconds=schedule_publish_interval)
            # Round to the next second to fix timer goofyness in agent timers.
            if latest_next.microsecond:
                latest_next = latest_next.replace(microsecond=0) + datetime.timedelta(seconds=1)
            if next_event_time is None or latest_next < next_event_time:
                return latest_next
            return next_event_time

        def _update_schedule_state(self, unix_time):
            # Find the current slot and update the state
            now = datetime.datetime.fromtimestamp(unix_time)

            self.update_device_state_and_schedule(now)

        @matching.match_regex(topics.ACTUATOR_GET() + "/(.+)")
        def handle_get(self, topic, headers, message, match):
            point = match.group(1)
            collection_tokens, point_name = point.rsplit("/", 1)
            requester = headers.get("requesterID")
            if self.check_lock(collection_tokens, requester):
                request_url = "/".join([url, collection_tokens, ACTUATOR_COLLECTION, point_name])
                try:
                    r = requests.get(request_url, timeout=connection_timeout)
                    self.process_smap_request_result(r, point, requester)
                except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as ex:
                    error = {"type": ex.__class__.__name__, "value": str(ex)}
                    self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)
            else:
                error = {"type": "LockError", "value": "does not have this lock"}
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)

        @matching.match_regex(topics.ACTUATOR_SET() + "/(.+)")
        def handle_set(self, topic, headers, message, match):
            _log.debug("handle_set: {topic},{headers}, {message}".format(topic=topic, headers=headers, message=message))
            point = match.group(1)
            collection_tokens, point_name = point.rsplit("/", 1)
            requester = headers.get("requesterID")
            headers = self.get_headers(requester)
            if not message:
                error = {"type": "ValueError", "value": "missing argument"}
                _log.debug("ValueError: " + str(error))
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)
                return
            else:
                try:
                    message = jsonapi.loads(message[0])
                    if isinstance(message, bool):
                        message = int(message)
                except ValueError as ex:
                    # Could be ValueError of JSONDecodeError depending
                    # on if simplesjson was used.  JSONDecodeError
                    # inherits from ValueError
                    _log.debug("ValueError: " + message)
                    error = {"type": "ValueError", "value": str(ex)}
                    self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)
                    return

            if self.check_lock(collection_tokens, requester):
                request_url = "/".join([url, collection_tokens, ACTUATOR_COLLECTION, point_name])
                payload = {"state": str(message)}
                try:
                    r = requests.put(request_url, params=payload, timeout=connection_timeout)
                    self.process_smap_request_result(r, point, requester)
                except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as ex:

                    error = {"type": ex.__class__.__name__, "value": str(ex)}
                    self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)
                    _log.debug("ConnectionError: " + str(error))
            else:
                error = {"type": "LockError", "value": "does not have this lock"}
                _log.debug("LockError: " + str(error))
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)

        def check_lock(self, device, requester):
            _log.debug("check_lock: {device}, {requester}".format(device=device, requester=requester))
            device = device.strip("/")
            if device in self._device_states:
                device_state = self._device_states[device]
                return device_state.agent_id == requester
            return False

        @matching.match_exact(topics.ACTUATOR_SCHEDULE_REQUEST())
        def handle_schedule_request(self, topic, headers, message, match):
            request_type = headers.get("type")
            now = datetime.datetime.now()
            _log.debug(
                "handle_schedule_request: {topic}, {headers}, {message}".format(
                    topic=topic, headers=str(headers), message=str(message)
                )
            )

            if request_type == SCHEDULE_ACTION_NEW:
                self.handle_new(headers, message, now)

            elif request_type == SCHEDULE_ACTION_CANCEL:
                self.handle_cancel(headers, now)

            else:
                _log.debug("handle-schedule_request, invalid request type")
                self.publish_json(
                    topics.ACTUATOR_SCHEDULE_RESULT(),
                    headers,
                    {"result": SCHEDULE_RESPONSE_FAILURE, "data": {}, "info": "INVALID_REQUEST_TYPE"},
                )

        def handle_new(self, headers, message, now):
            requester = headers.get("requesterID")
            taskID = headers.get("taskID")
            priority = headers.get("priority")

            _log.debug(
                "Got new schedule request: {headers}, {message}".format(headers=str(headers), message=str(message))
            )

            try:
                requests = jsonapi.loads(message[0])
            except (ValueError, IndexError) as ex:
                # Could be ValueError of JSONDecodeError depending
                # on if simplesjson was used.  JSONDecodeError
                # inherits from ValueError

                # We let the schedule manager tell us this is a bad request.
                _log.error("bad request: {request}, {error}".format(request=requests, error=str(ex)))
                requests = []

            result = self._schedule_manager.request_slots(requester, taskID, requests, priority, now)
            success = SCHEDULE_RESPONSE_SUCCESS if result.success else SCHEDULE_RESPONSE_FAILURE

            # If we are successful we do something else with the real result data
            data = result.data if not result.success else {}

            topic = topics.ACTUATOR_SCHEDULE_RESULT()
            headers = self.get_headers(requester, task_id=taskID)
            headers["type"] = SCHEDULE_ACTION_NEW
            self.publish_json(topic, headers, {"result": success, "data": data, "info": result.info_string})

            # Dealing with success and other first world problems.
            if result.success:
                self.update_device_state_and_schedule(now)
                for preempted_task in result.data:
                    topic = topics.ACTUATOR_SCHEDULE_RESULT()
                    headers = self.get_headers(preempted_task[0], task_id=preempted_task[1])
                    headers["type"] = SCHEDULE_ACTION_CANCEL
                    self.publish_json(
                        topic,
                        headers,
                        {
                            "result": SCHEDULE_CANCEL_PREEMPTED,
                            "info": "",
                            "data": {"agentID": requester, "taskID": taskID},
                        },
                    )

        def handle_cancel(self, headers, now):
            requester = headers.get("requesterID")
            taskID = headers.get("taskID")

            result = self._schedule_manager.cancel_task(requester, taskID, now)
            success = SCHEDULE_RESPONSE_SUCCESS if result.success else SCHEDULE_RESPONSE_FAILURE

            topic = topics.ACTUATOR_SCHEDULE_RESULT()
            self.publish_json(topic, headers, {"result": success, "info": result.info_string, "data": {}})

            if result.success:
                self.update_device_state_and_schedule(now)

        def get_headers(self, requester, time=None, task_id=None):
            headers = {}
            if time is not None:
                headers["time"] = time
            else:
                headers = {"time": str(datetime.datetime.utcnow())}
            if requester is not None:
                headers["requesterID"] = requester
            if task_id is not None:
                headers["taskID"] = task_id
            return headers

        def process_smap_request_result(self, request, point, requester):
            _log.debug(
                "Start of process_smap: \n{request}, \n{point}, \n{requester}".format(
                    request=request, point=point, requester=requester
                )
            )
            headers = self.get_headers(requester)
            try:

                request.raise_for_status()
                results = request.json()
                readings = results["Readings"]
                _log.debug("Readings: {readings}".format(readings=readings))
                reading = readings[0][1]
                self.push_result_topic_pair(VALUE_RESPONSE_PREFIX, point, headers, reading)
            except requests.exceptions.HTTPError as ex:
                error = {"type": ex.__class__.__name__, "value": str(request.text)}
                _log.error("process_smap HTTPError: " + str(error))
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)
            except (ValueError, IndexError, KeyError, requests.exceptions.ConnectionError) as ex:
                error = {"type": ex.__class__.__name__, "value": str(ex)}
                _log.error("process_smap RequestError: " + str(error))
                self.push_result_topic_pair(ERROR_RESPONSE_PREFIX, point, headers, error)

            _log.debug(
                "End of process_smap: \n{request}, \n{point}, \n{requester}".format(
                    request=request, point=point, requester=requester
                )
            )

        def push_result_topic_pair(self, prefix, point, headers, *args):
            topic = normtopic("/".join([prefix, point]))
            self.publish_json(topic, headers, *args)