Загрузка данных
conftest.py
SMOKE_SUITE_LEVEL_MAPPING = {
'test_lds_configurator_verify': 'lds_configurator_verify_test',
LDS_STATUS_SUITE_LEVEL_MAPPING = {
'test_lds_configurator_verify': 'lds_configurator_verify_test',
# Для suite-level тестов берём из config
if 'config' in params:
if test_name == 'test_lds_configurator_verify':
suite_config = params['config']
if not suite_config.use_lds_configurator:
return None
if not suite_config.tu_name.strip():
pytest.fail(
f"Набор '{suite_config.suite_name}': tu_name обязателен к заполнению в датасете набора при use_lds_configurator=True"
)
return suite_config.lds_configurator_verify_test
if test_name in SMOKE_SUITE_LEVEL_MAPPING:
suite_config = params['config']
attr_name = SMOKE_SUITE_LEVEL_MAPPING[test_name]
return getattr(suite_config, attr_name, None)
if test_name in LDS_STATUS_SUITE_LEVEL_MAPPING:
suite_config = params['config']
attr_name = LDS_STATUS_SUITE_LEVEL_MAPPING[test_name]
return getattr(suite_config, attr_name, None)
return None
pytest.exit(f"[SETUP] [ERROR] ошибка обновления id датчиков отбраковки из конфигурации: {error}")
if suite_config is not None and suite_config.use_lds_configurator:
try:
_run_lds_admin_setup(suite_config, cfg)
except Exception as error:
pytest.exit(f"[SETUP] [ERROR] LDS Configurator admin setup: {error}")
yield # pytest продолжит выполнение теста
def _run_lds_admin_setup(suite_config, group_state: dict) -> None:
"""
WS-setup СОУ через Администрирование до старта имитатора.
"""
async def _admin_setup() -> None:
ws_host = get_ws_host()
token = get_token()
async with WebSocketClient(ws_host, token) as client:
await lds_configurator_scenarios.lds_configurator_admin_setup(
client, suite_config, group_state
)
asyncio.run(_admin_setup())
селект
lds_configurator_verify_test=CaseMarkers(test_case_id="", offset=0),
мод фо тест
resolved_tu_id: Optional[int] = None
lds_configurator_verify_test: Optional[CaseMarkers] = None
@property
def tu_id(self) -> int:
"""ID технологического участка"""
if self.use_lds_configurator:
if self.resolved_tu_id is None:
raise RuntimeError(
"resolved_tu_id не установлен - выполните lds_configurator_admin_setup перед тестами сценария"
)
return self.resolved_tu_id
# legacy: захардкоженный id из enum TU (имитатор использует тот же id для tn{id}_tags.txt)
return self.technological_unit.id
сцен ини
scenarios.export_mt_mode_report,
lds_configurator_scenarios.lds_configurator_admin_setup,
lds_configurator_scenarios.lds_configurator_verify_after_core,
lds_configurator_scenarios.lds_configurator_teardown,
лдс сцен конф
"""
Сценарии setup/teardown СОУ через раздел Администрирование (LDS Configurator).
Admin setup выполняется в pytest_runtest_setup до имитатора.
Verify after core - critical_stop автотест после запуска lds-core.
"""
from __future__ import annotations
from typing import Any, Dict, Optional
import allure
from pytest import fail
from clients.websocket_client import WebSocketClient
from constants.enums import SouAdminStatus
from constants.test_constants import LdsConfiguratorConstants as LdsCfgConst
from test_config.models_for_tests import BaseSuiteConfig
from utils.helpers import lds_configurator_utils as lds_utils
from utils.helpers import ws_test_utils as t_utils
from utils.helpers.ws_message_parser import ws_message_parser as parser
def _save_group_state(group_state: Optional[Dict[str, Any]], cfg: BaseSuiteConfig, tu_id: int) -> None:
"""
Сохраняет resolved tu_id и флаги в group_state для teardown в conftest.
"""
if group_state is None:
return
group_state["use_lds_configurator"] = cfg.use_lds_configurator
group_state["resolved_tu_id"] = tu_id
group_state["tu_name"] = cfg.tu_name
async def lds_configurator_admin_setup(
ws_client: WebSocketClient,
cfg: BaseSuiteConfig,
group_state: Optional[Dict[str, Any]] = None,
) -> None:
"""
Холодный запуск СОУ через Администрирование до старта имитатора.
Выполняется пока lds-core ещё не запущен
1. Получить tu_id по tu_name из GetBasicInfoAdmin.
2. При необходимости остановить уже запущенную СОУ.
3. LaunchLdsRequest и ожидание status=включена.
4. Подтвердить launchedAt в GetTusInformation.
"""
tu_id: int
sou_status: SouAdminStatus
with allure.step(f"[SETUP] Получение ТУ '{cfg.tu_name}' из Администрирования"):
admin_reply = await lds_utils.get_basic_info_admin_with_retry(ws_client, parser)
admin_tu = lds_utils.find_tu_by_name(admin_reply, cfg.tu_name)
lds_utils.validate_admin_tu(admin_tu)
sou_status = SouAdminStatus(admin_tu.status)
tu_id = admin_tu.tuId
cfg.resolved_tu_id = tu_id
_save_group_state(group_state, cfg, tu_id)
allure.attach(
f"tuId={tu_id}\n"
f"tuName={admin_tu.tuName!r}\n"
f"status={sou_status} ({SouAdminStatus.report_text_by_value(admin_tu.status)})",
name="Найденный ТУ",
attachment_type=allure.attachment_type.TEXT,
)
launch_checkpoint = t_utils.moscow_now()
allure.attach(
t_utils.format_datetime_moscow(launch_checkpoint),
name="Момент фиксации времени перед холодным запуском",
attachment_type=allure.attachment_type.TEXT,
)
if sou_status == SouAdminStatus.RUNNING:
with allure.step("[SETUP] Остановка СОУ перед холодным запуском (уже была включена)"):
await lds_utils.invoke_lds_command(ws_client, parser, LdsCfgConst.STOP_LDS_REQUEST, tu_id)
with allure.step("Проверка: СОУ выключена в Администрировании"):
if not await lds_utils.poll_admin_tu_status(ws_client, parser, tu_id, SouAdminStatus.STOPPED):
fail(
"Не удалось перезапустить СОУ: статус в Администрировании не стал 'выключена' за 2 минуты",
pytrace=False,
)
with allure.step("[SETUP] Холодный запуск СОУ (LaunchLdsRequest)"):
await lds_utils.invoke_lds_command(ws_client, parser, LdsCfgConst.LAUNCH_LDS_REQUEST, tu_id)
with allure.step("[SETUP] Ожидание включения СОУ в Администрировании"):
with allure.step("Проверка: статус стал 'включена'"):
if not await lds_utils.poll_admin_tu_status(ws_client, parser, tu_id, SouAdminStatus.RUNNING):
fail(
"Не удалось запустить СОУ: статус в Администрировании не стал 'включена' за 2 минуты",
pytrace=False,
)
with allure.step("[SETUP] Подтверждение времени запуска (GetTusInformation)"):
await lds_utils.verify_launched_at(ws_client, parser, tu_id, launch_checkpoint)
async def lds_configurator_verify_after_core(
ws_client: WebSocketClient,
cfg: BaseSuiteConfig,
) -> None:
"""
Critical-stop: проверка готовности стенда после запуска lds-core.
1. Актуальный статус СОУ из Администрирования.
2. Сверка с Состоянием МТ (MainPageInfoContent).
3. Ожидание появления ТУ в Состоянии МТ при status=включена.
"""
tu_id = cfg.tu_id
with allure.step(f"Получение актуального статуса СОУ для tuId={tu_id}"):
admin_reply = await lds_utils.get_basic_info_admin_with_retry(ws_client, parser)
sou_status = lds_utils.get_admin_tu_status(admin_reply, tu_id)
with allure.step("Проверка: ТУ найден в Администрировании"):
if sou_status is None:
fail(
f"ТУ tuId={tu_id} ('{cfg.tu_name}') не найден в GetBasicInfoAdminResponse",
pytrace=False,
)
with allure.step("Сверка статуса СОУ: Администрирование vs Состояние МТ"):
is_on_main_page = await lds_utils.is_tu_present_on_main_page(ws_client, parser, tu_id)
lds_utils.check_sou_status_sync(sou_status, is_on_main_page, tu_id, cfg.tu_name)
if sou_status == SouAdminStatus.RUNNING:
with allure.step("Ожидание появления ТУ в Состоянии МТ"):
with allure.step("Проверка: ТУ отображается в Состоянии МТ"):
if not await lds_utils.poll_main_page_tu_presence(ws_client, tu_id, expect_present=True):
fail(
"СОУ не отображается в Состоянии МТ: ТУ не появилась за 2 минуты после запуска core",
pytrace=False,
)
async def lds_configurator_teardown(
ws_client: WebSocketClient,
tu_id: int,
tu_name: str,
) -> None:
"""
Teardown набора: остановка СОУ после прогона.
Некритичные отклонения оформляются как Allure ALERT без падения прогона.
Ошибки ws при StopLds логируются и не прерывают pytest session.
"""
with allure.step(f"Teardown. Проверка статуса СОУ (tuId={tu_id}, «{tu_name}»)"):
try:
admin_reply = await lds_utils.get_basic_info_admin(ws_client, parser)
except Exception as error:
lds_utils.attach_allure_alert(
f"Не удалось получить статус СОУ при teardown: {error}. "
f"tuId={tu_id}, tuName={tu_name!r}"
)
return
sou_status = lds_utils.get_admin_tu_status(admin_reply, tu_id)
if sou_status != SouAdminStatus.RUNNING:
lds_utils.attach_allure_alert(
f"СОУ не в статусе 'включена' при teardown (status={sou_status}), остановка пропущена. "
f"tuId={tu_id}, tuName='{tu_name}'"
)
return
with allure.step("Teardown. Остановка СОУ (StopLdsRequest)"):
try:
await lds_utils.invoke_lds_command(ws_client, parser, LdsCfgConst.STOP_LDS_REQUEST, tu_id)
except Exception as error:
lds_utils.attach_allure_alert(
f"Ошибка при StopLdsRequest: {error}. tuId={tu_id}, tuName={tu_name!r}"
)
return
with allure.step("Teardown. Ожидание выключения СОУ в Администрировании"):
if not await lds_utils.poll_admin_tu_status(ws_client, parser, tu_id, SouAdminStatus.STOPPED):
lds_utils.attach_allure_alert(
f"СОУ не выключилась за 2 минуты после StopLdsRequest. "
f"tuId={tu_id}, tuName={tu_name!r}. Проверить вручную."
)
тест лдс статус регрес
@pytest.mark.asyncio
@pytest.mark.critical_stop
async def test_lds_configurator_verify(
self, ws_client: WebSocketClient, config: LDSStatusConfig
) -> None:
tag = "LdsConfigurator"
title = f"[{tag}] Проверка наличия запускаемого ТУ на ЭФ Состояние МТ сразу после запуска core"
_apply_allure_markers(config.lds_configurator_verify_test, tag, title)
await lds_configurator_scenarios.lds_configurator_verify_after_core(ws_client, config)
тест смок
@pytest.mark.asyncio
@pytest.mark.critical_stop
async def test_lds_configurator_verify(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig
) -> None:
tag = "LdsConfigurator"
title = f"[{tag}] Проверка наличия запускаемого ТУ на ЭФ Состояние МТ сразу после запуска core"
_apply_allure_markers(config.lds_configurator_verify_test, tag, title)
await lds_configurator_scenarios.lds_configurator_verify_after_core(ws_client, config)