예제 #1
0
class PowerControllerTest(unittest.TestCase):
    """ Tests for PowerStore. """
    @classmethod
    def setUpClass(cls):
        SetTestMode()

    def setUp(self):
        self.power_communicator = mock.Mock()
        SetUpTestInjections(power_communicator=self.power_communicator,
                            power_db=':memory:')
        self.store = PowerStore()

    def test_empty(self):
        """ Test an empty database. """
        self.assertEqual({}, self.store.get_power_modules())
        self.assertEqual(1, self.store.get_free_address())

        self.store.register_power_module(1, POWER_MODULE)

        self.assertEqual(
            {
                1: {
                    'id': 1,
                    'address': 1,
                    'name': u'',
                    'version': 8,
                    'input0': u'',
                    'input1': u'',
                    'input2': u'',
                    'input3': u'',
                    'input4': u'',
                    'input5': u'',
                    'input6': u'',
                    'input7': u'',
                    'sensor0': 0,
                    'sensor1': 0,
                    'sensor2': 0,
                    'sensor3': 0,
                    'sensor4': 0,
                    'sensor5': 0,
                    'sensor6': 0,
                    'sensor7': 0,
                    'times0': None,
                    'times1': None,
                    'times2': None,
                    'times3': None,
                    'times4': None,
                    'times5': None,
                    'times6': None,
                    'times7': None,
                    'inverted0': 0,
                    'inverted1': 0,
                    'inverted2': 0,
                    'inverted3': 0,
                    'inverted4': 0,
                    'inverted5': 0,
                    'inverted6': 0,
                    'inverted7': 0
                }
            }, self.store.get_power_modules())

        self.assertEqual(2, self.store.get_free_address())

        self.store.register_power_module(5, POWER_MODULE)
        self.assertEqual(
            {
                1: {
                    'id': 1,
                    'address': 1,
                    'name': u'',
                    'version': 8,
                    'input0': u'',
                    'input1': u'',
                    'input2': u'',
                    'input3': u'',
                    'input4': u'',
                    'input5': u'',
                    'input6': u'',
                    'input7': u'',
                    'sensor0': 0,
                    'sensor1': 0,
                    'sensor2': 0,
                    'sensor3': 0,
                    'sensor4': 0,
                    'sensor5': 0,
                    'sensor6': 0,
                    'sensor7': 0,
                    'times0': None,
                    'times1': None,
                    'times2': None,
                    'times3': None,
                    'times4': None,
                    'times5': None,
                    'times6': None,
                    'times7': None,
                    'inverted0': 0,
                    'inverted1': 0,
                    'inverted2': 0,
                    'inverted3': 0,
                    'inverted4': 0,
                    'inverted5': 0,
                    'inverted6': 0,
                    'inverted7': 0
                },
                2: {
                    'id': 2,
                    'address': 5,
                    'name': u'',
                    'version': 8,
                    'input0': u'',
                    'input1': u'',
                    'input2': u'',
                    'input3': u'',
                    'input4': u'',
                    'input5': u'',
                    'input6': u'',
                    'input7': u'',
                    'sensor0': 0,
                    'sensor1': 0,
                    'sensor2': 0,
                    'sensor3': 0,
                    'sensor4': 0,
                    'sensor5': 0,
                    'sensor6': 0,
                    'sensor7': 0,
                    'times0': None,
                    'times1': None,
                    'times2': None,
                    'times3': None,
                    'times4': None,
                    'times5': None,
                    'times6': None,
                    'times7': None,
                    'inverted0': 0,
                    'inverted1': 0,
                    'inverted2': 0,
                    'inverted3': 0,
                    'inverted4': 0,
                    'inverted5': 0,
                    'inverted6': 0,
                    'inverted7': 0
                }
            }, self.store.get_power_modules())

        self.assertEqual(6, self.store.get_free_address())

    def test_update(self):
        """ Test for updating the power module information. """
        self.assertEqual({}, self.store.get_power_modules())

        self.store.register_power_module(1, POWER_MODULE)

        self.assertEqual(
            {
                1: {
                    'id': 1,
                    'address': 1,
                    'name': u'',
                    'version': 8,
                    'input0': u'',
                    'input1': u'',
                    'input2': u'',
                    'input3': u'',
                    'input4': u'',
                    'input5': u'',
                    'input6': u'',
                    'input7': u'',
                    'sensor0': 0,
                    'sensor1': 0,
                    'sensor2': 0,
                    'sensor3': 0,
                    'sensor4': 0,
                    'sensor5': 0,
                    'sensor6': 0,
                    'sensor7': 0,
                    'times0': None,
                    'times1': None,
                    'times2': None,
                    'times3': None,
                    'times4': None,
                    'times5': None,
                    'times6': None,
                    'times7': None,
                    'inverted0': 0,
                    'inverted1': 0,
                    'inverted2': 0,
                    'inverted3': 0,
                    'inverted4': 0,
                    'inverted5': 0,
                    'inverted6': 0,
                    'inverted7': 0
                }
            }, self.store.get_power_modules())

        times = ",".join(["00:00" for _ in range(14)])

        self.store.update_power_module({
            'id': 1,
            'name': 'module1',
            'input0': 'in0',
            'input1': 'in1',
            'input2': 'in2',
            'input3': 'in3',
            'input4': 'in4',
            'input5': 'in5',
            'input6': 'in6',
            'input7': 'in7',
            'sensor0': 0,
            'sensor1': 1,
            'sensor2': 2,
            'sensor3': 3,
            'sensor4': 4,
            'sensor5': 5,
            'sensor6': 6,
            'sensor7': 7,
            'times0': times,
            'times1': times,
            'times2': times,
            'times3': times,
            'times4': times,
            'times5': times,
            'times6': times,
            'times7': times,
            'inverted0': 0,
            'inverted1': 0,
            'inverted2': 0,
            'inverted3': 0,
            'inverted4': 0,
            'inverted5': 0,
            'inverted6': 0,
            'inverted7': 0
        })

        self.assertEqual(
            {
                1: {
                    'id': 1,
                    'address': 1,
                    'version': 8,
                    'name': 'module1',
                    'input0': 'in0',
                    'input1': 'in1',
                    'input2': 'in2',
                    'input3': 'in3',
                    'input4': 'in4',
                    'input5': 'in5',
                    'input6': 'in6',
                    'input7': 'in7',
                    'sensor0': 0,
                    'sensor1': 1,
                    'sensor2': 2,
                    'sensor3': 3,
                    'sensor4': 4,
                    'sensor5': 5,
                    'sensor6': 6,
                    'sensor7': 7,
                    'times0': times,
                    'times1': times,
                    'times2': times,
                    'times3': times,
                    'times4': times,
                    'times5': times,
                    'times6': times,
                    'times7': times,
                    'inverted0': 0,
                    'inverted1': 0,
                    'inverted2': 0,
                    'inverted3': 0,
                    'inverted4': 0,
                    'inverted5': 0,
                    'inverted6': 0,
                    'inverted7': 0
                }
            }, self.store.get_power_modules())

    def test_module_exists(self):
        """ Test for module_exists. """

        self.assertFalse(self.store.module_exists(1))

        self.store.register_power_module(1, POWER_MODULE)

        self.assertTrue(self.store.module_exists(1))
        self.assertFalse(self.store.module_exists(2))

    def test_readdress_power_module(self):
        """ Test for readdress_power_module. """
        self.store.register_power_module(1, POWER_MODULE)

        self.store.readdress_power_module(1, 2)

        self.assertFalse(self.store.module_exists(1))
        self.assertTrue(self.store.module_exists(2))

        self.assertEqual(
            {
                1: {
                    'id': 1,
                    'address': 2,
                    'name': u'',
                    'version': 8,
                    'input0': u'',
                    'input1': u'',
                    'input2': u'',
                    'input3': u'',
                    'input4': u'',
                    'input5': u'',
                    'input6': u'',
                    'input7': u'',
                    'sensor0': 0,
                    'sensor1': 0,
                    'sensor2': 0,
                    'sensor3': 0,
                    'sensor4': 0,
                    'sensor5': 0,
                    'sensor6': 0,
                    'sensor7': 0,
                    'times0': None,
                    'times1': None,
                    'times2': None,
                    'times3': None,
                    'times4': None,
                    'times5': None,
                    'times6': None,
                    'times7': None,
                    'inverted0': 0,
                    'inverted1': 0,
                    'inverted2': 0,
                    'inverted3': 0,
                    'inverted4': 0,
                    'inverted5': 0,
                    'inverted6': 0,
                    'inverted7': 0
                }
            }, self.store.get_power_modules())

    def test_get_address(self):
        """ Test for get_address. """
        self.assertEqual({}, self.store.get_power_modules())

        self.store.register_power_module(1, POWER_MODULE)
        self.store.readdress_power_module(1, 3)

        self.assertEqual(3, self.store.get_address(1))
예제 #2
0
class PowerCommunicatorTest(unittest.TestCase):
    """ Tests for PowerCommunicator class """

    @classmethod
    def setUpClass(cls):
        SetTestMode()

    def setUp(self):
        self.pubsub = PubSub()
        SetUpTestInjections(pubsub=self.pubsub)
        self.power_data = []  # type: list
        SetUpTestInjections(power_db=':memory:')
        self.serial = RS485(SerialMock(self.power_data))
        self.store = PowerStore()
        SetUpTestInjections(power_serial=self.serial,
                            power_store=self.store)
        self.communicator = PowerCommunicator()

    def tearDown(self):
        self.communicator.stop()
        self.serial.stop()

    def test_do_command(self):
        """ Test for standard behavior PowerCommunicator.do_command. """
        action = power_api.get_voltage(power_api.POWER_MODULE)

        self.power_data.extend([
            sin(action.create_input(1, 1)), sout(action.create_output(1, 1, 49.5))
        ])
        self.serial.start()
        self.communicator.start()

        output = self.communicator.do_command(1, action)
        self.assertEqual((49.5, ), output)

        self.assertEqual(14, self.communicator.get_communication_statistics()['bytes_written'])
        self.assertEqual(18, self.communicator.get_communication_statistics()['bytes_read'])

    def test_do_command_timeout_once(self):
        """ Test for timeout in PowerCommunicator.do_command. """
        action = power_api.get_voltage(power_api.POWER_MODULE)

        self.power_data.extend([
            sin(action.create_input(1, 1)),
            sout(bytearray()),
            sin(action.create_input(1, 2)),
            sout(action.create_output(1, 2, 49.5))
        ])
        self.serial.start()
        self.communicator.start()

        output = self.communicator.do_command(1, action)
        self.assertEqual((49.5, ), output)

    def test_do_command_timeout_twice(self):
        """ Test for timeout in PowerCommunicator.do_command. """
        action = power_api.get_voltage(power_api.POWER_MODULE)

        self.power_data.extend([
            sin(action.create_input(1, 1)),
            sout(bytearray()),
            sin(action.create_input(1, 2)),
            sout(bytearray())
        ])
        self.serial.start()
        self.communicator.start()

        with self.assertRaises(CommunicationTimedOutException):
            self.communicator.do_command(1, action)

    def test_do_command_split_data(self):
        """ Test PowerCommunicator.do_command when the data is split over multiple reads. """
        action = power_api.get_voltage(power_api.POWER_MODULE)
        out = action.create_output(1, 1, 49.5)

        self.power_data.extend([
            sin(action.create_input(1, 1)),
            sout(out[:5]), sout(out[5:])
        ])
        self.serial.start()
        self.communicator.start()

        output = self.communicator.do_command(1, action)
        self.assertEqual((49.5, ), output)

    def test_wrong_response(self):
        """ Test PowerCommunicator.do_command when the power module returns a wrong response. """
        action_1 = power_api.get_voltage(power_api.POWER_MODULE)
        action_2 = power_api.get_frequency(power_api.POWER_MODULE)

        self.power_data.extend([
            sin(action_1.create_input(1, 1)),
            sout(action_2.create_output(3, 2, 49.5))
        ])
        self.serial.start()
        self.communicator.start()

        with self.assertRaises(Exception):
            self.communicator.do_command(1, action_1)

    @mark.slow
    def test_address_mode(self):
        """ Test the address mode. """
        events = []

        def handle_events(master_event):
            events.append(master_event)

        self.pubsub.subscribe_master_events(PubSub.MasterTopics.POWER, handle_events)

        sad = power_api.set_addressmode(power_api.POWER_MODULE)
        sad_p1c = power_api.set_addressmode(power_api.P1_CONCENTRATOR)

        self.power_data.extend([
            sin(sad.create_input(power_api.BROADCAST_ADDRESS, 1, power_api.ADDRESS_MODE)),
            sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 2, power_api.ADDRESS_MODE)),
            sout(power_api.want_an_address(power_api.POWER_MODULE).create_output(0, 0)),
            sin(power_api.set_address(power_api.POWER_MODULE).create_input(0, 0, 1)),
            sout(power_api.want_an_address(power_api.ENERGY_MODULE).create_output(0, 0)),
            sin(power_api.set_address(power_api.ENERGY_MODULE).create_input(0, 0, 2)),
            sout(power_api.want_an_address(power_api.P1_CONCENTRATOR).create_output(0, 0)),
            sin(power_api.set_address(power_api.P1_CONCENTRATOR).create_input(0, 0, 3)),
            sout(bytearray()),  # Timeout read after 1 second
            sin(sad.create_input(power_api.BROADCAST_ADDRESS, 3, power_api.NORMAL_MODE)),
            sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 4, power_api.NORMAL_MODE))
        ])
        self.serial.start()
        self.communicator.start()

        self.assertEqual(self.store.get_free_address(), 1)

        self.communicator.start_address_mode()
        self.assertTrue(self.communicator.in_address_mode())
        self.pubsub._publish_all_events()
        time.sleep(0.5)
        assert [] == events

        self.communicator.stop_address_mode()
        self.pubsub._publish_all_events()
        assert MasterEvent(MasterEvent.Types.POWER_ADDRESS_EXIT, {}) in events
        assert len(events) == 1

        self.assertEqual(self.store.get_free_address(), 4)
        self.assertFalse(self.communicator.in_address_mode())


    @mark.slow
    def test_do_command_in_address_mode(self):
        """ Test the behavior of do_command in address mode."""
        action = power_api.get_voltage(power_api.POWER_MODULE)
        sad = power_api.set_addressmode(power_api.POWER_MODULE)
        sad_p1c = power_api.set_addressmode(power_api.P1_CONCENTRATOR)

        self.power_data.extend([
            sin(sad.create_input(power_api.BROADCAST_ADDRESS, 1, power_api.ADDRESS_MODE)),
            sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 2, power_api.ADDRESS_MODE)),
            sout(bytearray()),  # Timeout read after 1 second
            sin(sad.create_input(power_api.BROADCAST_ADDRESS, 3, power_api.NORMAL_MODE)),
            sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 4, power_api.NORMAL_MODE)),
            sin(action.create_input(1, 5)),
            sout(action.create_output(1, 5, 49.5))
        ])
        self.serial.start()
        self.communicator.start()

        self.communicator.start_address_mode()
        with self.assertRaises(InAddressModeException):
            self.communicator.do_command(1, action)

        self.communicator.stop_address_mode()
        self.assertEqual((49.5, ), self.communicator.do_command(1, action))

    @mark.slow
    def test_address_mode_timeout(self):
        """ Test address mode timeout. """
        action = power_api.get_voltage(power_api.POWER_MODULE)
        sad = power_api.set_addressmode(power_api.POWER_MODULE)
        sad_p1c = power_api.set_addressmode(power_api.P1_CONCENTRATOR)

        self.power_data.extend([
            sin(sad.create_input(power_api.BROADCAST_ADDRESS, 1, power_api.ADDRESS_MODE)),
            sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 2, power_api.ADDRESS_MODE)),
            sout(bytearray()),  # Timeout read after 1 second
            sin(sad.create_input(power_api.BROADCAST_ADDRESS, 3, power_api.NORMAL_MODE)),
            sin(sad_p1c.create_input(power_api.BROADCAST_ADDRESS, 4, power_api.NORMAL_MODE)),
            sin(action.create_input(1, 5)),
            sout(action.create_output(1, 5, 49.5))
        ])
        self.communicator = PowerCommunicator(address_mode_timeout=1)
        self.serial.start()
        self.communicator.start()

        self.communicator.start_address_mode()
        time.sleep(1.1)

        self.assertEqual((49.5, ), self.communicator.do_command(1, action))

    @mark.slow
    def test_timekeeper(self):
        """ Test the TimeKeeper. """
        self.store.register_power_module(1, power_api.POWER_MODULE)

        time_action = power_api.set_day_night(power_api.POWER_MODULE)
        times = [power_api.NIGHT for _ in range(8)]
        action = power_api.get_voltage(power_api.POWER_MODULE)

        self.power_data.extend([
            sin(time_action.create_input(1, 1, *times)),
            sout(time_action.create_output(1, 1)),
            sin(action.create_input(1, 2)),
            sout(action.create_output(1, 2, 243))
        ])
        self.communicator = PowerCommunicator(time_keeper_period=1)
        self.serial.start()
        self.communicator.start()

        time.sleep(1.5)
        self.assertEqual((243, ), self.communicator.do_command(1, action))