def test_remote_value(self): """Test string representation of remote value.""" xknx = XKNX() remote_value = RemoteValue( xknx, group_address="1/2/3", device_name="MyDevice", group_address_state="1/2/4", ) assert ( str(remote_value) == '<RemoteValue device_name="MyDevice" feature_name="Unknown" <1/2/3, 1/2/4, [], None /> />' ) remote_value.value = 34 assert (str(remote_value) == '<RemoteValue device_name="MyDevice" feature_name="Unknown" ' "<1/2/3, 1/2/4, [], 34 /> />") remote_value_passive = RemoteValue( xknx, group_address=["1/2/3", "1/2/4", "i-test"], device_name="MyDevice", ) assert ( str(remote_value_passive) == "<RemoteValue device_name=\"MyDevice\" feature_name=\"Unknown\" <1/2/3, None, ['1/2/4', 'i-test'], None /> />" )
def test_register_unregister(self): """Test register and unregister.""" xknx = XKNX(loop=self.loop) self.assertEqual(len(xknx.state_updater._workers), 0) # register when state address and sync_state is set remote_value_1 = RemoteValue(xknx, sync_state=True, group_address_state=GroupAddress("1/1/1")) self.assertEqual(len(xknx.state_updater._workers), 1) # don't register when sync_state is False remote_value_2 = RemoteValue(xknx, sync_state=False, group_address_state=GroupAddress("1/1/1")) self.assertEqual(len(xknx.state_updater._workers), 1) # manual registration xknx.state_updater.register_remote_value(remote_value_2) self.assertEqual(len(xknx.state_updater._workers), 2) # manual unregister xknx.state_updater.unregister_remote_value(remote_value_1) # only remote_value_2 remaining self.assertEqual(len(xknx.state_updater._workers), 1) self.assertEqual( list(xknx.state_updater._workers.keys())[0], id(remote_value_2)) # unregister on RemoteValue.__del__() remote_value_2.__del__() self.assertEqual(len(xknx.state_updater._workers), 0)
def test_register_unregister(self): """Test register and unregister.""" xknx = XKNX() assert len(xknx.state_updater._workers) == 0 # register when state address and sync_state is set remote_value_1 = RemoteValue(xknx, sync_state=True, group_address_state=GroupAddress("1/1/1")) assert len(xknx.state_updater._workers) == 1 # don't register when sync_state is False remote_value_2 = RemoteValue(xknx, sync_state=False, group_address_state=GroupAddress("1/1/1")) assert len(xknx.state_updater._workers) == 1 # manual registration xknx.state_updater.register_remote_value(remote_value_2) assert len(xknx.state_updater._workers) == 2 # manual unregister xknx.state_updater.unregister_remote_value(remote_value_1) # only remote_value_2 remaining assert len(xknx.state_updater._workers) == 1 assert list( xknx.state_updater._workers.keys())[0] == id(remote_value_2) # unregister on RemoteValue.__del__() remote_value_2.__del__() assert len(xknx.state_updater._workers) == 0
def test_warn_to_knx(self): """Test for warning if to_knx is not implemented.""" xknx = XKNX(loop=self.loop) remote_value = RemoteValue(xknx) with patch('logging.Logger.warning') as mock_warn: remote_value.to_knx(23) mock_warn.assert_called_with('to_knx not implemented for %s', 'RemoteValue')
def test_warn_payload_valid(self): """Test for warning if payload_valid is not implemented.""" xknx = XKNX(loop=self.loop) remote_value = RemoteValue(xknx) with patch('logging.Logger.warning') as mock_warn: remote_value.payload_valid(DPTBinary(0)) mock_warn.assert_called_with( 'payload_valid not implemented for %s', 'RemoteValue')
def test_warn_to_knx(self): """Test for warning if to_knx is not implemented.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("logging.Logger.warning") as mock_warn: remote_value.to_knx(23) mock_warn.assert_called_with("'to_knx()' not implemented for %s", "RemoteValue")
def test_warn_from_knx(self): """Test for warning if from_knx is not implemented.""" xknx = XKNX(loop=self.loop) remote_value = RemoteValue(xknx) with patch("logging.Logger.warning") as mock_warn: remote_value.from_knx(DPTBinary(0)) mock_warn.assert_called_with("'from_knx()' not implemented for %s", "RemoteValue")
def test_warn_payload_valid(self): """Test for warning if payload_valid is not implemented.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("logging.Logger.warning") as mock_warn: remote_value.payload_valid(DPTBinary(0)) mock_warn.assert_called_with( "'payload_valid()' not implemented for %s", "RemoteValue")
def test_info_set_uninitialized(self): """Test for info if RemoteValue is not initialized.""" xknx = XKNX(loop=self.loop) remote_value = RemoteValue(xknx) with patch('logging.Logger.info') as mock_info: self.loop.run_until_complete(asyncio.Task(remote_value.set(23))) mock_info.assert_called_with( 'Setting value of uninitialized device: %s (value: %s)', 'Unknown', 23)
def test_info_set_unwritable(self): """Test for warning if RemoteValue is read only.""" xknx = XKNX(loop=self.loop) remote_value = RemoteValue(xknx, group_address_state=GroupAddress('1/2/3')) with patch('logging.Logger.warning') as mock_info: self.loop.run_until_complete(asyncio.Task(remote_value.set(23))) mock_info.assert_called_with( 'Attempted to set value for non-writable device: %s (value: %s)', 'Unknown', 23)
def test_info_set_uninitialized(self): """Test for info if RemoteValue is not initialized.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("logging.Logger.info") as mock_info: self.loop.run_until_complete(remote_value.set(23)) mock_info.assert_called_with( "Setting value of uninitialized device: %s - %s (value: %s)", "Unknown", "Unknown", 23, )
def test_info_set_unwritable(self): """Test for warning if RemoteValue is read only.""" xknx = XKNX() remote_value = RemoteValue(xknx, group_address_state=GroupAddress("1/2/3")) with patch("logging.Logger.warning") as mock_info: self.loop.run_until_complete(remote_value.set(23)) mock_info.assert_called_with( "Attempted to set value for non-writable device: %s - %s (value: %s)", "Unknown", "Unknown", 23, )
def test_process_invalid_payload(self): """Test if exception is raised when processing telegram with invalid payload.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("xknx.remote_value.RemoteValue.payload_valid") as patch_valid, patch( "xknx.remote_value.RemoteValue.has_group_address" ) as patch_has_group_address: patch_valid.return_value = False patch_has_group_address.return_value = True telegram = Telegram(GroupAddress("1/2/1"), payload=DPTArray((0x01, 0x02))) with self.assertRaises(CouldNotParseTelegram): self.loop.run_until_complete(remote_value.process(telegram))
def test_remote_value(self): """Test string representation of remote value.""" xknx = XKNX(loop=self.loop) remote_value = RemoteValue( xknx, group_address='1/2/3', device_name="MyDevice", group_address_state='1/2/4') self.assertEqual( str(remote_value), '<RemoteValue device_name="MyDevice" GroupAddress("1/2/3")/GroupAddress("1/2/4")/None/None/>') remote_value.payload = DPTArray([0x01, 0x02]) self.assertEqual( str(remote_value), '<RemoteValue device_name="MyDevice" GroupAddress("1/2/3")/GroupAddress("1/2/4")/<DPTArray value="[0x1,0x2]" />/None/>')
async def test_process_unsupported_payload(self): """Test warning is logged when processing telegram with unsupported payload.""" xknx = XKNX() remote_value = RemoteValue(xknx) telegram = Telegram( destination_address=GroupAddress("1/2/1"), payload=GroupValueWrite(DPTArray((0x01, 0x02))), ) with patch( "xknx.remote_value.RemoteValue.payload_valid" ) as patch_valid, patch( "xknx.remote_value.RemoteValue.has_group_address" ) as patch_has_group_address, patch( "xknx.remote_value.RemoteValue.from_knx") as patch_from, patch( "logging.Logger.warning") as mock_warning: patch_valid.return_value = telegram.payload.value patch_has_group_address.return_value = True patch_from.side_effect = ConversionError("TestError") assert await remote_value.process(telegram) is False mock_warning.assert_called_once_with( "Can not process %s for %s - %s: %s", telegram, "Unknown", "Unknown", ConversionError("TestError"), )
async def test_set_value(self): """Test set_value awaitable.""" xknx = XKNX() remote_value = RemoteValue(xknx) remote_value.to_knx = lambda value: DPTArray( DPT2ByteFloat.to_knx(value)) remote_value.after_update_cb = AsyncMock() await remote_value.update_value(3.3) assert remote_value.value == 3.3 remote_value.after_update_cb.assert_called_once() assert xknx.telegrams.qsize() == 0 # invalid value raises ConversionError with pytest.raises(ConversionError): await remote_value.update_value("a") assert remote_value.value == 3.3
def test_remote_value(self): """Test string representation of remote value.""" xknx = XKNX() remote_value = RemoteValue( xknx, group_address="1/2/3", device_name="MyDevice", group_address_state="1/2/4", ) self.assertEqual( str(remote_value), '<RemoteValue device_name="MyDevice" feature_name="Unknown" GroupAddress("1/2/3")/GroupAddress("1/2/4")/None/None/>', ) remote_value.payload = DPTArray([0x01, 0x02]) self.assertEqual( str(remote_value), '<RemoteValue device_name="MyDevice" feature_name="Unknown" ' 'GroupAddress("1/2/3")/GroupAddress("1/2/4")/<DPTArray value="[0x1,0x2]" />/None/>', )
def test_process_unsupported_payload(self): """Test if exception is raised when processing telegram with unsupported payload.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("xknx.remote_value.RemoteValue.payload_valid") as patch_valid, patch( "xknx.remote_value.RemoteValue.has_group_address" ) as patch_has_group_address: patch_valid.return_value = False patch_has_group_address.return_value = True telegram = Telegram( destination_address=GroupAddress("1/2/1"), payload=object(), ) with self.assertRaisesRegex( CouldNotParseTelegram, r".*payload not a GroupValueWrite or GroupValueResponse.*", ): self.loop.run_until_complete(remote_value.process(telegram))
def test_process_listening_address(self): """Test if listening group addresses are processed.""" xknx = XKNX() remote_value = RemoteValue( xknx, group_address="1/2/3", passive_group_addresses=["1/1/1"] ) self.assertTrue(remote_value.writable) self.assertFalse(remote_value.readable) # RemoteValue is initialized with only passive group address self.assertTrue(remote_value.initialized) with patch("xknx.remote_value.RemoteValue.payload_valid") as patch_valid: patch_valid.return_value = True test_payload = DPTArray((0x01, 0x02)) telegram = Telegram(GroupAddress("1/1/1"), payload=test_payload) self.assertTrue( self.loop.run_until_complete( asyncio.Task(remote_value.process(telegram)) ) ) self.assertEqual(remote_value.payload, test_payload)
async def test_stat_updater_default(self, default, sync_state_value, expected_interval, expected_tracker_type): """Test setting a default for StateUpdater.""" xknx = XKNX(state_updater=default) remote_value = RemoteValue(xknx, sync_state=sync_state_value, group_address_state=GroupAddress("1/1/1")) assert (xknx.state_updater._workers[id(remote_value)].update_interval == expected_interval * 60) assert (xknx.state_updater._workers[id(remote_value)].tracker_type == expected_tracker_type)
async def test_process_invalid_payload(self): """Test if exception is raised when processing telegram with invalid payload.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("xknx.remote_value.RemoteValue.has_group_address", remote_value=True): telegram = Telegram( destination_address=GroupAddress("1/2/1"), payload=GroupValueWrite(DPTArray((0x01, 0x02))), ) assert await remote_value.process(telegram) is False
def test_state_updater_start_update_stop(self): """Test start, update_received and stop of StateUpdater.""" xknx = XKNX() remote_value_1 = RemoteValue(xknx, sync_state=True, group_address_state=GroupAddress("1/1/1")) remote_value_2 = RemoteValue(xknx, sync_state=True, group_address_state=GroupAddress("1/1/2")) xknx.state_updater._workers[id(remote_value_1)] = Mock() xknx.state_updater._workers[id(remote_value_2)] = Mock() assert not xknx.state_updater.started xknx.connection_manager._state = XknxConnectionState.CONNECTED xknx.state_updater.start() assert xknx.state_updater.started # start xknx.state_updater._workers[id( remote_value_1)].start.assert_called_once_with() xknx.state_updater._workers[id( remote_value_2)].start.assert_called_once_with() # update xknx.state_updater.update_received(remote_value_2) xknx.state_updater._workers[id( remote_value_1)].update_received.assert_not_called() xknx.state_updater._workers[id( remote_value_2)].update_received.assert_called_once_with() # stop xknx.state_updater.stop() assert not xknx.state_updater.started xknx.state_updater._workers[id( remote_value_1)].stop.assert_called_once_with() xknx.state_updater._workers[id( remote_value_2)].stop.assert_called_once_with() # don't update when not started xknx.state_updater.update_received(remote_value_1) xknx.state_updater._workers[id( remote_value_1)].update_received.assert_not_called()
def test_state_updater_start_update_stop(self): """Test start, update_received and stop of StateUpdater.""" xknx = XKNX(loop=self.loop) remote_value_1 = RemoteValue(xknx, sync_state=True, group_address_state=GroupAddress("1/1/1")) remote_value_2 = RemoteValue(xknx, sync_state=True, group_address_state=GroupAddress("1/1/2")) xknx.state_updater._workers[id(remote_value_1)] = Mock() xknx.state_updater._workers[id(remote_value_2)] = Mock() self.assertFalse(xknx.state_updater.started) xknx.state_updater.start() self.assertTrue(xknx.state_updater.started) # start xknx.state_updater._workers[id( remote_value_1)].start.assert_called_once_with() xknx.state_updater._workers[id( remote_value_2)].start.assert_called_once_with() # update xknx.state_updater.update_received(remote_value_2) xknx.state_updater._workers[id( remote_value_1)].update_received.assert_not_called() xknx.state_updater._workers[id( remote_value_2)].update_received.assert_called_once_with() # stop xknx.state_updater.stop() self.assertFalse(xknx.state_updater.started) xknx.state_updater._workers[id( remote_value_1)].stop.assert_called_once_with() xknx.state_updater._workers[id( remote_value_2)].stop.assert_called_once_with() # don't update when not started xknx.state_updater.update_received(remote_value_1) xknx.state_updater._workers[id( remote_value_1)].update_received.assert_not_called()
async def test_process_passive_address(self): """Test if passive group addresses are processed.""" xknx = XKNX() remote_value = RemoteValue(xknx, group_address=["1/2/3", "1/1/1"]) assert remote_value.writable assert not remote_value.readable # RemoteValue is initialized with only passive group address assert remote_value.initialized with patch("xknx.remote_value.RemoteValue.payload_valid" ) as patch_always_valid: patch_always_valid.side_effect = lambda payload: payload test_payload = DPTArray((0x01, 0x02)) telegram = Telegram( destination_address=GroupAddress("1/1/1"), payload=GroupValueWrite(test_payload), ) assert await remote_value.process(telegram) assert remote_value.telegram.payload.value == test_payload
async def test_process_invalid_payload(self): """Test if exception is raised when processing telegram with invalid payload.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("xknx.remote_value.RemoteValue.payload_valid" ) as patch_valid, patch( "xknx.remote_value.RemoteValue.has_group_address" ) as patch_has_group_address: patch_valid.return_value = None patch_has_group_address.return_value = True telegram = Telegram( destination_address=GroupAddress("1/2/1"), payload=GroupValueWrite(DPTArray((0x01, 0x02))), ) with pytest.raises(CouldNotParseTelegram, match=r".*payload invalid.*"): await remote_value.process(telegram)
async def test_process_unsupported_payload(self): """Test if exception is raised when processing telegram with unsupported payload.""" xknx = XKNX() remote_value = RemoteValue(xknx) with patch("xknx.remote_value.RemoteValue.payload_valid" ) as patch_valid, patch( "xknx.remote_value.RemoteValue.has_group_address" ) as patch_has_group_address: patch_valid.return_value = False patch_has_group_address.return_value = True telegram = Telegram(destination_address=GroupAddress("1/2/1"), payload=object()) with pytest.raises( CouldNotParseTelegram, match= r".*payload not a GroupValueWrite or GroupValueResponse.*", ): await remote_value.process(telegram)
async def test_get_set_value(self): """Test value getter and setter.""" xknx = XKNX() remote_value = RemoteValue(xknx) remote_value.to_knx = lambda value: DPTArray( DPT2ByteFloat.to_knx(value)) remote_value.after_update_cb = AsyncMock() assert remote_value.value is None remote_value.value = 2.2 assert remote_value.value == 2.2 # invalid value raises ConversionError with pytest.raises(ConversionError): remote_value.value = "a" # new value is used in response Telegram test_payload = remote_value.to_knx(2.2) remote_value._send = AsyncMock() await remote_value.respond() remote_value._send.assert_called_with(test_payload, response=True) # callback is not called when setting value programmatically remote_value.after_update_cb.assert_not_called() # no Telegram was sent to the queue assert xknx.telegrams.qsize() == 0
def test_tracker_parser_invalid_options(self, logging_warning_mock): """Test parsing invalid tracker options.""" xknx = XKNX() def _get_only_tracker() -> _StateTracker: # _workers is unordered so it just works with 1 item self.assertEqual(len(xknx.state_updater._workers), 1) _tracker = next(iter(xknx.state_updater._workers.values())) return _tracker # INVALID string remote_value_invalid = RemoteValue( xknx, sync_state="invalid", group_address_state=GroupAddress("1/1/1")) logging_warning_mock.assert_called_once_with( 'Could not parse StateUpdater tracker_options "%s" for %s. Using default %s %s minutes.', "invalid", remote_value_invalid, StateTrackerType.EXPIRE, 60, ) self.assertEqual(_get_only_tracker().tracker_type, StateTrackerType.EXPIRE) self.assertEqual(_get_only_tracker().update_interval, 60 * 60) remote_value_invalid.__del__() logging_warning_mock.reset_mock() # intervall too long remote_value_long = RemoteValue( xknx, sync_state=1441, group_address_state=GroupAddress("1/1/1")) logging_warning_mock.assert_called_once_with( "StateUpdater interval of %s to long for %s. Using maximum of %s minutes (1 day)", 1441, remote_value_long, 1440, ) remote_value_long.__del__()
def test_eq(self): """Test __eq__ operator.""" xknx = XKNX() remote_value1 = RemoteValue(xknx, group_address=GroupAddress("1/1/1")) remote_value2 = RemoteValue(xknx, group_address=GroupAddress("1/1/1")) remote_value3 = RemoteValue(xknx, group_address=GroupAddress("1/1/2")) remote_value4 = RemoteValue(xknx, group_address=GroupAddress("1/1/1")) remote_value4.fnord = "fnord" def _callback(): pass remote_value5 = RemoteValue(xknx, group_address=GroupAddress("1/1/1"), after_update_cb=_callback()) self.assertEqual(remote_value1, remote_value2) self.assertEqual(remote_value2, remote_value1) self.assertNotEqual(remote_value1, remote_value3) self.assertNotEqual(remote_value3, remote_value1) self.assertNotEqual(remote_value1, remote_value4) self.assertNotEqual(remote_value4, remote_value1) self.assertEqual(remote_value1, remote_value5) self.assertEqual(remote_value5, remote_value1)
def test_eq(self): """Test __eq__ operator.""" xknx = XKNX() remote_value1 = RemoteValue(xknx, group_address=GroupAddress("1/1/1")) remote_value2 = RemoteValue(xknx, group_address=GroupAddress("1/1/1")) remote_value3 = RemoteValue(xknx, group_address=GroupAddress("1/1/2")) remote_value4 = RemoteValue(xknx, group_address=GroupAddress("1/1/1")) remote_value4.fnord = "fnord" def _callback(): pass remote_value5 = RemoteValue(xknx, group_address=GroupAddress("1/1/1"), after_update_cb=_callback()) assert remote_value1 == remote_value2 assert remote_value2 == remote_value1 assert remote_value1 != remote_value3 assert remote_value3 != remote_value1 assert remote_value1 != remote_value4 assert remote_value4 != remote_value1 assert remote_value1 == remote_value5 assert remote_value5 == remote_value1