async def test_message_to_topic(self): """Test converting a message to a topic.""" async with async_protocol_manager() as protocol: tests = await import_commands() for test_info in tests: self._topic = None address = repr(random_address()) curr_test = tests[test_info] if curr_test.get("address") is not None: curr_test["address"] = address msgs = [create_message(curr_test)] curr_topic = curr_test["topic"].format(address) subscribe_topic(self.capture_topic, curr_topic) send_data(msgs, protocol.read_queue) try: await asyncio.sleep(0.1) assert self._topic.name == curr_topic except asyncio.TimeoutError: raise AssertionError( "Failed timed out {} with test topic {}".format( test_info, curr_test.get("topic") ) ) except (AssertionError, AttributeError): raise AssertionError( "Failed test {} with test topic {}".format( test_info, curr_test.get("topic") ) ) finally: unsubscribe_topic(self.capture_topic, curr_topic)
async def test_receive_on_msg(self): """Test receiving an ON message.""" async with async_protocol_manager() as protocol: last_topic = None def topic_received(cmd1, cmd2, target, user_data, hops_left, topic=pub.AUTO_TOPIC): """Receive the OFF topic for a device.""" nonlocal last_topic last_topic = topic.name address = random_address() byte_data = create_std_ext_msg(address, 0x80, 0x11, 0xFF, target=Address("000001")) expected_topic = "{}.{}.on.broadcast".format(address.id, 1) pub.subscribe(topic_received, expected_topic) on_cmd = DataItem(byte_data, 0) data = [on_cmd] send_data(data, protocol.read_queue) await asyncio.sleep(0.05) assert last_topic == expected_topic
async def test_send_on_all_link_broadcast_topic(self): """Test sending the broadcast ON command.""" from pyinsteon.handlers.to_device.on_level_all_link_broadcast import ( OnLevelAllLinkBroadcastCommand, ) topic_lock = asyncio.Lock() async with async_protocol_manager(): last_topic = None def topic_received(cmd1, cmd2, user_data, topic=pub.AUTO_TOPIC): """Receive the OFF topic for a device.""" nonlocal last_topic last_topic = topic.name if topic_lock.locked(): topic_lock.release() group = 3 target = Address(bytearray([0x00, 0x00, group])) ack_topic = "ack.{}.on.all_link_broadcast".format(target.id) pub.subscribe(topic_received, ack_topic) cmd = OnLevelAllLinkBroadcastCommand(group=group) await topic_lock.acquire() await cmd.async_send() # Mock transport auto sends ACK/NAK try: await asyncio.wait_for(topic_lock.acquire(), 2) assert last_topic == ack_topic except asyncio.TimeoutError: assert ack_topic is None if topic_lock.locked(): topic_lock.release()
async def test_inbound(self): """Test direct command.""" async with async_protocol_manager(auto_ack=False) as protocol: tests = await import_commands() subscribe_topic(self.async_validate_values, pub.ALL_TOPICS) for test_info in tests: self._current_test = test_info test_command = tests[test_info] cmd_class = test_command.get("command") params = test_command.get("params") inbound_message = test_command.get("message") if params.get("address") == "": params["address"] = random_address() inbound_message["address"] = params["address"] self._assert_tests = test_command.get("assert_tests") obj = get_class_or_method(commands, cmd_class) cmd = obj(**params) inbound_data_item = create_message(inbound_message, 0) self._call_count = 0 send_data([inbound_data_item], protocol.read_queue) await sleep(0.1) assert self._call_count == 1 assert self._assert_result
async def test_send_on_topic(self): """Test sending the ON command.""" async with async_protocol_manager(): received_topic = "" def expected_topic_received(cmd1, cmd2, user_data, topic=pub.AUTO_TOPIC): nonlocal received_topic received_topic = topic.name address = random_address() on_topic = "send.{}.1.direct".format(ON) topics = [ TopicItem(on_topic, { "address": address, "on_level": 0xFF, "group": 0 }, 0) ] self._last_topic = None expected_topic = "ack.{}.1.on.direct".format(address.id) pub.subscribe(expected_topic_received, expected_topic) send_topics(topics) await asyncio.sleep(0.05) assert received_topic == expected_topic
async def test_connected(self): """Test the connected property.""" with patch("pyinsteon.protocol.protocol.publish_topic", self.mock_publish_topic): async with async_protocol_manager() as protocol: assert self.topic == "connection.made" assert protocol.connected protocol.close() assert not protocol.connected assert protocol.message_queue
async def test_device_commands(self): """Test sending a command from a device.""" async with async_protocol_manager(): tests = await import_commands() await sleep(0.1) for device_type in tests: # ["SwitchedLightingControl_DinRail"]: test_configs = tests[device_type] for command in test_configs: await self._execute_command(device_type, command, test_configs[command])
async def test_connection_failed(self): """Test the connected property.""" with patch("pyinsteon.protocol.protocol.publish_topic", self.mock_publish_topic): try: async with async_protocol_manager(connect=False, retry=False): await asyncio.sleep(0.1) assert False except ConnectionError: await asyncio.sleep(0.1) assert self.topic == "connection.failed"
async def test_data_received(self): """Test the data_received method.""" def dummy_nak_listener(*args, **kwargs): """Listen for NAK. This ensures we send the NAK rather than resend the message. """ data = [ { "data": "025003040506070809110b", "topic": "030405.1.on.direct" }, { "data": "02500304050607", "topic": None }, { "data": "0809130b", "topic": "030405.1.off.direct" }, ] with patch("pyinsteon.protocol.protocol.publish_topic", self.mock_publish_topic): async with async_protocol_manager(auto_ack=False) as protocol: for test in data: self.topic = None protocol.data_received(unhexlify(test["data"])) await asyncio.sleep(0.1) try: assert self.topic == test["topic"] except AssertionError: raise AssertionError( f"Failed with data {test['data']}: Topic: {self.topic} Expected: {test['topic']}" ) # Test when the modem only responds with a NAK rather than the original message. nak_topic = "nak.0a0b0c.1.on.direct" pub.subscribe(dummy_nak_listener, nak_topic) protocol.write(unhexlify("02620a0b0c09110b")) await asyncio.sleep(0.1) self.topic = None protocol.data_received(unhexlify("15")) await asyncio.sleep(0.1) assert self.topic == nak_topic # Test that a NAK is resent rather than published as a topic. self.topic = None protocol.data_received(unhexlify("02620d0e0f09110b15")) await asyncio.sleep(0.1) assert self.topic is None
async def test_command(self): """Test direct command.""" async with async_protocol_manager() as protocol: msgs = [] def listen_for_ack(): send_data(msgs, protocol.read_queue) tests = await import_commands() subscribe_topic(self.validate_values, pub.ALL_TOPICS) subscribe_topic(listen_for_ack, "ack") for test_info in tests: address = random_address() self._current_test = test_info test_command = tests[test_info] command = test_command.get("command") cmd_class = command.get("class") params = command.get("params") if params.get("address"): params["address"] = address send_params = command.get("send_params") test_response = test_command.get("response") obj = get_class_or_method(commands, cmd_class) cmd = obj(**params) messages = test_command.get("messages") msgs = [] for msg_dict in messages: #msg_dict = messages[message] msg_dict["address"] = address msgs.append(create_message(msg_dict)) self._assert_tests = test_command.get("assert_tests") self._call_count = 0 try: response = await cmd.async_send(**send_params) except Exception as ex: raise Exception("Failed test {} with error: {}".format( self._current_test, str(ex))) try: if test_response: assert int(response) == test_response if self._assert_tests: call_count = test_command.get("call_count", 1) assert self._call_count == call_count except AssertionError: raise AssertionError( "Failed test: {} command response: {} call count {}". format(self._current_test, response, self._call_count)) await sleep(0.1) assert self._assert_result
async def test_x10_commands(self): """Test X10 commands.""" async with async_protocol_manager(): x10_types = ["X10OnOff", "X10Dimmable"] for device_type in x10_types: device_class = getattr(device_types, device_type) device = device_class("A", 3) result = await device.async_on() assert int(result) == 1 assert device.groups[1].value == 255 result = await device.async_off() assert int(result) == 1 assert device.groups[1].value == 0
async def test_connection_retry(self): """Test the connected property.""" with patch("pyinsteon.protocol.protocol.publish_topic", self.mock_publish_topic): try: async with async_protocol_manager(connect=False, retry=True, retries=[1, 1]) as protocol: await asyncio.sleep(0.1) assert protocol.connected assert self.topic == "connection.made" except ConnectionError: assert False
async def test_pause_resume_writer(self): """Test the pause_writer and resume_writer methods.""" async with async_protocol_manager(auto_ack=False) as protocol: await asyncio.sleep(0.1) protocol.write(unhexlify("02620a0b0c09110b")) await asyncio.sleep(0.1) assert protocol.message_queue.empty() protocol.pause_writing() await asyncio.sleep(0.1) protocol.write(unhexlify("026201020309110b")) await asyncio.sleep(0.1) assert not protocol.message_queue.empty() protocol.resume_writing() await asyncio.sleep(0.1) assert protocol.message_queue.empty()
async def test_modem_inbound(self): """Test direct command.""" async with async_protocol_manager(auto_ack=False) as protocol: tests = await import_modem_commands() pub.subscribe(self.validate_values, pub.ALL_TOPICS) for test_info in tests: self._current_test = test_info test_command = tests[test_info] command = test_command.get("command") cmd_class = command.get("class") inbound_message = command.get("inbound_message")["data"] self._assert_tests = test_command.get("assert_tests") obj = get_class_or_method(commands, cmd_class) cmd = obj() inbound_data = unhexlify(f"02{inbound_message}") ack_response_item = DataItem(inbound_data, 0) send_data([ack_response_item], protocol.read_queue) await sleep(0.1)
async def test_receive_on_msg(self): """Test receiving an ON message.""" topic_lock = asyncio.Lock() async with async_protocol_manager() as protocol: last_topic = None def topic_received(cmd1, cmd2, target, user_data, hops_left, topic=pub.AUTO_TOPIC): """Receive the OFF topic for a device.""" nonlocal last_topic last_topic = topic.name if topic_lock.locked(): topic_lock.release() address = random_address() byte_data = create_std_ext_msg(address, 0x80, 0x11, 0xFF, target=Address("000001")) expected_topic = "{}.{}.on.broadcast".format(address.id, 1) pub.subscribe(topic_received, expected_topic) on_cmd = DataItem(byte_data, 0) data = [on_cmd] await topic_lock.acquire() send_data(data, protocol.read_queue) try: await asyncio.wait_for(topic_lock.acquire(), 2) assert last_topic == expected_topic except asyncio.TimeoutError: assert expected_topic is None if topic_lock.locked(): topic_lock.release()
async def test_send_on_topic(self): """Test sending the ON command.""" topic_lock = asyncio.Lock() async with async_protocol_manager(): received_topic = "" def expected_topic_received(cmd1, cmd2, user_data, topic=pub.AUTO_TOPIC): nonlocal received_topic received_topic = topic.name if topic_lock.locked(): topic_lock.release() address = random_address() on_topic = "send.{}.1.direct".format(ON) topics = [ TopicItem(on_topic, { "address": address, "on_level": 0xFF, "group": 0 }, 0) ] self._last_topic = None expected_topic = "ack.{}.1.on.direct".format(address.id) pub.subscribe(expected_topic_received, expected_topic) await topic_lock.acquire() send_topics(topics) try: await asyncio.wait_for(topic_lock.acquire(), 2) assert received_topic == expected_topic except asyncio.TimeoutError: assert expected_topic is None if topic_lock.locked(): topic_lock.release()