""" Tests for the retrieve_context LangGraph node. These tests focus on: - Combining knowledge-base and user-memory context - Retrieving user memory only on the first turn - Normalizing both sources into the same retrieved_context shape To run this test, enter the following code in the terminal: PYTHONPATH=src pytest tests/test_retrieve_context_node.py -q -s """ from __future__ import annotations from walkxr_ai.core.nodes import build_retrieve_context_node class FakeRetrievalEngine: """ Fake knowledgebase retriever returning a fixed normalized result. """ def retrieve(self, query: str) -> list[dict]: return [ { "text": "Knowledge: grounding techniques help with anxiety.", "source": "knowledge_base", "score": 0.9, "metadata": {}, } ] class FakeNode: """ Fake node that mimics the LlamaIndex interface used by the node. """ def __init__(self, text: str, metadata: dict) -> None: self._text = text self.metadata = metadata def get_text(self) -> str: return self._text class FakeResult: """ Fake result that mimics a LlamaIndex retrieval result. """ def __init__(self, text: str) -> None: self.node = FakeNode(text, {"user_id": "user_1"}) self.score = 0.8 class FakeUserMemoryStore: """ Fake user-memory store returning LlamaIndex-like result objects. """ def query_memories(self, user_id: str, query: str): return [FakeResult("Memory: the user finds reflective walks relaxing.")] def test_retrieve_context_combines_knowledge_and_memory_on_new_session() -> None: """ Test #1: Test to verify that the knowledgebase (non-memory) context and user memory context are combined on the first turn. """ retrieve_context = build_retrieve_context_node( FakeRetrievalEngine(), FakeUserMemoryStore(), ) state = { "user_input": "How can I relax?", "user_id": "user_1", "turn_index": 0, } result = retrieve_context(state) assert result["phase"] == "context_retrieved" # Is the phase correct? assert any(item["source"] == "knowledge_base" for item in result["retrieved_context"]) # Is knowledgebase context included? assert any(item["source"] == "user_memory" for item in result["retrieved_context"]) # Is user memory context included? def test_retrieve_context_skips_memory_after_first_turn() -> None: """ Test #2: Test to verify that user-memory retrieval is skipped on subsequent turns after the first turn of the session, even if user_id is present. This ensures that we only retrieve user memory on the first turn, as intended. """ retrieve_context = build_retrieve_context_node( FakeRetrievalEngine(), FakeUserMemoryStore(), ) state = { "user_input": "How can I relax?", "user_id": "user_1", "turn_index": 1, } result = retrieve_context(state) assert result["phase"] == "context_retrieved" # Is the phase correct? assert len(result["retrieved_context"]) == 1 # Is only one context item returned (the knowledgebase context)? assert all(item["source"] != "user_memory" for item in result["retrieved_context"]) # Is user memory context skipped? def test_retrieve_context_skips_memory_if_no_user_id() -> None: """ Test #3: Test to verify that user-memory retrieval is skipped if user_id is blank, even on the first turn. This ensures that we only retrieve user memory when we have a valid user_id, as intended. """ retrieve_context = build_retrieve_context_node( FakeRetrievalEngine(), FakeUserMemoryStore(), ) state = { "user_input": "How can I relax?", "user_id": "", "turn_index": 0, } result = retrieve_context(state) assert result["phase"] == "context_retrieved" # Is the phase correct? assert len(result["retrieved_context"]) == 1 # Is only one context item returned (the knowledgebase context)? assert all(item["source"] != "user_memory" for item in result["retrieved_context"]) # Is user memory context skipped? def test_retrieve_context_returns_expected_structure() -> None: """ Test #4: Test to verify that the retrieved context items from both knowledgebase and user memory are returned in the expected normalized structure, with keys: text, source, score, and metadata. This ensures that the node is correctly normalizing different context sources into a consistent format for downstream nodes. """ retrieve_context = build_retrieve_context_node( FakeRetrievalEngine(), FakeUserMemoryStore(), ) state = { "user_input": "How can I relax?", "user_id": "user_1", "turn_index": 0, } result = retrieve_context(state) assert result["phase"] == "context_retrieved" # Is the phase correct? for item in result["retrieved_context"]: # Does each item have the expected keys? assert "text" in item assert "source" in item assert "score" in item assert "metadata" in item