All checks were successful
Mostovik Backend CI/CD / Tests and lint (push) Successful in 9m37s
Mostovik Backend CI/CD / Build linux/amd64 release images (push) Successful in 4m18s
Mostovik Backend CI/CD / Deploy and verify internal main (push) Has been skipped
Mostovik Backend CI/CD / Deploy customer main (push) Has been skipped
Mostovik Backend CI/CD / Deploy dev (push) Successful in 1m48s
98 lines
4.0 KiB
Python
98 lines
4.0 KiB
Python
"""Оба публичных входа запускают один импорт и исключают конкурирующий запуск."""
|
||
|
||
from importlib import import_module
|
||
from unittest.mock import patch
|
||
|
||
import pytest
|
||
from apps.core.models import BackgroundJob
|
||
from core.celery import app as celery_app
|
||
from django.urls import reverse
|
||
from rest_framework.test import APIClient
|
||
|
||
from tests.apps.user.factories import UserFactory
|
||
|
||
SOURCES = [
|
||
("budget-process-registry", "budget_ubpandnubp", "parse_budget_registry"),
|
||
(
|
||
"sme-support-recipients-registry",
|
||
"fns_sme_support_recipients",
|
||
"parse_sme_support_recipients",
|
||
),
|
||
]
|
||
|
||
|
||
@pytest.mark.django_db
|
||
def test_openapi_exposes_refresh_conflict_and_pollable_task():
|
||
client = APIClient()
|
||
client.force_authenticate(UserFactory.create_user(is_staff=True))
|
||
response = client.get(reverse("schema-swagger-ui"), {"format": "openapi"})
|
||
assert response.status_code == 200
|
||
schema = response.data
|
||
path = next(path for path in schema["paths"] if "/parsers/run/" in path)
|
||
responses = schema["paths"][path]["post"]["responses"]
|
||
assert "409" in responses
|
||
assert responses["202"]["schema"]["$ref"].endswith("/ParserRunEnvelope")
|
||
assert "task_id" in schema["definitions"]["ParserRunResponse"]["properties"]
|
||
card_path = next(
|
||
path for path in schema["paths"] if "/sources/{slug}/refresh/" in path
|
||
)
|
||
assert "409" in schema["paths"][card_path]["post"]["responses"]
|
||
|
||
|
||
@pytest.mark.django_db
|
||
@pytest.mark.parametrize("slug,source,task", SOURCES)
|
||
@pytest.mark.parametrize("first", ["card", "parser"])
|
||
def test_refresh_is_pollable_and_other_entrypoint_conflicts(slug, source, task, first):
|
||
client = APIClient()
|
||
client.force_authenticate(UserFactory.create_user(is_staff=True))
|
||
urls = {
|
||
"card": f"/api/v1/sources/{slug}/refresh/",
|
||
"parser": f"/api/v1/parsers/run/{source}/",
|
||
}
|
||
second = "parser" if first == "card" else "card"
|
||
import_module("apps.parsers.tasks")
|
||
registered_task = celery_app.tasks[f"parsers.{source}.refresh"]
|
||
with patch.object(registered_task, "apply_async") as dispatch:
|
||
response = client.post(urls[first], {"params": {}}, format="json")
|
||
assert response.status_code == 202, response.data
|
||
payload = response.data.get("data", response.data)
|
||
job = BackgroundJob.objects.get(task_id=payload["task_id"])
|
||
assert payload["status"] == "queued"
|
||
assert dispatch.call_args.kwargs["task_id"] == job.task_id
|
||
assert dispatch.call_args.kwargs["kwargs"] == {"requested_by_id": job.user_id}
|
||
assert job.meta["refresh_task_ids"] == [job.task_id]
|
||
assert client.get(f"/api/v1/jobs/{job.task_id}/").status_code == 200
|
||
duplicate = client.post(urls[second], {}, format="json")
|
||
assert duplicate.status_code == 409, duplicate.data
|
||
assert BackgroundJob.objects.count() == 1
|
||
assert dispatch.call_count == 1
|
||
job.complete()
|
||
next_run = client.post(urls[second], {}, format="json")
|
||
assert next_run.status_code == 202
|
||
assert BackgroundJob.objects.count() == 2
|
||
|
||
|
||
@pytest.mark.django_db
|
||
@pytest.mark.parametrize("slug,source,task", SOURCES)
|
||
def test_refresh_requires_administrator_and_rejects_loader_parameters(
|
||
slug, source, task
|
||
):
|
||
client = APIClient()
|
||
client.force_authenticate(UserFactory.create_user())
|
||
import_module("apps.parsers.tasks")
|
||
registered_task = celery_app.tasks[f"parsers.{source}.refresh"]
|
||
with patch.object(registered_task, "apply_async") as dispatch:
|
||
for url in [
|
||
f"/api/v1/sources/{slug}/refresh/",
|
||
f"/api/v1/parsers/run/{source}/",
|
||
]:
|
||
assert client.post(url, {}, format="json").status_code == 403
|
||
client.force_authenticate(UserFactory.create_user(is_staff=True))
|
||
response = client.post(
|
||
f"/api/v1/sources/{slug}/refresh/",
|
||
{"params": {"url": "https://example.invalid"}},
|
||
format="json",
|
||
)
|
||
assert response.status_code == 400
|
||
dispatch.assert_not_called()
|