Skip to content

Commit cde189a

Browse files
committed
Updates to InelsMqtt tests
1 parent eee32b9 commit cde189a

File tree

3 files changed

+135
-23
lines changed

3 files changed

+135
-23
lines changed

inelsmqtt/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,9 @@ def subscribe(self, topics, qos=0, options=None, properties=None) -> dict[str, s
338338
r, mid = self.__client.subscribe(filtered_topics, options, properties)
339339
if r != mqtt.MQTT_ERR_SUCCESS:
340340
_LOGGER.error("Failed to subscribe to topics: %s", filtered_topics)
341+
# Clean up the state for failed subscriptions
342+
for topic, _ in filtered_topics:
343+
self.__is_subscribed_list.pop(topic, None)
341344
return {}
342345

343346
for topic, _ in filtered_topics:

tests/test_device.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ def test_device_initialization(device, mqtt_mock):
4040
assert device.is_available == False
4141
assert device.mqtt == mqtt_mock
4242

43-
mqtt_mock.subscribe.assert_any_call(device.state_topic)
44-
mqtt_mock.subscribe.assert_any_call(device.connected_topic, 0, None, None)
45-
4643

4744
def test_device_availability(device):
4845
# Simulate an update to the device value

tests/test_inels_mqtt.py

Lines changed: 132 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,50 @@ def test_instance_initialization_pytest_style(inels_mqtt, mqtt_config):
3636
assert inels_mqtt._InelsMqtt__port == mqtt_config["port"] # pylint: disable=protected-access
3737

3838

39-
def test_publish_pytest_style(mqtt_client_mock, inels_mqtt):
40-
"""Test publishing a message using pytest."""
41-
mqtt_client_mock.publish.return_value = (mqtt.MQTT_ERR_SUCCESS, 1)
39+
def test_publish_successful(mqtt_client_mock, inels_mqtt):
40+
"""Test successful publishing of a message."""
41+
info = Mock()
42+
info.rc = mqtt.MQTT_ERR_SUCCESS
43+
info.is_published.return_value = True
4244

43-
inels_mqtt.publish("inels/status/10e97f8b7d30/01/01E8", "data")
45+
mqtt_client_mock.publish.return_value = info
46+
47+
result = inels_mqtt.publish("inels/status/10e97f8b7d30/01/01E8", "data")
48+
49+
mqtt_client_mock.publish.assert_called_once_with("inels/status/10e97f8b7d30/01/01E8", "data", 0, True, None)
50+
51+
assert result == True
52+
53+
54+
def test_publish_unsuccessful(mqtt_client_mock, inels_mqtt):
55+
"""Test unsuccessful publishing of a message."""
56+
info = Mock()
57+
info.rc = mqtt.MQTT_ERR_NO_CONN
58+
59+
mqtt_client_mock.publish.return_value = info
60+
61+
result = inels_mqtt.publish("inels/status/10e97f8b7d30/01/01E8", "data")
62+
63+
mqtt_client_mock.publish.assert_called_once_with("inels/status/10e97f8b7d30/01/01E8", "data", 0, True, None)
64+
65+
assert result == False
66+
67+
68+
def test_publish_exception(mqtt_client_mock, inels_mqtt):
69+
"""Test publishing a message with an exception during wait_for_publish."""
70+
info = Mock()
71+
info.rc = mqtt.MQTT_ERR_SUCCESS
72+
info.is_published.return_value = False
73+
info.wait_for_publish.side_effect = Exception("Timeout")
74+
75+
mqtt_client_mock.publish.return_value = info
76+
77+
result = inels_mqtt.publish("inels/status/10e97f8b7d30/01/01E8", "data")
4478

45-
# Assert that the publish method was called with the correct parameters
4679
mqtt_client_mock.publish.assert_called_once_with("inels/status/10e97f8b7d30/01/01E8", "data", 0, True, None)
4780

81+
assert result == False
82+
4883

4984
def test_is_available_true_false_based_on__on_connect_function(mqtt_client_mock, inels_mqtt):
5085
"""Testing if the broker is available with result True or False based on the on_connect function."""
@@ -75,30 +110,74 @@ def test_discovery_all_with_tree_messages(mqtt_client_mock, inels_mqtt):
75110
inels_mqtt, Mock(), msg
76111
)
77112

113+
mqtt_client_mock.subscribe.return_value = (mqtt.MQTT_ERR_SUCCESS, 1)
114+
78115
devices = inels_mqtt.discovery_all()
79116
assert len(devices) == 3
80117

81118

82-
def test_subscribe(mqtt_client_mock, inels_mqtt):
83-
"""Test subscribing to a topic."""
119+
def test_subscribe_successful(mqtt_client_mock, inels_mqtt):
120+
"""Test successful subscription to topics."""
121+
topics = [("inels/status/10e97f8b7d30/01/01E8", 0), ("inels/status/10e97f8b7d30/01/01E9", 0)]
84122

85-
topic = "inels/status/10e97f8b7d30/01/01E8"
86-
msg = type(
87-
"msg",
88-
(object,),
89-
{"topic": topic, "payload": "02\n01\n"},
90-
)
123+
mqtt_client_mock.subscribe.return_value = (mqtt.MQTT_ERR_SUCCESS, 1)
124+
125+
# Simulate the behavior of __on_subscribe
126+
def wait_for_side_effect(condition_func, timeout):
127+
for topic, _ in topics:
128+
inels_mqtt._InelsMqtt__is_subscribed_list[topic] = True
129+
inels_mqtt._InelsMqtt__expected_mid.pop(topic, None)
130+
131+
inels_mqtt._InelsMqtt__subscription_condition.wait_for = wait_for_side_effect
132+
inels_mqtt._InelsMqtt__timeout = 0.1
133+
result = inels_mqtt.subscribe(topics)
134+
135+
mqtt_client_mock.subscribe.assert_called_once_with(topics, None, None)
136+
assert result == {topic: None for topic, _ in topics}
137+
138+
for topic, _ in topics:
139+
assert inels_mqtt._InelsMqtt__is_subscribed_list[topic] == True
140+
assert topic not in inels_mqtt._InelsMqtt__expected_mid
91141

92-
inels_mqtt._InelsMqtt__on_message(inels_mqtt, Mock(), msg)
93142

94-
# mqtt_client_mock.is_connected.return_value = True
95-
# mqtt_client_mock.subscribe.return_value = (mqtt.MQTT_ERR_SUCCESS, 1)
143+
def test_subscribe_unsuccessful(mqtt_client_mock, inels_mqtt):
144+
"""Test unsuccessful subscription to a topic."""
145+
topics = [("inels/status/10e97f8b7d30/01/01E8", 0), ("inels/status/10e97f8b7d30/01/01E9", 0)]
96146

97-
last_messages = inels_mqtt.subscribe(topic)
147+
mqtt_client_mock.subscribe.return_value = (mqtt.MQTT_ERR_NO_CONN, 0)
98148

99-
mqtt_client_mock.subscribe.assert_called_once_with(topic, 0, None, None)
100-
assert inels_mqtt._InelsMqtt__is_subscribed_list[topic] == True
101-
assert msg.payload == last_messages
149+
result = inels_mqtt.subscribe(topics)
150+
151+
mqtt_client_mock.subscribe.assert_called_once_with(topics, None, None)
152+
assert result == {}
153+
154+
# Check that failed topics are removed
155+
for topic, _ in topics:
156+
assert topic not in inels_mqtt._InelsMqtt__is_subscribed_list
157+
assert topic not in inels_mqtt._InelsMqtt__expected_mid
158+
159+
160+
def test_subscribe_unsuccessful_wait_for(mqtt_client_mock, inels_mqtt):
161+
"""Test unsuccessful subscription to a topic with wait_for."""
162+
topics = [("inels/status/10e97f8b7d30/01/01E8", 0), ("inels/status/10e97f8b7d30/01/01E9", 0)]
163+
164+
mqtt_client_mock.subscribe.return_value = (mqtt.MQTT_ERR_SUCCESS, 1)
165+
166+
# Simulate initial state
167+
for i, (topic, _) in enumerate(topics):
168+
inels_mqtt._InelsMqtt__is_subscribed_list[topic] = False
169+
inels_mqtt._InelsMqtt__expected_mid[topic] = i
170+
171+
inels_mqtt._InelsMqtt__timeout = 0.01
172+
result = inels_mqtt.subscribe(topics)
173+
174+
mqtt_client_mock.subscribe.assert_called_once_with(topics, None, None)
175+
assert result == {"inels/status/10e97f8b7d30/01/01E8": None, "inels/status/10e97f8b7d30/01/01E9": None}
176+
177+
# Check that failed topics are removed
178+
for topic, _ in topics:
179+
assert topic not in inels_mqtt._InelsMqtt__is_subscribed_list
180+
assert topic not in inels_mqtt._InelsMqtt__expected_mid
102181

103182

104183
def test_message_property(inels_mqtt):
@@ -154,3 +233,36 @@ def dummy_callback(prm):
154233

155234
# Check if no listeners are left
156235
assert len(inels_mqtt.list_of_listeners) == 0
236+
237+
238+
def test_unsubscribe_success(mqtt_client_mock, inels_mqtt):
239+
"""Test successful unsubscribe."""
240+
topic = "inels/status/10e97f8b7d30/01/01E8"
241+
inels_mqtt._InelsMqtt__is_subscribed_list = {topic: True}
242+
inels_mqtt._InelsMqtt__expected_mid = {topic: 1}
243+
inels_mqtt._InelsMqtt__timeout = 0.01
244+
245+
mqtt_client_mock.unsubscribe.return_value = (mqtt.MQTT_ERR_SUCCESS, 1)
246+
247+
# Simulate the behavior of __on_unsubscribe
248+
def wait_for_side_effect(condition_func, timeout):
249+
inels_mqtt._InelsMqtt__is_subscribed_list.pop(topic, None)
250+
inels_mqtt._InelsMqtt__expected_mid.pop(topic, None)
251+
252+
inels_mqtt._InelsMqtt__subscription_condition.wait_for = wait_for_side_effect
253+
254+
inels_mqtt.unsubscribe(topic)
255+
256+
mqtt_client_mock.unsubscribe.assert_called_once_with(topic)
257+
258+
assert topic not in inels_mqtt._InelsMqtt__is_subscribed_list
259+
assert topic not in inels_mqtt._InelsMqtt__expected_mid
260+
261+
262+
def test_unsubscribe_nonexistent_topic(mqtt_client_mock, inels_mqtt):
263+
"""Test unsubscribe edge cases."""
264+
inels_mqtt._InelsMqtt__is_subscribed_list = {}
265+
266+
inels_mqtt.unsubscribe("non_existent_topic")
267+
268+
mqtt_client_mock.unsubscribe.assert_not_called()

0 commit comments

Comments
 (0)