Beispiel #1
0
def test_event_context_update(event_setup, monkeypatch):
    """ Test update command """
    syscfg = event_setup()
    syscfg.get('device').config.set('value', 'oldval')
    syscfg.get('device').config.save()

    event = make_event('device', 'update', {
        'value': 'newval',
        'task_id': 123123
    })

    with mgr.EventContext(syscfg) as context:
        monkeypatch.setattr(
            context, 'confirm_update', lambda *args: {
                'task_id': args[0],
                'response': args[1]
            })
        result = context.manage(event)

    devconf = syscfg.get('device').config
    devconf.data = {}  # clean up config
    test_conf = devconf.load()  # reread from file

    assert result.get('response') == 'ACK'
    assert result.get('task_id') == 123123
    assert test_conf.get('value') == 'newval'
Beispiel #2
0
 def run(self):
     """start application device module"""
     self.logger.info('application starting')
     self.logger.debug(
         f'{self} starting with device config: \n {self.config}')
     reload_event = make_event('device', 'reload')
     self.q_int.put(reload_event)
Beispiel #3
0
    def run(self):
        """ Running lock

            self.gpio_setup() must be performed before run
        """
        self.on_start()
        self.logger.info('running lock...')
        start_event = make_event('device', 'reload')
        self.q_int.put(start_event)
        self.running = True
        self.keypad_thread.start()

        while self.running:
            time.sleep(DEFAULT_SLEEP / 5)
            # main routine
            self.manage_sound()
            # Это должно быть сверху, потому что иначе неправильно работает игровой фидбек от замка в blocked статусе
            if not self.keypad_data_queue.empty():
                # reading serial from keypads.
                data = self.keypad_data_queue.get()
                self.parse_data(data)
            # blocked rules all
            if self.config.get('blocked') or self.check_timer("main", int(time.time())):
                self.set_closed()
                continue
            # sync state - opening
            if self.closed and not self.config.get('closed'):
                self.open()
            # sync state - closing
            if not self.closed and self.config.get('closed'):
                self.close()
        else:
            return self.stop()
Beispiel #4
0
    def run(self):
        print('application is starting...')
        self.logger.info(f'tester starting as: {self.sysconf}')
        self.running = True
        event = make_event('device', 'reload')
        self.q_int.put(event)
        initial_config = self.config.data
        #q_ext = self.sysconf.get('q_ext')
        while self.running:
            #    event = q_ext.get()
            #    if event:
            #        print(event)
            #        q_ext.put(event)
            #self.emulate_activity()
            if self.web:
                form_data = self.flask_queue.get()
                try:
                    res = json.loads(form_data.get("datahold"))
                except json.decoder.JSONDecodeError as e:
                    res = form_data.get("datahold")

                if form_data.get("type") == "SUP":
                    self.state_update(res)
                else:
                    self.send_message(res)

            new_config = self.config.data
            if new_config != initial_config:
                print(f"{new_config}")
                initial_config = new_config
            time.sleep(1)
Beispiel #5
0
 def mqtt_to_internal(self, mqtt_event: Event, internal_command: str):
     datahold = mqtt_event.data.get('datahold')
     if not datahold:
         raise Exception(
             f'empty datahold in {mqtt_event.data.get("command").upper()} packet: {mqtt_event}'
         )
     event = make_event('device', internal_command, datahold)
     self.q_int.put(event)
Beispiel #6
0
def test_device_input_send_msg(get_device, default_config):
    device, devcfg, syscfg = get_device

    event = device.send_message(default_config('dev'))
    test_event = make_event('device', 'info', default_config('dev'))

    assert event.type == test_event.type, 'bad event type'
    assert event.cmd == test_event.cmd, 'bad event command'
    assert event.data == test_event.data, 'bad event data'
Beispiel #7
0
def test_event_context_reload(event_setup, default_config):
    """ Test reload command """
    syscfg = event_setup()
    dev_conf = syscfg.get('device').config

    pre_conf = dev_conf.load()
    changed = dev_conf.update({'value': 'updated'})
    event = make_event('device', 'reload')

    with mgr.EventContext(syscfg) as context:
        result = context.manage(event)

    assert changed.get('value') == 'updated', 'config not updated on the fly'
    assert result == pre_conf, 'config was not reloaded'
Beispiel #8
0
def test_event_context_info_send(event_setup, monkeypatch, default_config):
    """ Test send command """
    syscfg = event_setup()
    _dict = {'new_value': 'new'}
    event = make_event('device', 'info', _dict)

    with mgr.EventContext(syscfg) as context:
        monkeypatch.setattr(context, 'send_message', lambda x: x)
        result = context.manage(event)

    test_conf = syscfg.get('device').config.load()

    assert test_conf.get('new_value') is None, 'config saved when should not'
    assert result == _dict, 'bad data sent'
Beispiel #9
0
def test_event_context_input(event_setup, monkeypatch, default_config,
                             payload):
    """ Test device state_update (input event) """
    syscfg = event_setup()
    event = make_event('device', 'input', payload)

    with mgr.EventContext(syscfg) as context:
        # not sending config anywhere, just calling device.config.save
        monkeypatch.setattr(context, 'send_config', lambda x: x)
        result = context.manage(event)

    post_conf = {**default_config('dev'), **payload}

    assert result == payload, 'config not sent'
    assert syscfg.get('device').config.load() == post_conf, 'config not saved'
Beispiel #10
0
def test_device_input_new(get_device, default_config, payload):
    device, devcfg, syscfg = get_device

    event = device.state_update({**default_config('dev'), **payload})
    payload_and_uid = {**payload, **{'uid': syscfg.get('uid')}}
    test_event = make_event('device', 'input', payload_and_uid)
    device.save(payload)

    assert device.config.data == {
        **devcfg.data,
        **payload
    }, 'user input not saved'
    assert event.type == test_event.type, 'bad event type'
    assert event.cmd == test_event.cmd, 'bad event command'
    assert event.data == test_event.data, 'bad event data'
Beispiel #11
0
def test_router_event_device(get_router, monkeypatch, get_from_queue,
                             event_data):
    router, syscfg, devcfg = get_router
    test_queue = Queue()
    monkeypatch.setattr(EventContext, 'manage', lambda x, y: test_queue.put(y))
    router.start()

    event = make_event('device', 'test', event_data)
    syscfg.get('q_int').put(event)
    result = list(get_from_queue(test_queue))

    assert result, 'event not managed'
    assert not len(result) > 1, 'too many events'
    assert result[0].type == 'device'
    assert result[0].cmd == 'test'
    assert result[0].data == event_data
Beispiel #12
0
def test_router_exit_by_event(get_router, request, get_from_queue):
    router, syscfg, devcfg = get_router
    router.start()

    def _fin():
        router.running = False
        router.join(.1)

    request.addfinalizer(_fin)

    event = make_event('exit')
    syscfg.data['q_int'].put(event)
    expected_event = list(get_from_queue(syscfg.get('q_ext')))

    assert expected_event, 'cannot get event from external queue'
    assert not len(expected_event) > 1, 'too many events'
    assert expected_event[0].type == 'exit', 'external message not sent'
    assert router.running is False, 'router was not stopped'
Beispiel #13
0
    def connect_client(self):
        exit_message = make_event('device', 'exit')
        tries = 0
        while not self.is_connected:
            if self.running is False:
                return
            self.client.loop()  # manual loop while not connected
            sleep_time = self.default_timeout  # default sleep time
            tries += 1
            self.logger.info(
                f':: trying MQTT broker: {tries}, next try after {sleep_time}s'
            )
            try:
                self.client.connect(host=self.broker_ip,
                                    port=self.broker_port,
                                    keepalive=60)
            except ValueError:
                _errm = f"check system config, client misconfigured.\n"\
                        f"broker_ip: {self.broker_ip} broker_port: {self.broker_port}"
                self.client.loop_stop()
                self.q_int.put(exit_message)
            except (ConnectionRefusedError, OSError):
                sleep_time = 30
                _errm = f'mqtt broker not available, waiting {sleep_time}s'
                self.logger.error(_errm)
            except MQTTAuthError:
                self.logger.exception('auth error. check system config ')
                self.q_int.put(exit_message)
            except MQTTProtocolError:
                self.logger.exception('protocol error. report immediately')
                self.q_int.put(exit_message)
            except Exception:
                self.logger.exception('exception occured')
                self.q_int.put(exit_message)
            time.sleep(sleep_time)

        _connm = ':: connected to MQTT broker at ' \
                 '{broker_ip}:{broker_port} ' \
                 'as {client._client_id}'.format(**self.__dict__)

        self.logger.info(_connm)
        self.client.loop_start()
Beispiel #14
0
def test_router_event_mqtt(get_router, monkeypatch, get_from_queue):
    router, syscfg, devcfg = get_router
    test_queue = Queue()
    monkeypatch.setattr(EventContext, 'manage_mqtt',
                        lambda x, y: test_queue.put(y))
    router.start()

    kinda_mqtt_parsed_message = {
        'datahold': {
            'data': 'test'
        },
        'command': 'PING'
    }
    event = make_event('mqtt', 'test', kinda_mqtt_parsed_message)
    syscfg.get('q_int').put(event)
    result = list(get_from_queue(test_queue))

    assert result, 'event not managed'
    assert not len(result) > 1, 'too many events'
    assert result[0].data.get('command') == 'PING'
    assert result[0].data.get('datahold') == {'data': 'test'}
Beispiel #15
0
    def on_connect(self, client: mqtt.Client, userdata: Any, flags, rc: int):
        """On connect to broker
            TODO: type annotation for userdata
        """

        if 6 > rc > 0:
            # connection failed
            raise auth_exc.get(str(rc))

        self.is_connected = True

        try:
            for c in self.sub:
                self.client.subscribe(c)
            self.subscriptions_info = "subscribed to " + ','.join(self.sub)
        except Exception:
            raise

        # request config on connect
        request_config_event = make_event("device", "cup")
        self.q_int.put(request_config_event)
Beispiel #16
0
    def state_update(self, data: dict):
        """Update device configuration from user actions

           When new data from user actions received, check current config and if changed,
           send new event to inner event queue for local config change.
        """
        if not isinstance(data, dict):
            self.logger.error('message type not dict: {}\n{}'.format(
                type(data), data))
            return
        delta = {}
        for key in data:
            # make diff
            old_value = self.config.get(key, None)
            if data[key] != old_value:
                delta[key] = data[key]
        if delta:
            delta['uid'] = self.uid
            event = make_event('device', 'input', delta)
            self.q_int.put(event)
            return event
Beispiel #17
0
    def on_message(self, client: mqtt.Client, userdata, msg):
        """Message from MQTT broker received
           receive message as (str, b'{}'), return dict
           TODO: type annotations for userdata, msg
        """
        self.logger.debug(f'RECEIVE: {msg.topic} {msg.payload}')

        try:
            full_topic = msg.topic.split('/')
            if 2 > len(full_topic) > 3:
                raise Exception(f'unsupported topic format: {full_topic}')
            payload = json.loads(msg.payload.decode('utf-8'))

            data = dict(topic=full_topic[0],
                        uid=full_topic[1] if len(full_topic) == 3 else None,
                        command=full_topic[-1],
                        task_id=payload.get('task_id'),
                        timestamp=int(payload.get('timestamp')),
                        datahold=payload.get('datahold'))
            event = make_event('mqtt', 'new', data)
            self.q_int.put(event)
        except BaseException:
            self.logger.exception('while receiving message')
Beispiel #18
0
def test_event_context_send_config_from_event_with_data(
        event_setup, monkeypatch, default_config, key, expected):
    """ Test send config to server with filtered fields """
    in_queue = list()
    syscfg = event_setup(dev_config=base_config)
    internal_event = make_event("device", "sup", [
        key,
    ])

    with mgr.EventContext(syscfg) as context:
        monkeypatch.setattr(context.q_ext, 'put', lambda x: in_queue.append(x))
        context.manage(internal_event)
        while not in_queue:
            time.sleep(.1)
        else:
            message = MockMessage(in_queue[-1])

    packet_topic = '/'.join((context.topic, syscfg.get('uid'), 'SUP'))
    assert message.topic == packet_topic, 'wrong message topic'
    assert message.decoded.get(
        'timestamp') == 0, f'wrong device timestamp {message.decoded}'
    assert message.decoded['datahold'].get(
        key
    ) == expected, f'{key}, {expected} > bad data send: {message.decoded}'
Beispiel #19
0
 def stop(self):
     """stop application device module"""
     self.logger.info('device is stopping...')
     self.logger.debug(f"stopping device {self}")
     end_event = make_event("exit")
     self.q_int.put(end_event)
Beispiel #20
0
 def enqueue(self, record):
     data = {"msg": record.msg, "lvl": record.levelname}
     event = make_event('device', 'send', data)
     self.queue.put(event)
Beispiel #21
0
 def send_message(self, data: dict):
     """Send message to server"""
     event = make_event('device', 'info', data)
     self.q_int.put(event)
     return event