Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 1 addition & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,8 @@ jobs:
- name: Install dependencies
run: pip install -r requirements.txt -r requirements-loader.txt -r requirements-test.txt

# test_endpoints.py and test_callback.py use an older docker-compose harness
# that builds the full app image; they are not yet wired up for CI (tracked
# in issue #383). Everything else runs headless.
- name: Unit tests
run: pytest -m "not integration" --ignore=tests/test_endpoints.py --ignore=tests/test_callback.py
run: pytest -m "not integration"

# GitHub's ubuntu runners have Docker, so testcontainers can start a real
# Redis for the loader integration test.
Expand Down
5 changes: 3 additions & 2 deletions node_normalizer/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,12 @@ async def status() -> Dict:
# Can we figure out the NodeNorm version?
nodenorm_version = "unknown"
if "version" in app.openapi_schema["info"]:
nodenorm_version = "v" + app.openapi_schema["info"]["version"]
nodenorm_version = app.openapi_schema["info"]["version"]

return {
"status": "running",
"nodenorm_version": nodenorm_version,
"version": nodenorm_version,
"backend": "redis",
"babel_version": babel_version,
"babel_version_url": babel_version_url,
"biolink_model": {
Expand Down
4 changes: 2 additions & 2 deletions tests/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ requests/docker/testcontainers landmine) are in `documentation/Loader.md`.

## The shared-app-singleton pitfall

`test_norm.py` and `test_setid.py` assign to `app.state.*` at **import time**,
`frontend/test_norm.py` and `frontend/test_setid.py` assign to `app.state.*` at **import time**,
mutating the shared `node_normalizer.server.app` singleton for the rest of the
process. Don't assume that app is pristine in a later test, and don't add more
import-time mutation. New tests should build their own fake app
Expand Down Expand Up @@ -38,7 +38,7 @@ mock — it avoids reimplementing the loader's canonical-id/db-5 keying. See
`create_node` reads Redis beyond these dbs, so the stored-`preferred_name` path needs
nothing more.

For a pure-unit version that skips Docker entirely, `test_normalizer.py` drives
For a pure-unit version that skips Docker entirely, `frontend/test_normalizer.py` drives
`get_normalized_nodes` / `create_node` against a tiny `_MgetRedis` mock — cheaper, but
you must construct the redis values (canonical-id keys, db-5 JSON, gene-first conflation
list) by hand, so it's easy to encode an assumption the loader doesn't actually make.
1 change: 1 addition & 0 deletions tests/frontend/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

7 changes: 6 additions & 1 deletion tests/test_callback.py → tests/frontend/test_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import time

import pytest
import reasoner_pydantic
import requests
import fastapi
Expand All @@ -11,7 +12,11 @@

logger = LoggingUtil.init_logging()

premerged_response = Path(__file__).parent / "resources" / "premerged_response.json"
# Uses an older docker-compose harness that builds the full app image; not yet
# wired up for CI (tracked in issue #383).
pytestmark = pytest.mark.skip(reason="requires docker-compose harness, see #383")

premerged_response = Path(__file__).parent.parent / "resources" / "premerged_response.json"


def test_async_query_callback(session):
Expand Down
19 changes: 12 additions & 7 deletions tests/test_endpoints.py → tests/frontend/test_endpoints.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Test node_normalizer server.py"""
import json

import pytest
import reasoner_pydantic

from node_normalizer.server import app
Expand All @@ -13,16 +14,20 @@
from reasoner_pydantic import Response

# Need to add to sources root to avoid linter warnings
from .helpers.redis_mocks import mock_get_equivalent_curies
from .helpers.redis_mocks import mock_get_ic
from ..helpers.redis_mocks import mock_get_equivalent_curies
from ..helpers.redis_mocks import mock_get_ic

premerged_response = Path(__file__).parent / "resources" / "premerged_response.json"
postmerged_response = Path(__file__).parent / "resources" / "postmerged_response.json"
# Uses an older docker-compose harness that builds the full app image; not yet
# wired up for CI (tracked in issue #383).
pytestmark = pytest.mark.skip(reason="requires docker-compose harness, see #383")

premerged_dupe_edge = Path(__file__).parent / "resources" / "premerged_dupe_edge.json"
postmerged_dupe_edge = Path(__file__).parent / "resources" / "postmerged_dupe_edge.json"
premerged_response = Path(__file__).parent.parent / "resources" / "premerged_response.json"
postmerged_response = Path(__file__).parent.parent / "resources" / "postmerged_response.json"

input_set = Path(__file__).parent / "resources" / "input_set.json"
premerged_dupe_edge = Path(__file__).parent.parent / "resources" / "premerged_dupe_edge.json"
postmerged_dupe_edge = Path(__file__).parent.parent / "resources" / "postmerged_dupe_edge.json"

input_set = Path(__file__).parent.parent / "resources" / "input_set.json"


class TestServer:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_norm.py → tests/frontend/test_norm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from node_normalizer.server import app
from fastapi.testclient import TestClient
from unittest.mock import Mock, patch
from .helpers.redis_mocks import mock_get_equivalent_curies, mock_get_ic
from ..helpers.redis_mocks import mock_get_equivalent_curies, mock_get_ic
from pathlib import Path
import os
from bmt import Toolkit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from unittest.mock import Mock, patch

# Need to add to sources root to avoid linter warnings
from .helpers.redis_mocks import mock_get_equivalent_curies, mock_get_ic
from ..helpers.redis_mocks import mock_get_equivalent_curies, mock_get_ic
from types import SimpleNamespace

from node_normalizer.normalizer import (
Expand Down Expand Up @@ -121,8 +121,8 @@ def float_or_none(x):
return None


premerged_graph = Path(__file__).parent / "resources" / "premerged_kgraph.json"
postmerged_graph = Path(__file__).parent / "resources" / "postmerged_kgraph.json"
premerged_graph = Path(__file__).parent.parent / "resources" / "premerged_kgraph.json"
postmerged_graph = Path(__file__).parent.parent / "resources" / "postmerged_kgraph.json"


class TestNormalizer:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pathlib import Path
from unittest.mock import patch

REDIS_CONF_PATH = Path(__file__).parent / 'resources' / 'redis-config.yaml'
REDIS_CONF_PATH = Path(__file__).parent.parent / 'resources' / 'redis-config.yaml'

@pytest.fixture
def config_dict():
Expand Down
File renamed without changes.
24 changes: 24 additions & 0 deletions tests/frontend/test_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Test the /status endpoint (issue #377: openapi_version + backend keys)."""
from node_normalizer.server import app
from fastapi.testclient import TestClient


class MockStatusRedis:
async def dbsize(self):
return 0

async def used_memory_rss_human(self):
return "0B"


def test_status_openapi_version_and_backend():
for db in (
"eq_id_to_id_db", "id_to_eqids_db", "id_to_type_db", "curie_to_bl_type_db",
"info_content_db", "gene_protein_db", "chemical_drug_db",
):
setattr(app.state, db, MockStatusRedis())

body = TestClient(app).get("/status").json()

assert body["backend"] == "redis"
assert body["version"] == app.openapi_schema["info"]["version"]
Loading