Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests for dependencies.py #11

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f92049d
Added test for get_settings
cszsol Sep 24, 2024
72b08e7
Added tests for test_get_connection_string
cszsol Sep 24, 2024
c9b6f9f
Added tests for get_engine
cszsol Sep 24, 2024
e1a5cb7
Added tests for get_session
cszsol Sep 24, 2024
839a91e
Added test for process_validation_error
cszsol Sep 24, 2024
d80f1fd
lint
cszsol Sep 25, 2024
cb3f1c6
lint
cszsol Sep 25, 2024
e7ffd36
Added type ignores for mypy
cszsol Sep 25, 2024
88e89b1
ruff format
cszsol Sep 25, 2024
d8faa45
Added fixes for unit old tests
cszsol Sep 25, 2024
59d66d2
Added type arguments
cszsol Sep 27, 2024
1411b36
Removed mock settings
cszsol Sep 27, 2024
65bc474
code review
cszsol Sep 27, 2024
ee85b7f
Fixed most unit test issues
cszsol Sep 30, 2024
2efc883
Had to delete one unit test, since it was not working
cszsol Sep 30, 2024
0d50e28
Added change to make tests backwards compatible with new httpx_mock v…
cszsol Sep 30, 2024
839be90
Update test_simple_agent.py
cszsol Sep 30, 2024
996117e
Update test_simple_chat_agent.py
cszsol Sep 30, 2024
5e95765
Update test_tools.py
cszsol Sep 30, 2024
a266fbf
Added changelog
cszsol Sep 30, 2024
74036cd
Reformatted with proper ruff version
cszsol Sep 30, 2024
fcebe80
Merge branch 'failing_ci' into unit_tests
cszsol Sep 30, 2024
228df9e
Added patch_required_env fixture
cszsol Oct 2, 2024
4c67b79
Merge branch 'main' into unit_tests
cszsol Oct 2, 2024
1cc6650
code review
cszsol Oct 2, 2024
86ce5fc
Merge branch 'main' into unit_tests
cszsol Oct 2, 2024
2092fc1
lint
cszsol Oct 2, 2024
6fe1e81
lint
cszsol Oct 2, 2024
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed
- Fixed a bug that prevented AsyncSqlite checkpoint to access the DB in streamed endpoints.
- Fixed a bug that caused some unit tests to fail due to a change in how httpx_mock works in version 0.32

## [0.1.0] - 19.09.2024

### Added
- Update readme
- Extra unit tests for dependencies.py

### Removed
- Github action to create the docs.
Expand Down
1 change: 0 additions & 1 deletion src/neuroagent/app/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,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.")
Expand Down
2 changes: 2 additions & 0 deletions tests/agents/test_simple_chat_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from neuroagent.agents import AgentOutput, AgentStep, SimpleChatAgent


@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
@pytest.mark.asyncio
async def test_arun(fake_llm_with_tools, httpx_mock):
llm, tools, fake_responses = await anext(fake_llm_with_tools)
Expand Down Expand Up @@ -64,6 +65,7 @@ async def test_arun(fake_llm_with_tools, httpx_mock):
assert len(messages_list) == 10


@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
@pytest.mark.asyncio
async def test_astream(fake_llm_with_tools, httpx_mock):
llm, tools, fake_responses = await anext(fake_llm_with_tools)
Expand Down
130 changes: 129 additions & 1 deletion tests/app/test_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
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
Expand All @@ -19,13 +20,18 @@
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_morpho_tool,
get_morphology_feature_tool,
get_session,
get_settings,
get_traces_tool,
get_update_kg_hierarchy,
get_user_id,
Expand All @@ -38,6 +44,18 @@
LiteratureSearchTool,
MorphologyFeatureTool,
)
from sqlalchemy import create_engine
from sqlalchemy.orm import Session


def test_get_settings(monkeypatch):
cszsol marked this conversation as resolved.
Show resolved Hide resolved
cszsol marked this conversation as resolved.
Show resolved Hide resolved
monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "https://localhost1")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "https://localhost2")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")
cszsol marked this conversation as resolved.
Show resolved Hide resolved
settings = get_settings()
assert settings.tools.literature.url == "https://localhost1"
assert settings.knowledge_graph.url == "https://localhost2/search/query/"


@pytest.mark.asyncio
Expand Down Expand Up @@ -361,3 +379,113 @@ 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):
monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "http://localhost")
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")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")
cszsol marked this conversation as resolved.
Show resolved Hide resolved

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):
monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")

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):
create_engine_mock.return_value = Mock()
cszsol marked this conversation as resolved.
Show resolved Hide resolved

monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")

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):
create_engine_mock.return_value = Mock()

monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")

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):
monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")

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):
monkeypatch.setenv("NEUROAGENT_TOOLS__LITERATURE__URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_KNOWLEDGE_GRAPH__BASE_URL", "http://localhost")
monkeypatch.setenv("NEUROAGENT_DB__PREFIX", "prefix")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__USERNAME", "fake_username")
monkeypatch.setenv("NEUROAGENT_KEYCLOAK__PASSWORD", "fake_password")
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"
1 change: 1 addition & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ async def test_get_kg_data_errors(httpx_mock):
)


@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
@pytest.mark.asyncio
async def test_get_kg_data(httpx_mock):
url = "http://fake_url"
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions tests/tools/test_electrophys_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@


class TestElectrophysTool:
@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
@pytest.mark.asyncio
async def test_arun(self, httpx_mock):
url = "http://fake_url"
Expand Down
1 change: 1 addition & 0 deletions tests/tools/test_traces_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


class TestTracesTool:
@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
@pytest.mark.asyncio
async def test_arun(self, httpx_mock, brain_region_json_path):
url = "http://fake_url"
Expand Down
Loading