90 lines
3.5 KiB
Python
90 lines
3.5 KiB
Python
|
|
"""Сценарии с эталонным отказом ДДС (lct-52).
|
|||
|
|
|
|||
|
|
Мотивированный отказ по эталону не даёт отметок; «Принята» вопреки эталону —
|
|||
|
|
D2 с причиной из сценария в норме. Причины — из памятки АРМ-112: не наша
|
|||
|
|
зона, не наша компетенция, дубль.
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from pathlib import Path
|
|||
|
|
from uuid import uuid4
|
|||
|
|
|
|||
|
|
import pytest
|
|||
|
|
|
|||
|
|
from app.domain.events import Exercise, SessionMode
|
|||
|
|
from app.scenarios.loader import load_file
|
|||
|
|
from app.session import finish as finish_module
|
|||
|
|
from app.session.dds import prepare_queue
|
|||
|
|
from app.session.hub import hub
|
|||
|
|
from app.session.state import SessionState
|
|||
|
|
from app.session.store import MemorySessionStore
|
|||
|
|
|
|||
|
|
from tests.test_dds_desk_scores import station
|
|||
|
|
|
|||
|
|
LIBRARY = Path(__file__).resolve().parents[2] / "scenarios"
|
|||
|
|
DECLINES = ["dds-decline-duplicate.yaml", "dds-decline-out-of-zone.yaml"]
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.fixture(autouse=True)
|
|||
|
|
def offline_finish(monkeypatch):
|
|||
|
|
class NoCoaching:
|
|||
|
|
def model_dump(self, **_kwargs):
|
|||
|
|
return {}
|
|||
|
|
|
|||
|
|
async def no_coach(_metrics):
|
|||
|
|
return NoCoaching()
|
|||
|
|
|
|||
|
|
monkeypatch.setattr(finish_module, "coach", no_coach)
|
|||
|
|
monkeypatch.setattr(hub, "store", MemorySessionStore())
|
|||
|
|
|
|||
|
|
|
|||
|
|
def lesson(name: str) -> SessionState:
|
|||
|
|
scenario = load_file(LIBRARY / name, LIBRARY)
|
|||
|
|
state = SessionState(
|
|||
|
|
session_id=uuid4(), scenario_id=scenario.id, scenario_title=scenario.title,
|
|||
|
|
level=scenario.level.value, mode=SessionMode.TRAINING, exercise=Exercise.DDS,
|
|||
|
|
)
|
|||
|
|
prepare_queue(state, [scenario])
|
|||
|
|
station(state, type="card.open", card_id=str(state.station_snapshot().card_id))
|
|||
|
|
return state
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.parametrize("name", DECLINES)
|
|||
|
|
def test_library_scenario_expects_a_reasoned_decline(name):
|
|||
|
|
scenario = load_file(LIBRARY / name, LIBRARY)
|
|||
|
|
|
|||
|
|
assert scenario.dds_decision.expected == "decline"
|
|||
|
|
assert scenario.dds_decision.reason.split(":")[0] in {"дубль", "не наша зона"}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.parametrize("name", DECLINES)
|
|||
|
|
def test_reasoned_decline_by_the_reference_leaves_a_clean_report(name):
|
|||
|
|
state = lesson(name)
|
|||
|
|
service = state.station_snapshot().managed_service
|
|||
|
|
reason = load_file(LIBRARY / name, LIBRARY).dds_decision.reason
|
|||
|
|
|
|||
|
|
station(state, type="card.status", service=service, status="declined",
|
|||
|
|
comment=f"Основание: {reason}.\nСведения: причина отказа передана дежурному 112.")
|
|||
|
|
station(state, type="station.finish")
|
|||
|
|
|
|||
|
|
score = state.score
|
|||
|
|
assert score["findings"] == []
|
|||
|
|
decision = next(item for item in score["metrics"] if item["key"] == "dds_decision")
|
|||
|
|
assert decision["passed"] and decision["norm"] == reason
|
|||
|
|
assert score["score_auto"] == 100.0
|
|||
|
|
|
|||
|
|
|
|||
|
|
@pytest.mark.parametrize("name", DECLINES)
|
|||
|
|
def test_accepting_against_the_reference_is_d2_with_the_scenario_reason(name):
|
|||
|
|
state = lesson(name)
|
|||
|
|
reason = load_file(LIBRARY / name, LIBRARY).dds_decision.reason
|
|||
|
|
|
|||
|
|
station(state, type="card.ack",
|
|||
|
|
comment="Основание: карточка поступила.\nСведения: принята, доклад дежурному.")
|
|||
|
|
station(state, type="station.finish")
|
|||
|
|
|
|||
|
|
score = state.score
|
|||
|
|
d2 = [item for item in score["findings"]
|
|||
|
|
if item["code"] == "D2" and "вопреки эталону" in item["summary"]]
|
|||
|
|
assert len(d2) == 1 and d2[0]["norm"] == reason
|
|||
|
|
decision = next(item for item in score["metrics"] if item["key"] == "dds_decision")
|
|||
|
|
assert not decision["passed"]
|