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()