Skip to content

Tests(py): add runtime profiles and endpoint-aware fixtures#10500

Draft
nmanovic wants to merge 4 commits intov3-pr4b-fast-restorefrom
v3-pr4c-profiles-runtime-urls
Draft

Tests(py): add runtime profiles and endpoint-aware fixtures#10500
nmanovic wants to merge 4 commits intov3-pr4b-fast-restorefrom
v3-pr4c-profiles-runtime-urls

Conversation

@nmanovic
Copy link
Copy Markdown
Contributor

Summary

This is the next stacked PR after v3-pr4b-fast-restore.

It introduces explicit local runtime profiles and runtime-aware endpoint handling for Python tests.

Scope:

  • add simple, standard, and full local runtime profiles
  • select the required local profile from explicit @pytest.mark.infra_profile(...) markers in test files
  • fail early when an explicit --infra-profile is too small
  • make fixture-backed webhook / cloud-storage / SDK / CLI URLs adapt to the active runtime
  • keep repo-tracked fixture JSON stable by normalizing URLs in memory at load time

Out of scope:

  • dynamic local ports
  • parallel runtime
  • kube runtime replacement
  • profiler
  • CI workflow changes

Why

After the runtime foundation and fast restore PRs, the remaining local-runtime gap was test selection and endpoint assumptions.

Some Python tests need a heavier local stack than others:

  • MinIO-backed cloud storage
  • webhook receiver / test servers
  • full analytics-related services

At the same time, some fixture-backed payloads still assumed fixed legacy internal URLs.

This PR makes those requirements explicit and keeps the runtime/test data aligned without introducing dynamic ports yet.

What changed

Local runtime profiles

Added 3 local profiles:

  • simple
  • standard
  • full

Selection rules:

  • unmarked tests implicitly require simple
  • tests that need more services use explicit @pytest.mark.infra_profile("standard") or @pytest.mark.infra_profile("full")
  • if --infra-profile is not explicitly provided, the local runtime selects the smallest sufficient profile for the collected test set
  • if --infra-profile is explicitly too small, pytest fails before starting the stack

Compose layering

Added only valid local profile overlays:

  • tests/docker-compose.simple.profile.yml
  • tests/docker-compose.standard.profile.yml

Important:

  • this PR does not reintroduce the outdated:
    • tests/docker-compose.core.profile.yml
    • tests/docker-compose.extended.profile.yml

The full profile is assembled from valid existing compose inputs only.

Runtime-aware endpoints

Added shared helper support so runtime-facing URLs adapt without changing committed fixture assets:

  • CVAT_BASE_URL for SDK / CLI / shared helpers
  • runtime-aware webhook target handling
  • runtime-aware cloud-storage endpoint handling
  • in-memory normalization of fixture JSON at load time

This keeps repo-tracked fixtures stable while still matching the active runtime.

Test classification cleanup

  • migrated Python test requirements to explicit infra_profile(...) markers
  • removed the legacy with_external_services marker usage from tests/python
  • removed the now-dead marker registration

Validation

Static checks:

  • py_compile
  • black --check
  • isort --check --diff --resolve-all-configs
  • pylint
  • typos
  • remark

Profile selection checks:

  • simple local smoke: passed
  • standard local smoke: passed
  • full local smoke: passed
  • explicit too-small profile fails early as intended

Targeted profile-sensitive suites:

  • tests/python/rest_api/test_cloud_storages.py
    • 52 passed
  • tests/python/rest_api/test_webhooks.py
    • 94 passed, 1 skipped

Full local Python suite:

  • pytest tests/python --platform=local
  • result: 2178 passed, 20 skipped, 1 xfailed

CI-like Django unit tests:

  • docker compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.ci.yml run --rm cvat_ci python manage.py test cvat/apps -v 2
  • result: 412 tests, OK (skipped=58)

Review notes

  • This PR keeps profile requirements in test files only.
  • Infra code reads infra_profile(...) markers but does not create a second synthetic marker system.
  • Dynamic local ports are intentionally deferred to the next PR.
  • Kube remains on the legacy path until the dedicated kube PR.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 993bf99607

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +958 to +961
invocation_args = tuple(str(arg) for arg in config.invocation_params.args)
explicit_profile_requested = any(
arg == "--infra-profile" or arg.startswith("--infra-profile=")
for arg in invocation_args
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat addopts infra profile as explicit

explicit_profile_requested is derived only from config.invocation_params.args, but pytest does not include options injected via addopts/PYTEST_ADDOPTS there. As a result, a user-provided --infra-profile from those standard config paths is treated as implicit and can be silently replaced by required_profile, so an intentionally fixed (or intentionally too-small) profile no longer enforces the expected fail-fast behavior and can start a different stack than requested.

Useful? React with 👍 / 👎.

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd233ad3c6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/python/conftest.py
Comment on lines +157 to +158
elif platform == "local":
return
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Start cleanup/dumpdb commands before collection

The unconditional local-mode early return means instance.start() is deferred until pytest_runtestloop, so --cleanup / --dumpdb no longer execute during session startup and now depend on successful test collection. If collection/import fails first, these maintenance commands never run, leaving generated compose artifacts or DB dumps unchanged even though the user explicitly requested them.

Useful? React with 👍 / 👎.

Comment on lines +950 to +954
marker = item.get_closest_marker("infra_profile")
if marker and marker.args:
item_profile = str(RuntimeInfraConfig.parse_infra_profile(marker.args[0]))
else:
item_profile = str(InfraProfile.SIMPLE)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Honor keyword form of infra_profile markers

Profile detection only reads marker.args, so tests marked as @pytest.mark.infra_profile(name="full") are treated as unmarked (simple) because marker.args is empty. Since pytest.ini documents the marker as infra_profile(name), this silently underestimates required services and can start an undersized runtime for affected tests.

Useful? React with 👍 / 👎.

@nmanovic nmanovic force-pushed the v3-pr4b-fast-restore branch from b8f310d to fec0185 Compare April 21, 2026 07:17
@nmanovic nmanovic requested a review from SpecLad as a code owner April 21, 2026 07:17
@nmanovic nmanovic force-pushed the v3-pr4c-profiles-runtime-urls branch from dd233ad to 3f3c5a8 Compare April 21, 2026 07:17
@nmanovic nmanovic force-pushed the v3-pr4b-fast-restore branch from fec0185 to 6719c1e Compare April 21, 2026 12:47
@nmanovic nmanovic force-pushed the v3-pr4c-profiles-runtime-urls branch from 3f3c5a8 to b1c63cd Compare April 21, 2026 12:47
@nmanovic nmanovic marked this pull request as draft April 21, 2026 12:48
@nmanovic nmanovic force-pushed the v3-pr4c-profiles-runtime-urls branch from b1c63cd to 987e99a Compare April 21, 2026 12:51
@nmanovic nmanovic force-pushed the v3-pr4b-fast-restore branch from 6719c1e to 943f5b3 Compare April 21, 2026 12:51
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b1c63cdb10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +948 to +952
required_profile = str(InfraProfile.SIMPLE)
for item in items:
marker = item.get_closest_marker("infra_profile")
if marker and marker.args:
item_profile = str(RuntimeInfraConfig.parse_infra_profile(marker.args[0]))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive infra profile after test deselection

collection_modifyitems computes required_profile from every collected item, but this hook runs before pytest's built-in -k/-m deselection handlers, so filtered-out high-profile tests still influence the result. In practice, selecting a small subset can still force standard/full startup or trigger a false --infra-profile ... is too small error even though the deselected tests would not run. Move this logic to run after deselection (for example via trylast) or recompute from the final selected item set.

Useful? React with 👍 / 👎.

Comment on lines +123 to +126
if runtime.port:
netloc = f"{netloc}:{runtime.port}"
elif current.port:
netloc = f"{netloc}:{current.port}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve fixture-specific MinIO ports during URL normalization

The normalization logic always replaces the endpoint port with runtime.port when CVAT_TEST_DB_MINIO_ENDPOINT_URL is set, which collapses intentionally distinct fixture ports (including broken endpoints used for negative scenarios) into the runtime default. That can turn fixtures like the minio:9777 case into a valid endpoint and invalidate status/error expectations when endpoint remapping is enabled. The rewrite should avoid overriding an explicit fixture port indiscriminately.

Useful? React with 👍 / 👎.

@nmanovic nmanovic force-pushed the v3-pr4b-fast-restore branch from 943f5b3 to 86c7dba Compare April 21, 2026 15:30
@nmanovic nmanovic force-pushed the v3-pr4c-profiles-runtime-urls branch from 987e99a to 6e83eae Compare April 21, 2026 15:30
@nmanovic nmanovic force-pushed the v3-pr4b-fast-restore branch from 86c7dba to 753f499 Compare April 21, 2026 16:06
@nmanovic nmanovic force-pushed the v3-pr4c-profiles-runtime-urls branch from 6e83eae to 6cfb20b Compare April 21, 2026 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant