コード例 #1
0
class LogicTest(unittest.TestCase):
    def setUp(self):
        self.state_mock = Mock()
        self.state_mock.get_electric_meters_dict.return_value = {}
        self.state_mock.get_electric_meters.return_value = {}
        self.db_mock = Mock()
        self.plugin_loader_mock = Mock()
        self.data_per_hour = 3600
        self.logic = Logic(self.state_mock, self.db_mock,
                           self.plugin_loader_mock, self.data_per_hour)

        self.plugin_mock = Mock()
        self.plugin_loader_mock.get_plugin.return_value = self.plugin_mock

    def test_call_serialize_hook(self):
        plugin_type = 'TEST_TYPE'
        serialize_dict = Mock()
        electric_meter = Mock()
        electric_meter.get_type.return_value = plugin_type
        # serialize_hook = Mock()
        self.plugin_mock.serialize_electric_meter_dict.return_value = serialize_dict
        # self.logic.set_serialize_hook(serialize_hook)

        # Test
        self.logic._call_serialize_hook(electric_meter)

        # Assert
        electric_meter.get_type.assert_called_once()
        self.plugin_loader_mock.get_plugin.assert_called_once_with(plugin_type)
        self.plugin_mock.serialize_electric_meter_dict.assert_called_once_with(
            electric_meter)
        self.state_mock.update_electric_meter.assert_called_once_with(
            electric_meter, serialize_dict)
        # serialize_hook.assert_called_once()

    def test_add_electric_meter(self):
        # Create random values
        name = ''.join(
            random.choice(string.ascii_lowercase) for i in range(10))
        type = 'TEST_PLUGIN'
        custom = {
            'value': random.random() * random.randint(1, 100),
            'pin': random.randint(1, 10),
            'active_low': random.choice([True, False])
        }
        self.plugin_mock.validate_custom_data.return_value = True
        created_electric_meter_mock = Mock()
        self.plugin_mock.create_electric_meter.return_value = created_electric_meter_mock

        # Add electric meter
        new_meter, id = self.logic.add_electric_meter(name, type, custom)

        # Assertion
        self.plugin_loader_mock.get_plugin.assert_called_once_with(type)
        self.plugin_mock.validate_custom_data.assert_called_once_with(custom)
        self.plugin_mock.create_electric_meter.assert_called_once_with(
            name, type, custom)
        created_electric_meter_mock.set_serialize_hook.assert_called_once()

        self.state_mock.add_electric_meter.assert_called_once_with(
            created_electric_meter_mock)

        self.db_mock.add_data_src.assert_called_once_with(id)

    def test_add_electric_meter_invalid_plugin(self):
        invalid_plugin_type = 'invalid type'
        self.plugin_loader_mock.get_plugin = Mock(
            side_effect=PluginNotFoundException())

        # Add electric meter
        self.assertRaises(PluginNotFoundException,
                          self.logic.add_electric_meter, 'test',
                          invalid_plugin_type, {})
        self.plugin_loader_mock.get_plugin.assert_called_once_with(
            invalid_plugin_type)

    def test_add_invalid_custom(self):
        # Create random values
        name = ''.join(
            random.choice(string.ascii_lowercase) for i in range(10))
        type = 'TEST_PLUGIN'
        custom = {
            'value': random.random() * random.randint(1, 100),
            'pin': random.randint(1, 10),
            'active_low': random.choice([True, False])
        }
        self.plugin_mock.validate_custom_data.return_value = False

        # Add electric meter
        self.assertRaises(logic.Logic.InvalidCustomElectricMeterDataException,
                          self.logic.add_electric_meter, name, type, custom)

        # Assertion
        self.plugin_loader_mock.get_plugin.assert_called_once_with(type)
        self.plugin_mock.validate_custom_data.assert_called_once_with(custom)

    def test_remove_electric_meter(self):
        # Add electric meter
        electric_meter_id = 0
        electric_meter = Mock()
        self.state_mock.get_electric_meters_dict.return_value = {
            electric_meter_id: electric_meter
        }
        # Remove electric meter
        removed_meter = self.logic.remove_electric_meter(electric_meter_id)

        self.db_mock.remove_data_src.assert_called_once_with(electric_meter_id)
        # Check if electric meter has been removed
        self.assertEqual(electric_meter, removed_meter)
        self.state_mock.remove_electric_meter.assert_called_once_with(
            electric_meter_id)

    def test_remove_not_existing_meter(self):
        invalid_meter_id = -100

        self.assertRaises(KeyError, self.logic.remove_electric_meter,
                          invalid_meter_id)

    def test_change_electric_meter(self):
        electric_meter_id = 10
        name = Mock()
        custom = MagicMock()
        electric_meter_type = 'PLUGIN_TEST'
        electric_meter_mock = Mock()
        electric_meter_dict_mock = MagicMock()
        electric_meter_dict_mock['type'] = electric_meter_type
        electric_meter_mock.get_type.return_value = electric_meter_type
        self.plugin_mock.change_electric_meter.return_value = True
        self.state_mock.get_electric_meters.return_value = {
            electric_meter_id: electric_meter_mock
        }
        self.state_mock.get_electric_meters_dict.return_value = electric_meter_dict_mock

        # Test
        changed = self.logic.change_electric_meter(electric_meter_id,
                                                   name=name,
                                                   custom=custom)

        # Assertion
        electric_meter_mock.get_type.assert_called_once()
        self.plugin_loader_mock.get_plugin.assert_called_once_with(
            electric_meter_type)
        self.plugin_mock.change_electric_meter.assert_called_once_with(
            electric_meter_mock, name, custom)
        self.assertTrue(changed)
        electric_meter_mock.serialize.assert_called_once()

    def test_change_electric_meter_no_change(self):
        # Setup
        electric_meter_id = 10
        electric_meter_type = 'PLUGIN_TYPE'
        electric_meter = Mock()
        electric_meter.get_type.return_value = electric_meter_type
        electric_meter_dict = MagicMock()
        electric_meter_dict['type'] = electric_meter_type
        name = Mock()
        custom = MagicMock()

        self.state_mock.get_electric_meters.return_value = {
            electric_meter_id: electric_meter
        }
        self.state_mock.get_electric_meters_dict.return_value = {
            electric_meter_id: electric_meter_dict
        }
        self.plugin_mock.change_electric_meter.return_value = False

        # Test
        changed = self.logic.change_electric_meter(electric_meter_id,
                                                   name=name,
                                                   custom=custom)

        # Check if Electric Meter data was changed
        self.assertFalse(changed)
        electric_meter.get_type.assert_called_once()
        self.plugin_loader_mock.get_plugin.assert_called_once_with(
            electric_meter_type)
        self.plugin_mock.change_electric_meter.assert_called_once_with(
            electric_meter, name, custom)
        electric_meter.serialize.assert_not_called()

    def test_change_not_existing_meter(self):
        invalid_meter_id = -100
        electric_meters = MagicMock()
        electric_meters.__getitem__.side_effect = KeyError()
        electric_meters_dict = MagicMock()
        electric_meters_dict.__getitem__.side_effect = KeyError()
        self.state_mock.get_electric_meters.return_value = electric_meters
        self.state_mock.get_electric_meters_dict.return_value = electric_meters_dict

        # Assert
        self.assertRaises(KeyError, self.logic.change_electric_meter,
                          invalid_meter_id)

    def test_invalid_change_on_meter(self):
        # Setup
        electric_meter_id = 10
        electric_meter_type = 'PLUGIN_TYPE'
        electric_meter = Mock()
        electric_meter_dict = MagicMock()
        electric_meter.get_type.return_value = electric_meter_type
        name = Mock()
        custom = MagicMock()
        self.plugin_mock.change_electric_meter.side_effect = ValueError()
        self.state_mock.get_electric_meters.return_value = {
            electric_meter_id: electric_meter
        }
        self.state_mock.get_electric_meters_dict.return_value = {
            electric_meter_id: electric_meter_dict
        }

        # Assert
        self.assertRaises(ValueError,
                          self.logic.change_electric_meter,
                          electric_meter_id,
                          name=name,
                          custom=custom)
        electric_meter.get_type.assert_called_once()
        self.plugin_loader_mock.get_plugin.assert_called_once_with(
            electric_meter_type)
        self.plugin_mock.change_electric_meter.assert_called_once_with(
            electric_meter, name, custom)
        electric_meter.serialize.assert_not_called()

    def test_read_electric_meters(self):
        # Setup Electric Meter
        em1_id = 0
        em2_id = 1
        em1 = Mock()
        em1.get_amount.return_value = 1
        em2 = Mock()
        em2.get_amount.return_value = 10
        self.state_mock.get_electric_meters.return_value = {
            em1_id: em1,
            em2_id: em2
        }

        # Test _read_electric_meters()
        for i in range(10):
            em1.get_amount.return_value = i
            em2.get_amount.return_value = i * 10
            # Test
            self.logic._read_electric_meters()

            # Assert
            self.db_mock.add_data.assert_has_calls(
                [call(i, em1_id), call(i * 10, em2_id)])

            em1.get_amount.assert_called_once()
            em2.get_amount.assert_called_once()

            em1.reset.assert_called_once()
            em2.reset.assert_called_once()

            em1.reset_mock()
            em2.reset_mock()

        # Assert database values
        self.db_mock.add_data.assert_has_calls(
            [call(i * 10, em2_id)
             for i in range(10)] + [call(i, em1_id) for i in range(10)],
            any_order=True)

    def test_read_electric_meters_with_error(self):
        # Setup Electric Meter
        error_message = 'Error reading electric meter \'%s\' data'
        em1_id = 0
        em2_id = 1
        em1 = Mock()
        formatted_error_message = error_message % em1_id
        em1.get_amount.side_effect = plugin.ElectricMeterSPI.ElectricMeterReadException(
            error_message)
        em2 = Mock()
        em2.get_amount.return_value = 10
        self.state_mock.get_electric_meters.return_value = {
            em1_id: em1,
            em2_id: em2
        }

        # Test / Assert
        with self.assertLogs('logic.Logic', level=logging.ERROR) as log:
            self.logic._read_electric_meters()
            self.assertIn('ERROR:logic.Logic:' + formatted_error_message,
                          log.output)

        # Assert
        self.db_mock.add_data.assert_has_calls(
            [call(None, em1_id), call(10, em2_id)])

        em1.get_amount.assert_called_once()
        em2.get_amount.assert_called_once()

        em1.reset.assert_called_once()
        em2.reset.assert_called_once()