diff --git a/nbxmpp/modules/activity.py b/nbxmpp/modules/activity.py
index d6318be..25b0207 100644
--- a/nbxmpp/modules/activity.py
+++ b/nbxmpp/modules/activity.py
@@ -56,7 +56,7 @@ def _process_pubsub_activity(
return
activity_node = item.getTag("activity", namespace=Namespace.ACTIVITY)
- if not activity_node.getChildren():
+ if activity_node is None or not activity_node.getChildren():
self._log.info("Received activity: %s - no activity set", properties.jid)
return
diff --git a/nbxmpp/modules/location.py b/nbxmpp/modules/location.py
index 8eaa676..fda501f 100644
--- a/nbxmpp/modules/location.py
+++ b/nbxmpp/modules/location.py
@@ -55,7 +55,7 @@ def _process_pubsub_location(
return
location_node = item.getTag("geoloc", namespace=Namespace.LOCATION)
- if not location_node.getChildren():
+ if location_node is None or not location_node.getChildren():
self._log.info("Received location: %s - no location set", properties.jid)
return
diff --git a/nbxmpp/modules/mood.py b/nbxmpp/modules/mood.py
index bec3264..da98605 100644
--- a/nbxmpp/modules/mood.py
+++ b/nbxmpp/modules/mood.py
@@ -56,7 +56,7 @@ def _process_pubsub_mood(
return
mood_node = item.getTag("mood", namespace=Namespace.MOOD)
- if not mood_node.getChildren():
+ if mood_node is None or not mood_node.getChildren():
self._log.info("Received mood: %s - removed mood", properties.jid)
return
diff --git a/nbxmpp/modules/tune.py b/nbxmpp/modules/tune.py
index f056f8b..e2150ad 100644
--- a/nbxmpp/modules/tune.py
+++ b/nbxmpp/modules/tune.py
@@ -55,7 +55,7 @@ def _process_pubsub_tune(
return
tune_node = item.getTag("tune", namespace=Namespace.TUNE)
- if not tune_node.getChildren():
+ if tune_node is None or not tune_node.getChildren():
self._log.info("Received tune: %s - no tune set", properties.jid)
return
diff --git a/test/unit/test_activity.py b/test/unit/test_activity.py
index 7c0f645..a1f32c4 100644
--- a/test/unit/test_activity.py
+++ b/test/unit/test_activity.py
@@ -53,3 +53,18 @@ def _on_message(_con, _stanza, properties):
)
self.dispatcher.process_data(event)
+
+ def test_activity_item_without_payload(self):
+ # An item published without an payload must not crash the handler.
+ event = """
+
+
+
+
+
+
+
+ """
+
+ with self.assertNoLogs("nbxmpp", level="ERROR"):
+ self.dispatcher.process_data(event)
diff --git a/test/unit/test_location.py b/test/unit/test_location.py
index 362a69b..2b072b4 100644
--- a/test/unit/test_location.py
+++ b/test/unit/test_location.py
@@ -96,3 +96,18 @@ def _on_message(_con, _stanza, properties):
)
self.dispatcher.process_data(event)
+
+ def test_location_item_without_payload(self):
+ # An item published without a payload must not crash the handler.
+ event = """
+
+
+
+
+
+
+
+ """
+
+ with self.assertNoLogs("nbxmpp", level="ERROR"):
+ self.dispatcher.process_data(event)
diff --git a/test/unit/test_mood.py b/test/unit/test_mood.py
index 8db0124..cd40b86 100644
--- a/test/unit/test_mood.py
+++ b/test/unit/test_mood.py
@@ -49,3 +49,18 @@ def _on_message(_con, _stanza, properties):
)
self.dispatcher.process_data(event)
+
+ def test_mood_item_without_payload(self):
+ # An item published without a payload must not crash the handler.
+ event = """
+
+
+
+
+
+
+
+ """
+
+ with self.assertNoLogs("nbxmpp", level="ERROR"):
+ self.dispatcher.process_data(event)
diff --git a/test/unit/test_tune.py b/test/unit/test_tune.py
index 1ea4e86..4055f2b 100644
--- a/test/unit/test_tune.py
+++ b/test/unit/test_tune.py
@@ -62,3 +62,19 @@ def _on_message(_con, _stanza, properties):
)
self.dispatcher.process_data(event)
+
+ def test_tune_item_without_payload(self):
+ # Some clients signal "stopped listening" with an empty instead
+ # of retracting it, so the payload can be absent.
+ event = """
+
+
+
+
+
+
+
+ """
+
+ with self.assertNoLogs("nbxmpp", level="ERROR"):
+ self.dispatcher.process_data(event)