diff --git a/CHANGELOG.md b/CHANGELOG.md index bf37c12..a6faf18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Update readme +- Extra unit tests for dependencies.py ### Removed - Github action to create the docs. diff --git a/src/neuroagent/app/dependencies.py b/src/neuroagent/app/dependencies.py index 430491d..be73680 100644 --- a/src/neuroagent/app/dependencies.py +++ b/src/neuroagent/app/dependencies.py @@ -102,7 +102,6 @@ def get_engine( if "sqlite" in settings.db.prefix: # type: ignore # https://fastapi.tiangolo.com/tutorial/sql-databases/#create-the-sqlalchemy-engine engine_kwargs["connect_args"] = {"check_same_thread": False} - engine = create_engine(**engine_kwargs) else: logger.warning("The SQL db_prefix needs to be set to use the SQL DB.") diff --git a/tests/app/test_dependencies.py b/tests/app/test_dependencies.py index cde38e3..5af7ea5 100644 --- a/tests/app/test_dependencies.py +++ b/tests/app/test_dependencies.py @@ -4,13 +4,16 @@ import os from pathlib import Path from typing import AsyncIterator -from unittest.mock import Mock +from unittest.mock import Mock, patch import pytest +from fastapi import HTTPException from httpx import AsyncClient from langchain_openai import ChatOpenAI from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver +from sqlalchemy import create_engine +from sqlalchemy.orm import Session from neuroagent.agents import SimpleAgent, SimpleChatAgent from neuroagent.app.dependencies import ( @@ -20,14 +23,19 @@ get_brain_region_resolver_tool, get_cell_types_kg_hierarchy, get_chat_agent, + get_connection_string, get_electrophys_feature_tool, + get_engine, get_httpx_client, get_kg_morpho_feature_tool, + get_kg_token, get_language_model, get_literature_tool, get_me_model_tool, get_morpho_tool, get_morphology_feature_tool, + get_session, + get_settings, get_traces_tool, get_update_kg_hierarchy, get_user_id, @@ -43,6 +51,12 @@ ) +def test_get_settings(monkeypatch, patch_required_env): + settings = get_settings() + assert settings.tools.literature.url == "https://fake_url" + assert settings.knowledge_graph.url == "https://fake_url/api/nexus/v1/search/query/" + + @pytest.mark.asyncio async def test_get_httpx_client(): request = Mock() @@ -369,3 +383,93 @@ async def test_get_cell_types_kg_hierarchy( ) assert os.path.exists(settings.knowledge_graph.ct_saving_path) + + +def test_get_connection_string_full(monkeypatch, patch_required_env): + monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "http://") + monkeypatch.setenv("NEUROAGENT_DB__USER", "John") + monkeypatch.setenv("NEUROAGENT_DB__PASSWORD", "Doe") + monkeypatch.setenv("NEUROAGENT_DB__HOST", "localhost") + monkeypatch.setenv("NEUROAGENT_DB__PORT", "5000") + monkeypatch.setenv("NEUROAGENT_DB__NAME", "test") + + settings = Settings() + result = get_connection_string(settings) + assert ( + result == "http://John:Doe@localhost:5000/test" + ), "must return fully formed connection string" + + +def test_get_connection_string_no_prefix(monkeypatch, patch_required_env): + monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "") + + settings = Settings() + + result = get_connection_string(settings) + assert result is None, "should return None when prefix is not set" + + +@patch("neuroagent.app.dependencies.create_engine") +def test_get_engine(create_engine_mock, monkeypatch, patch_required_env): + create_engine_mock.return_value = Mock() + + monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix") + + settings = Settings() + + connection_string = "https://localhost" + retval = get_engine(settings=settings, connection_string=connection_string) + assert retval is not None + + +@patch("neuroagent.app.dependencies.create_engine") +def test_get_engine_no_connection_string( + create_engine_mock, monkeypatch, patch_required_env +): + create_engine_mock.return_value = Mock() + + monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix") + + settings = Settings() + + retval = get_engine(settings=settings, connection_string=None) + assert retval is None + + +@patch("sqlalchemy.orm.Session") +def test_get_session_success(_): + database_url = "sqlite:///:memory:" + engine = create_engine(database_url) + result = next(get_session(engine)) + assert isinstance(result, Session) + + +def test_get_session_no_engine(): + with pytest.raises(HTTPException): + next(get_session(None)) + + +def test_get_kg_token_with_token(monkeypatch, patch_required_env): + monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix") + + settings = Settings() + + token = "Test_Token" + result = get_kg_token(settings, token) + assert result == "Test_Token" + + +def test_get_kg_token_with_settings_knowledge_graph_token( + monkeypatch, patch_required_env +): + monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix") + monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__USE_TOKEN", "true") + monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__TOKEN", "Test_kg_Token") + + settings = Settings() + + token = None + + result = get_kg_token(settings, token) + + assert result == "Test_kg_Token" diff --git a/tests/tools/test_basic_tool.py b/tests/tools/test_base_tool.py similarity index 100% rename from tests/tools/test_basic_tool.py rename to tests/tools/test_base_tool.py