Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions apps/backend/integrations/graphiti/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,10 +635,13 @@ def get_graphiti_status() -> dict:
try:
# Attempt to import the main graphiti_memory module
import graphiti_core # noqa: F401
from graphiti_core.driver.falkordb_driver import FalkorDriver # noqa: F401

# If we got here, packages are importable
status["available"] = True # pragma: no cover
# Try LadybugDB first (preferred for Python 3.12+), fall back to kuzu
try:
import real_ladybug # noqa: F401
except ImportError:
import kuzu # noqa: F401
status["available"] = True
except ImportError as e:
status["available"] = False
status["reason"] = f"Graphiti packages not installed: {e}"
Expand Down
8 changes: 4 additions & 4 deletions apps/backend/integrations/graphiti/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,16 @@ def mock_graphiti_core():


@pytest.fixture
def mock_falkor_driver():
"""Mock graphiti_core.driver.falkordb_driver.FalkorDriver.
def mock_kuzu_driver():
"""Mock graphiti_core.driver.kuzu_driver.KuzuDriver.

Prevents actual FalkorDB connections during tests.
Prevents actual LadybugDB/kuzu connections during tests.

Yields:
tuple: (mock_driver_class, mock_driver_instance)
"""
with patch(
"integrations.graphiti.queries_pkg.graphiti.graphiti_core.driver.falkordb_driver.FalkorDriver"
"integrations.graphiti.queries_pkg.graphiti.graphiti_core.driver.kuzu_driver.KuzuDriver"
) as mock_driver:
mock_instance = MagicMock()
mock_driver.return_value = mock_instance
Expand Down
19 changes: 11 additions & 8 deletions apps/backend/integrations/graphiti/tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1054,20 +1054,23 @@ def test_get_graphiti_status_with_validation_errors(self, clean_env):
assert "OPENAI_API_KEY" in status["errors"][0]

def test_get_graphiti_status_invalid_config_sets_reason(self, clean_env):
"""Test get_graphiti_status sets reason when config is invalid.
"""Test get_graphiti_status with validation errors (embedder misconfigured).

This tests lines 628-629 where the reason is set from validation errors.
When packages are installed but embedder config has errors, available should
still be True (embedder is optional - keyword search fallback exists).
Validation errors are reported in the errors list for informational purposes.
"""
os.environ["GRAPHITI_ENABLED"] = "true"
os.environ["GRAPHITI_EMBEDDER_PROVIDER"] = "voyage"

status = get_graphiti_status()

assert status["enabled"] is True
assert status["available"] is False
# When config is invalid, reason should be set from errors
assert status["reason"] != ""
# With LadybugDB/kuzu installed, available should be True
assert status["available"] is True
# Validation errors are informational (embedder is optional)
assert len(status["errors"]) > 0
assert "VOYAGE_API_KEY" in status["errors"][0]
Comment on lines 1056 to 1078
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test is fragile as it depends on graphiti_core and real_ladybug/kuzu being installed in the test environment. If they are not, the test will fail because get_graphiti_status will correctly report available: False.

To make the test more robust and isolate the logic under test (that available is True when packages are present, even with other configuration errors), you should mock the necessary imports.

Please also ensure MagicMock is imported from unittest.mock at the top of the file.

    def test_get_graphiti_status_invalid_config_sets_reason(self, clean_env):
        """Test get_graphiti_status with validation errors (embedder misconfigured).

        When packages are installed but embedder config has errors, available should
        still be True (embedder is optional - keyword search fallback exists).
        Validation errors are reported in the errors list for informational purposes.
        """
        os.environ["GRAPHITI_ENABLED"] = "true"
        os.environ["GRAPHITI_EMBEDDER_PROVIDER"] = "voyage"

        # Mock imports to ensure test is independent of environment
        with patch.dict(
            "sys.modules",
            {"graphiti_core": MagicMock(), "real_ladybug": MagicMock()},
        ):
            status = get_graphiti_status()

        assert status["enabled"] is True
        # With LadybugDB/kuzu installed, available should be True
        assert status["available"] is True
        # Validation errors are informational (embedder is optional)
        assert len(status["errors"]) > 0
        assert "VOYAGE_API_KEY" in status["errors"][0]


@pytest.mark.slow
def test_get_graphiti_status_with_graphiti_installed(self, clean_env):
Expand All @@ -1089,9 +1092,9 @@ def test_get_graphiti_status_with_graphiti_installed(self, clean_env):
assert "reason" in status
assert "errors" in status

# Note: Line 641 (status["available"] = True) requires falkordb to be installed.
# Since falkordb is not installed in the test environment, that line is marked
# with pragma: no cover. The except clause (lines 642-644) is tested here.
# Note: Line 641 (status["available"] = True) requires LadybugDB/kuzu to be installed.
# Since LadybugDB/kuzu may not be installed in all test environments, that line
# may be marked with pragma: no cover. The except clause is tested here.

def test_get_available_providers_empty(self, clean_env):
"""Test get_available_providers with no credentials."""
Expand Down
4 changes: 2 additions & 2 deletions apps/backend/integrations/graphiti/tests/test_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ async def test_handles_provider_error(self):

# Mock graphiti_core imports to succeed
mock_graphiti = MagicMock()
mock_falkordb_driver = MagicMock()
mock_kuzu_driver = MagicMock()

# Mock provider creation to raise ProviderError
with patch("graphiti_providers.create_llm_client") as mock_create_llm:
Expand All @@ -275,7 +275,7 @@ async def test_handles_provider_error(self):
{
"graphiti_core": MagicMock(Graphiti=mock_graphiti),
"graphiti_core.driver": MagicMock(),
"graphiti_core.driver.falkordb_driver": mock_falkordb_driver,
"graphiti_core.driver.kuzu_driver": mock_kuzu_driver,
"graphiti_providers": MagicMock(
ProviderError=ProviderError,
create_embedder=MagicMock(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ class TestTestGraphitiConnection:
"""Tests for the test_graphiti_connection async function.

Note: The function now uses embedded LadybugDB via patched KuzuDriver
instead of remote FalkorDB with host/port credentials.
instead of remote database with host/port credentials.
"""

@pytest.mark.asyncio
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/runners/spec_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def main():
python spec_runner.py --task "Update text" --complexity simple

# Complex integration (auto-detected)
python spec_runner.py --task "Add Graphiti memory integration with FalkorDB"
python spec_runner.py --task "Add Graphiti memory integration with LadybugDB"

# Interactive mode
python spec_runner.py --interactive
Expand Down
Loading