From eb8b83c9df8f58104850ef530133f81a15fe5ae8 Mon Sep 17 00:00:00 2001 From: Kimmo Huoman Date: Thu, 3 Mar 2016 03:16:48 +0200 Subject: [PATCH] Some minor re-structuring, improving tests. Still very worried that running the tests might wipe the Storage, need to figure out a solution :( --- enocean/communicators/communicator.py | 50 +++++++++++++++++-- .../communicators/tests/test_communicator.py | 31 ++++++++++++ enocean/storage/tests/test_storage.py | 44 +++++++++++++++- run_tests_with_timing.sh | 2 - test.sh | 2 + test_with_timing.sh | 2 + 6 files changed, 125 insertions(+), 6 deletions(-) delete mode 100755 run_tests_with_timing.sh create mode 100755 test.sh create mode 100755 test_with_timing.sh diff --git a/enocean/communicators/communicator.py b/enocean/communicators/communicator.py index 5d4b233..65caf9a 100644 --- a/enocean/communicators/communicator.py +++ b/enocean/communicators/communicator.py @@ -1,14 +1,15 @@ # -*- encoding: utf-8 -*- from __future__ import print_function, unicode_literals, division, absolute_import import logging - +import os import threading try: import queue except ImportError: import Queue as queue -from enocean.protocol.packet import Packet, UTETeachIn +from enocean.protocol.packet import Packet, RadioPacket, UTETeachIn from enocean.protocol.constants import PACKET, PARSE_RESULT, RETURN_CODE +from enocean.storage import Storage, Device class Communicator(threading.Thread): @@ -18,7 +19,8 @@ class Communicator(threading.Thread): ''' logger = logging.getLogger('enocean.communicators.Communicator') - def __init__(self, callback=None, teach_in=True): + # TODO: Stupid, ugly hack to disable storage during testing. + def __init__(self, callback=None, teach_in=True, use_storage=True if os.environ.get('ENOCEAN_TESTING', None) else False, storage_location=None): super(Communicator, self).__init__() # Create an event to stop the thread self._stop_flag = threading.Event() @@ -35,6 +37,12 @@ def __init__(self, callback=None, teach_in=True): # TODO: Not sure if we should use CO_WR_LEARNMODE?? self.teach_in = teach_in + # Initialize Storage + # TODO: Should really initialize with Storage-object, but not accept any new devices... + self.storage = None + if use_storage: + self.storage = Storage(storage_location) + def _get_from_send_queue(self): ''' Get message from send queue, if one exists ''' try: @@ -114,12 +122,48 @@ def parse(self): self.send(packet.create_response_packet(self.base_id), priority=0) packet.response_sent = True + self.store_device(packet) + + # TODO: Prioritize packages, once receive is changed to PriorityQueue if self.__callback is None: self.receive.put(packet) else: self.__callback(packet) self.logger.debug(packet) + def store_device(self, packet): + ''' Save device to storage, if all conditions are met. ''' + if self.storage is None: + return + if self.teach_in is False: + return + if not isinstance(packet, RadioPacket): + return + if not packet.learn: + return + + try: + device = self.storage.load_device(device_id=packet.sender) + # If device is found, update the data we're likely to get from the teach_in. + device.update({ + 'eep_rorg': packet.rorg, + 'eep_func': packet.rorg_func, + 'eep_type': packet.rorg_type, + 'manufacturer_id': packet.rorg_manufacturer, + }) + self.storage.save_device(device) + except KeyError: + # If device is not found, create a new device. + self.storage.save_device( + Device( + id=packet.sender, + eep_rorg=packet.rorg, + eep_func=packet.rorg_func, + eep_type=packet.rorg_type, + manufacturer_id=packet.rorg_manufacturer + ) + ) + @property def base_id(self): ''' Fetches Base ID from the transmitter, if required. Otherwise returns the currently set Base ID. ''' diff --git a/enocean/communicators/tests/test_communicator.py b/enocean/communicators/tests/test_communicator.py index d6c1c61..ab0fced 100644 --- a/enocean/communicators/tests/test_communicator.py +++ b/enocean/communicators/tests/test_communicator.py @@ -141,3 +141,34 @@ def test_thread(): com.start() com.base_id com.stop() + + +def test_storage(): + data = bytearray([ + 0x55, + 0x00, 0x0A, 0x07, 0x01, + 0xEB, + 0xA5, 0x08, 0x28, 0x46, 0x80, 0x01, 0x8A, 0x7B, 0x30, 0x00, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x49, 0x00, + 0x26 + ]) + + com = Communicator(use_storage=False) + assert com.storage is None + com._buffer.extend(data) + com.parse() + assert com.storage is None + + com = Communicator(use_storage=True, storage_location='/tmp/enocean-tests.json') + assert len(com.storage.devices.keys()) == 0 + com._buffer.extend(data) + com.parse() + assert len(com.storage.devices.keys()) == 1 + + com = Communicator() + com._buffer.extend(data) + com.parse() + packet = com.get_packet() + assert packet.learn + + com.storage.wipe() diff --git a/enocean/storage/tests/test_storage.py b/enocean/storage/tests/test_storage.py index 7a7c7c5..98fea7c 100644 --- a/enocean/storage/tests/test_storage.py +++ b/enocean/storage/tests/test_storage.py @@ -1,8 +1,9 @@ # -*- encoding: utf-8 -*- from __future__ import print_function, unicode_literals, division, absolute_import import os +import errno from enocean.storage import Storage, Device -from enocean.decorators import timing +from enocean.tests.decorators import timing PATH = '/tmp/enocean-tests.json' # Remove the file to be sure... @@ -103,6 +104,12 @@ def test_devices_add_remove(): assert s.next_offset == 0 assert s.used_offsets == [1] + try: + s.used_offsets = 'ASD' + assert False + except ValueError: + assert True + # Reload Storage, just to make sure save was successful. s.load() @@ -123,9 +130,20 @@ def test_devices_add_remove(): pass s.remove_device('DE:AD:BE:EF') + del s.data['devices'] + s.save_device(device) + # Reload Storage, just to make sure save was successful. + s.load() + s.remove_device('DE:AD:BE:EF') + s.save_device(device) # Reload Storage, just to make sure save was successful. s.load() + + s.save_device(device) + # Reload Storage, just to make sure save was successful. + s.load() + s.remove_device([0xDE, 0xAD, 0xBE, 0xEF]) assert s.devices == {} try: @@ -135,3 +153,27 @@ def test_devices_add_remove(): assert True s.wipe() + + +def test_random(): + # FFS, if this kind of tests fail, and cause issues, shoot @kipe. + # @kipe wrote: + # to be honest, I have no idea on how to do these kinds of tests, except in a very, very + # very, very, safe environoment :S + # and furthermore, if these kind of tests run in your environment, you're fucked anyways... + + # Try a directory, we are absolutely not allowed to write. + s = Storage('/usr/var/lib/local/bin/asd') + try: + s.save() + except OSError as exception: + if exception == errno.EEXIST: + raise + pass + + s.location = '/bin/sh' + try: + s.wipe() + except OSError as exception: + if exception == errno.EPERM: + pass diff --git a/run_tests_with_timing.sh b/run_tests_with_timing.sh deleted file mode 100755 index 4cd310e..0000000 --- a/run_tests_with_timing.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -WITH_TIMINGS=1 nosetests -s -q diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..1280a17 --- /dev/null +++ b/test.sh @@ -0,0 +1,2 @@ +#!/bin/sh +ENOCEAN_TESTING=1 nosetests -s -q --with-coverage --cover-package=enocean diff --git a/test_with_timing.sh b/test_with_timing.sh new file mode 100755 index 0000000..9710783 --- /dev/null +++ b/test_with_timing.sh @@ -0,0 +1,2 @@ +#!/bin/sh +WITH_TIMINGS=1 test.sh