From f8dee6d878d44b1c139d336ff3799b39ed38f1be Mon Sep 17 00:00:00 2001
From: Pim Hutting
Date: Wed, 29 Oct 2025 09:58:56 +0100
Subject: [PATCH] test: added tests
[
See test_continuous_collect.py
]
[ref]: N25B-206
---
.../behaviours/continuous_collect.py | 2 +-
.../agents/mock_agents/belief_text_mock.py | 3 +-
.../bdi/behaviours/test_continuous_collect.py | 121 +++++++++++++++++-
3 files changed, 122 insertions(+), 4 deletions(-)
diff --git a/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py b/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py
index dbb3bcd..b94dbd9 100644
--- a/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py
+++ b/src/control_backend/agents/belief_collector/behaviours/continuous_collect.py
@@ -67,7 +67,7 @@ class ContinuousBeliefCollector(CyclicBehaviour):
}
"""
- beliefs = payload.get("beliefs", dict)
+ beliefs = payload.get("beliefs", {})
if not beliefs:
logger.info("BeliefCollector: no beliefs to process.")
diff --git a/src/control_backend/agents/mock_agents/belief_text_mock.py b/src/control_backend/agents/mock_agents/belief_text_mock.py
index 05a6a13..d8a223f 100644
--- a/src/control_backend/agents/mock_agents/belief_text_mock.py
+++ b/src/control_backend/agents/mock_agents/belief_text_mock.py
@@ -12,8 +12,7 @@ class BeliefTextAgent(Agent):
# Send multiple beliefs in one JSON payload
payload = {
"type": "belief_extraction_text",
- "beliefs": {"user_said": [["hello","test"],["Can you help me?"],["stop talking to me"],["No"],["Pepper do a dance"]]}
-
+ "beliefs": {"user_said": [["hello test"],["Can you help me?"],["stop talking to me"],["No"],["Pepper do a dance"]]}
}
msg = Message(to=to_jid)
diff --git a/test/unit/agents/bdi/behaviours/test_continuous_collect.py b/test/unit/agents/bdi/behaviours/test_continuous_collect.py
index 0a19cb3..c603048 100644
--- a/test/unit/agents/bdi/behaviours/test_continuous_collect.py
+++ b/test/unit/agents/bdi/behaviours/test_continuous_collect.py
@@ -87,4 +87,123 @@ def test_get_sender_from_message(continuous_collector):
sender_node = continuous_collector._sender_node(msg)
# Assert
- assert sender_node == "agent_node"
\ No newline at end of file
+ assert sender_node == "agent_node"
+
+@pytest.mark.asyncio
+async def test_routes_to_handle_belief_text_by_type(continuous_collector, mocker):
+ msg = MagicMock()
+ msg.body = json.dumps({"type": "belief_extraction_text", "beliefs": {"user_said": [["hi"]]}})
+ msg.sender = "anyone@test"
+ spy = mocker.patch.object(continuous_collector, "_handle_belief_text", new=AsyncMock())
+ await continuous_collector._process_message(msg)
+ spy.assert_awaited_once()
+
+@pytest.mark.asyncio
+async def test_routes_to_handle_belief_text_by_sender(continuous_collector, mocker):
+ msg = MagicMock()
+ msg.body = json.dumps({"beliefs": {"user_said": [["hi"]]}}) # no type
+ msg.sender = "belief_text_agent_mock@test"
+ spy = mocker.patch.object(continuous_collector, "_handle_belief_text", new=AsyncMock())
+ await continuous_collector._process_message(msg)
+ spy.assert_awaited_once()
+
+@pytest.mark.asyncio
+async def test_routes_to_handle_emo_text(continuous_collector, mocker):
+ msg = MagicMock()
+ msg.body = json.dumps({"type": "emotion_extraction_text"})
+ msg.sender = "anyone@test"
+ spy = mocker.patch.object(continuous_collector, "_handle_emo_text", new=AsyncMock())
+ await continuous_collector._process_message(msg)
+ spy.assert_awaited_once()
+
+@pytest.mark.asyncio
+async def test_unrecognized_message_logs_info(continuous_collector, mocker):
+ msg = MagicMock()
+ msg.body = json.dumps({"type": "something_else"})
+ msg.sender = "x@test"
+ logger_mock = mocker.patch("control_backend.agents.belief_collector.behaviours.continuous_collect.logger")
+ await continuous_collector._process_message(msg)
+ logger_mock.info.assert_any_call(
+ "BeliefCollector: unrecognized message (sender=%s, type=%r). Ignoring.", "x", "something_else"
+ )
+
+
+@pytest.mark.asyncio
+async def test_belief_text_no_beliefs(continuous_collector, mocker):
+ msg_payload = {"type": "belief_extraction_text"} # no 'beliefs'
+ logger_mock = mocker.patch("control_backend.agents.belief_collector.behaviours.continuous_collect.logger")
+ await continuous_collector._handle_belief_text(msg_payload, "origin_node")
+ logger_mock.info.assert_any_call("BeliefCollector: no beliefs to process.")
+
+@pytest.mark.asyncio
+async def test_belief_text_beliefs_not_dict(continuous_collector, mocker):
+ payload = {"type": "belief_extraction_text", "beliefs": ["not", "a", "dict"]}
+ logger_mock = mocker.patch("control_backend.agents.belief_collector.behaviours.continuous_collect.logger")
+ await continuous_collector._handle_belief_text(payload, "origin")
+ logger_mock.warning.assert_any_call("BeliefCollector: 'beliefs' is not a dict: %r", ["not", "a", "dict"])
+
+@pytest.mark.asyncio
+async def test_belief_text_values_not_lists(continuous_collector, mocker):
+ payload = {"type": "belief_extraction_text", "beliefs": {"user_said": "not-a-list"}}
+ logger_mock = mocker.patch("control_backend.agents.belief_collector.behaviours.continuous_collect.logger")
+ await continuous_collector._handle_belief_text(payload, "origin")
+ logger_mock.warning.assert_any_call(
+ "BeliefCollector: 'beliefs' values are not all lists: %r", {"user_said": "not-a-list"}
+ )
+
+@pytest.mark.asyncio
+async def test_belief_text_happy_path_logs_items_and_sends(continuous_collector, mocker):
+ payload = {
+ "type": "belief_extraction_text",
+ "beliefs": {"user_said": [["hello", "test"], ["No"]]}
+ }
+ # Your code calls self.send(..); patch it (or switch implementation to self.agent.send and patch that)
+ continuous_collector.send = AsyncMock()
+ logger_mock = mocker.patch("control_backend.agents.belief_collector.behaviours.continuous_collect.logger")
+ await continuous_collector._handle_belief_text(payload, "belief_text_agent_mock")
+
+ logger_mock.info.assert_any_call("BeliefCollector: forwarding %d beliefs.", 1)
+ # and the item logs:
+ logger_mock.info.assert_any_call(" - %s %s", "user_said", "hello test")
+ logger_mock.info.assert_any_call(" - %s %s", "user_said", "No")
+ # make sure we attempted a send
+ continuous_collector.send.assert_awaited_once()
+
+@pytest.mark.asyncio
+async def test_send_beliefs_noop_on_empty(continuous_collector):
+ continuous_collector.send = AsyncMock()
+ await continuous_collector._send_beliefs_to_bdi([], origin="o")
+ continuous_collector.send.assert_not_awaited()
+
+@pytest.mark.asyncio
+async def test_send_beliefs_sends_json_packet(continuous_collector):
+ # Patch .send and capture the message body
+ sent = {}
+
+ async def _fake_send(msg):
+ sent["body"] = msg.body
+ sent["to"] = str(msg.to)
+
+ continuous_collector.send = AsyncMock(side_effect=_fake_send)
+ beliefs = ["user_said hello", "user_said No"]
+ await continuous_collector._send_beliefs_to_bdi(beliefs, origin="origin_node")
+
+ assert "belief_packet" in json.loads(sent["body"])["type"]
+ assert json.loads(sent["body"])["beliefs"] == beliefs
+
+def test_sender_node_no_sender_returns_literal(continuous_collector):
+ msg = MagicMock()
+ msg.sender = None
+ assert continuous_collector._sender_node(msg) == "no_sender"
+
+def test_sender_node_without_at(continuous_collector):
+ msg = MagicMock()
+ msg.sender = "localpartonly"
+ assert continuous_collector._sender_node(msg) == "localpartonly"
+
+@pytest.mark.asyncio
+async def test_belief_text_coerces_non_strings(continuous_collector, mocker):
+ payload = {"type": "belief_extraction_text", "beliefs": {"user_said": [["hi", 123]]}}
+ continuous_collector.send = AsyncMock()
+ await continuous_collector._handle_belief_text(payload, "origin")
+ continuous_collector.send.assert_awaited_once()