Complete incident selection and 112 to DDS workflow
This commit is contained in:
parent
0526b11f91
commit
68dd83c7c2
21 changed files with 281 additions and 56 deletions
|
|
@ -36,12 +36,13 @@ def read_until(socket, wanted):
|
|||
raise AssertionError(f"событие {wanted} не пришло")
|
||||
|
||||
|
||||
def start(client):
|
||||
def start(client, *, handoff_to_dds=False):
|
||||
session_id = uuid4()
|
||||
context = client.websocket_connect(f"/ws/control/{session_id}")
|
||||
control = context.__enter__()
|
||||
control.send_json({"type": "scenario.start", "scenario_id": "fire-apartment-l2",
|
||||
"trainee": "Иванов", "mode": "training", "exercise": "card"})
|
||||
"trainee": "Иванов", "mode": "training", "exercise": "card",
|
||||
"handoff_to_dds": handoff_to_dds})
|
||||
wait_for(lambda: hub.get(session_id))
|
||||
return session_id, context
|
||||
|
||||
|
|
@ -123,3 +124,53 @@ def test_incomplete_card_has_only_card_findings(client):
|
|||
assert report["reference_questions"] == []
|
||||
finally:
|
||||
control.__exit__(None, None, None)
|
||||
|
||||
|
||||
def test_filled_112_card_continues_as_dds_in_the_same_lesson(client):
|
||||
session_id, control = start(client, handoff_to_dds=True)
|
||||
try:
|
||||
with client.websocket_connect(f"/ws/call/{session_id}") as trainee:
|
||||
briefing = read_until(trainee, "card.briefing")
|
||||
assert briefing["handoff_to_dds"] is True
|
||||
trainee.send_json({"type": "kio.patch", "fields": {
|
||||
"address": "улица Ленина, 14", "incident_type": "fire",
|
||||
"victims_count": 2, "description": "горит балкон",
|
||||
"signs": ["жилой дом", "балкон", "открытое пламя"],
|
||||
}})
|
||||
wait_for(lambda: hub.get(session_id).kio.incident_code)
|
||||
trainee.send_json({"type": "card.submit"})
|
||||
assert read_until(trainee, "call.ended")["reason"] == "complete"
|
||||
state = hub.get(session_id)
|
||||
assert state.dispatched_card is not None and not state.ended
|
||||
assert state.score is None
|
||||
trainee.send_json({"type": "kio.patch", "fields": {"address": "поздняя правка"}})
|
||||
assert "передана" in read_until(trainee, "error")["message"]
|
||||
|
||||
with client.websocket_connect(f"/ws/call/{session_id}") as late:
|
||||
assert read_until(late, "card.briefing")["card"]["address"] == "улица Ленина, 14"
|
||||
assert read_until(late, "call.ended")["reason"] == "complete"
|
||||
|
||||
with client.websocket_connect(f"/ws/station/{session_id}") as station:
|
||||
assert read_until(station, "card.received")["card"]["address"] == "улица Ленина, 14"
|
||||
snapshot = read_until(station, "station.state")["snapshot"]
|
||||
service = snapshot["services"][0]
|
||||
crew = next(item for item in snapshot["crew_options"] if item.startswith(service + " — "))
|
||||
station.send_json({"type": "card.status", "service": service, "status": "accepted"})
|
||||
read_until(station, "station.state")
|
||||
station.send_json({"type": "crew.select", "crew": crew})
|
||||
read_until(station, "station.state")
|
||||
station.send_json({"type": "phone.dial"})
|
||||
assert read_until(station, "phone.report")["phase"] == "dispatched"
|
||||
read_until(station, "station.state")
|
||||
station.send_json({"type": "card.status", "service": service, "status": "responding"})
|
||||
read_until(station, "station.state")
|
||||
station.send_json({"type": "station.finish"})
|
||||
read_until(station, "score.ready")
|
||||
|
||||
score = wait_for(lambda: hub.get(session_id).score)
|
||||
assert hub.get(session_id).ended
|
||||
keys = {item["key"] for item in score["metrics"]}
|
||||
assert {"address", "incident_signs", "dds_primary", "dds_contact"} <= keys
|
||||
assert score["score_auto"] < 100
|
||||
finally:
|
||||
control.__exit__(None, None, None)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@
|
|||
"""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
from app.domain import ekp
|
||||
from app.domain.kio import KIO, derive_incident
|
||||
from app.scenarios.loader import load_library
|
||||
|
||||
|
||||
def test_reference_loads_whole_book():
|
||||
|
|
@ -20,6 +22,20 @@ def test_reference_loads_whole_book():
|
|||
assert all(incident.type for incident in reference.incidents), "код без итогового типа"
|
||||
|
||||
|
||||
def test_all_customer_ticket_cards_are_complete_and_classified():
|
||||
cards = [scenario for scenario in load_library(Path(__file__).resolve().parents[2] / "scenarios")
|
||||
if scenario.ticket is not None]
|
||||
assert len(cards) == 96
|
||||
assert {scenario.ticket for scenario in cards} == set(range(1, 33))
|
||||
for ticket in range(1, 33):
|
||||
assert {scenario.position for scenario in cards if scenario.ticket == ticket} == {1, 2, 3}
|
||||
assert all(scenario.facts and scenario.signs and scenario.ground_truth.address
|
||||
and scenario.ground_truth.victims is not None
|
||||
and scenario.ground_truth.incident_code
|
||||
and ekp.incident(scenario.ground_truth.incident_code)
|
||||
for scenario in cards)
|
||||
|
||||
|
||||
def test_signs_give_the_code_from_the_book():
|
||||
found = ekp.by_signs(["жилой дом", "подъезд", "открытое пламя"])
|
||||
assert found is not None
|
||||
|
|
@ -40,6 +56,20 @@ def test_next_level_narrows_by_previous():
|
|||
assert "мусор" not in second, "«мусор» относится к улице, а не к жилому дому"
|
||||
|
||||
|
||||
def test_category_filters_all_three_incident_choices_and_card_derivation():
|
||||
fire = ekp.by_signs(["жилой дом", "балкон", "открытое пламя"])
|
||||
assert fire is not None
|
||||
other_group = next(group.id for group in ekp.groups() if group.id != fire.group)
|
||||
assert ekp.by_signs(fire.signs, fire.group) == fire
|
||||
assert ekp.by_signs(fire.signs, other_group) is None
|
||||
assert fire.signs[0] in ekp.signs_at_level(1, group=fire.group)
|
||||
assert fire.signs[1] in ekp.signs_at_level(2, fire.signs[:1], group=fire.group)
|
||||
assert fire.signs[2] in ekp.signs_at_level(3, fire.signs[:2], group=fire.group)
|
||||
card = derive_incident(KIO(incident_group=fire.group, signs=fire.signs))
|
||||
assert card.incident_code == fire.code
|
||||
assert derive_incident(KIO(incident_group=other_group, signs=fire.signs)).incident_code is None
|
||||
|
||||
|
||||
def test_service_rows_hidden_from_operator_are_not_offered():
|
||||
"""Часть строк книги существует ради интеграции и оператору не показывается."""
|
||||
assert all(ekp.HIDDEN_SIGN not in sign.lower() for sign in ekp.signs_at_level(1))
|
||||
|
|
|
|||
Loading…
Reference in a new issue