Skip to content

Commit

Permalink
[Auto-generated] Update dependencies (#190)
Browse files Browse the repository at this point in the history
Update dependencies in `pyproject.toml` (#189)

Update support for latest pytest-asyncio and -httpx:
- Upgrade to new loop handling in pytest-asyncio.
- Use new way of managing mocked httpx requests.
- The non-mocked-hosts fixture no longer has any effect and must
  be applied rather through markers.


Co-authored-by: Casper Welzel Andersen <[email protected]>
Co-authored-by: Casper Welzel Andersen <[email protected]>
  • Loading branch information
3 people authored Oct 2, 2024
1 parent 11777a4 commit b8a376d
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 56 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ services:
stop_grace_period: 1s

mongodb:
image: mongo:7
image: mongo:8
restart: always
ports:
- "${MONGO_PORT:-27017}:27017"
Expand Down
19 changes: 10 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ requires-python = "~=3.10"
dynamic = ["version", "description"]

dependencies = [
"fastapi ~=0.112.0",
"httpx ~=0.27.0",
"pydantic-settings ~=2.4",
"pymongo ~=4.8",
"fastapi ~=0.115.0",
"httpx ~=0.27.2",
"pydantic-settings ~=2.5",
"pymongo ~=4.10",
"python-dotenv ~=1.0",
"uvicorn >=0.24.0,<1",
]
Expand All @@ -58,17 +58,17 @@ cli = [
]
testing = [
"cryptography ~=43.0",
"dlite-python ~=0.5.16",
"mongomock ~=4.1",
"dlite-python ~=0.5.22",
"mongomock ~=4.2",
"numpy <2", # requirement for DLite v0.5.16, which does not support NumPy v2
"pytest ~=8.3",
"pytest-asyncio ~=0.23.8",
"pytest-asyncio ~=0.24.0",
"pytest-cov ~=5.0",
"pytest-httpx ~=0.30.0",
"pytest-httpx ~=0.32.0",
"entities-service[cli]",
]
server = [
"gunicorn >=21.2.0,<23",
"gunicorn >=21.2.0,<24",
]
dev = [
"pre-commit ~=3.8",
Expand Down Expand Up @@ -167,6 +167,7 @@ filterwarnings = [
"ignore:.*MemoryObjectReceiveStream.*:pytest.PytestUnraisableExceptionWarning",
]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"

[tool.coverage.run]
sigterm = true
Expand Down
32 changes: 3 additions & 29 deletions tests/cli/commands/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import TYPE_CHECKING

import pytest
import pytest_asyncio

if TYPE_CHECKING:
from pathlib import Path
Expand All @@ -13,7 +14,7 @@
from typer import Typer


@pytest.fixture(scope="session")
@pytest_asyncio.fixture(loop_scope="session", scope="session")
def config_app() -> Typer:
"""Return the config APP."""
from entities_service.cli._utils.global_settings import global_options
Expand All @@ -27,7 +28,7 @@ def config_app() -> Typer:
return APP


@pytest.fixture(scope="session")
@pytest_asyncio.fixture(loop_scope="session", scope="session")
def list_app() -> Typer:
"""Return the list APP."""
from entities_service.cli._utils.global_settings import global_options
Expand Down Expand Up @@ -77,33 +78,6 @@ def _mock_config_base_url(monkeypatch: pytest.MonkeyPatch, live_backend: bool) -
)


@pytest.fixture
def non_mocked_hosts(live_backend: bool) -> list[str]:
"""Return a list of hosts that are not mocked by 'pytest-httpx."""
if not live_backend:
return []

import os

from entities_service.service.config import CONFIG

host, port = os.getenv("ENTITIES_SERVICE_HOST", "localhost"), os.getenv(
"ENTITIES_SERVICE_PORT", "8000"
)

localhost = host + (f":{port}" if port else "")
hosts = [localhost, host]

if (
CONFIG.base_url.host
and CONFIG.base_url.host not in hosts
and CONFIG.base_url.host not in ("onto-ns.com", "www.onto-ns.com")
):
hosts.append(CONFIG.base_url.host)

return hosts


@pytest.fixture
def _mock_successful_oauth_response(
monkeypatch: pytest.MonkeyPatch, token_mock: str, httpx_mock: HTTPXMock
Expand Down
5 changes: 4 additions & 1 deletion tests/cli/commands/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@

from .conftest import ParameterizeGetEntities

pytestmark = pytest.mark.skip_if_live_backend("OAuth2 verification cannot be mocked.")
pytestmark = [
pytest.mark.skip_if_live_backend("OAuth2 verification cannot be mocked."),
pytest.mark.httpx_mock(can_send_already_matched_responses=True),
]

CLI_RESULT_FAIL_MESSAGE = "STDOUT:\n{stdout}\n\nSTDERR:\n{stderr}"

Expand Down
22 changes: 13 additions & 9 deletions tests/cli/commands/test_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

from ...conftest import ParameterizeGetEntities

pytestmark = pytest.mark.skip_if_live_backend("OAuth2 verification cannot be mocked.")
pytestmark = [
pytest.mark.skip_if_live_backend("OAuth2 verification cannot be mocked."),
pytest.mark.httpx_mock(can_send_already_matched_responses=True),
]

CLI_RESULT_FAIL_MESSAGE = "STDOUT:\n{stdout}\n\nSTDERR:\n{stderr}"

Expand Down Expand Up @@ -90,14 +93,15 @@ def test_upload_filepath(
status_code=404, # not found
)

# Mock response for "Upload entities"
httpx_mock.add_response(
url=f"{str(CONFIG.base_url).rstrip('/')}/_admin/create",
method="POST",
match_headers={"Authorization": f"Bearer {token_mock}"},
match_json=[raw_entity],
status_code=201, # created
)
if namespace != "core":
# Mock response for "Upload entities"
httpx_mock.add_response(
url=f"{str(CONFIG.base_url).rstrip('/')}/_admin/create",
method="POST",
match_headers={"Authorization": f"Bearer {token_mock}"},
match_json=[raw_entity],
status_code=201, # created
)

result = cli.invoke(main.APP, f"upload {entity_filepath}")

Expand Down
60 changes: 53 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import TYPE_CHECKING, NamedTuple

import pytest
import pytest_asyncio

if TYPE_CHECKING:
from pathlib import Path
Expand Down Expand Up @@ -123,8 +124,14 @@ def pytest_collection_modifyitems(
"""Called after collection has been performed. May filter or re-order the items
in-place."""
if config.getoption("--live-backend"):
# If the tests are run with a live backend, skip the tests marked with
# 'skip_if_live_backend'
import os

from entities_service.service.config import CONFIG

# If the tests are run with a live backend, do the following:
# - skip the tests marked with 'skip_if_live_backend'
# - add non-mocked hosts list to the httpx_mock marker
# (if the tests are from the cli.commands module)
prefix_reason = "Live backend used: {reason}"
default_reason = "Test is skipped when using a live backend"
for item in items:
Expand All @@ -147,10 +154,48 @@ def pytest_collection_modifyitems(
reason, str
), "The reason for skipping the test must be a string."

# The marker does not have a reason
# Add the skip marker to the test
item.add_marker(
pytest.mark.skip(reason=prefix_reason.format(reason=reason))
)

## HTTPX non-mocked hosts

# Check if the test is from the cli.commands module
if "cli/commands/" not in str(item.path):
continue

host, port = os.getenv("ENTITIES_SERVICE_HOST", "localhost"), os.getenv(
"ENTITIES_SERVICE_PORT", "8000"
)

localhost = f"localhost:{port}" if port else "localhost"
non_mocked_hosts = [localhost, host]

if (
CONFIG.base_url.host
and CONFIG.base_url.host not in non_mocked_hosts
and CONFIG.base_url.host not in ("onto-ns.com", "www.onto-ns.com")
):
non_mocked_hosts.append(CONFIG.base_url.host)

# Handle the case of the httpx_mock marker already being present
if "httpx_mock" in item.keywords:
marker: pytest.Mark = item.keywords["httpx_mock"]

# The marker already has non-mocked hosts - ignore
if "non_mocked_hosts" in marker.kwargs:
continue

# Add the non-mocked hosts to the marker
item.add_marker(
pytest.mark.httpx_mock(non_mocked_hosts=non_mocked_hosts)
)
else:
# Add the httpx_mock marker with the non-mocked hosts
item.add_marker(
pytest.mark.httpx_mock(non_mocked_hosts=non_mocked_hosts)
)
else:
# If the tests are run with the mock backend, skip the tests marked with
# 'skip_if_not_live_backend'
Expand Down Expand Up @@ -415,7 +460,7 @@ def get_uri(entity: dict[str, Any]) -> str:
## Pytest fixtures ##


@pytest.fixture(scope="session")
@pytest_asyncio.fixture(loop_scope="session", scope="session")
def live_backend(request: pytest.FixtureRequest) -> bool:
"""Return whether to run the tests with a live backend."""
import os
Expand Down Expand Up @@ -446,15 +491,15 @@ def live_backend(request: pytest.FixtureRequest) -> bool:
return value


@pytest.fixture(scope="session")
@pytest_asyncio.fixture(loop_scope="session", scope="session")
def static_dir() -> Path:
"""Return the path to the static directory."""
from pathlib import Path

return (Path(__file__).parent / "static").resolve()


@pytest.fixture(scope="session")
@pytest_asyncio.fixture(loop_scope="session", scope="session")
def get_backend_user() -> GetBackendUserFixture:
"""Return a function to get the backend user.
Expand Down Expand Up @@ -505,7 +550,7 @@ def _get_backend_user(
return _get_backend_user


@pytest.fixture(scope="session", autouse=True)
@pytest_asyncio.fixture(loop_scope="session", scope="session", autouse=True)
def _setup_real_mongo_users(
live_backend: bool, get_backend_user: GetBackendUserFixture
) -> None:
Expand Down Expand Up @@ -716,6 +761,7 @@ def _mock_openid_config_call(base_url: str) -> None:
httpx_mock.add_response(
url=f"{base_url}/.well-known/openid-configuration",
json=openid_config_mock(base_url=base_url),
method="GET",
)

return _mock_openid_config_call
Expand Down
1 change: 1 addition & 0 deletions tests/service/routers/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ def test_create_no_entities(
response.json()


@pytest.mark.httpx_mock(can_send_already_matched_responses=True)
def test_create_invalid_entity(
static_dir: Path,
client: ClientFixture,
Expand Down

0 comments on commit b8a376d

Please sign in to comment.