Загрузка данных
сцен
"""
Сценарии тестов по режимам МТ - функции-обёртки без pytest маркеров.
Каждая функция содержит логику одного теста.
Pytest маркеры и allure декораторы применяются в тестовых файлах.
"""
from datetime import datetime
from typing import Any
import allure
import pytest
from constants.architecture_constants import HTTPClientConstants as HttpConst
from constants.enums import Direction, MessageType, StationaryStatus
from constants.test_constants import BaseTN3Constants as TestConst
from models.get_messages_model import Filtering, FilteringObjects, Pagination
from test_config.models_for_tests import BaseSuiteConfig, CaseData
from utils.helpers import ws_test_utils as t_utils
from utils.helpers.asserts import SoftAssertions, StepCheck
from utils.helpers.ws_message_parser import ws_message_parser as parser
def _unpack_stationary_status_test_data(
test_data: CaseData, require_control_points: bool = False
) -> tuple[Any, Any, list[str]]:
"""
Проверяет и распаковывает конфигурацию теста режима МТ.
"""
if not test_data or not test_data.expected_result:
pytest.fail("Не заполнены данные для теста режима МТ")
try:
expected_stationary_status, expected_stationary_status_reasons = test_data.expected_result
except (TypeError, ValueError) as error:
pytest.fail(
"Данные режима МТ должны содержать пару: "
f"(ожидаемый режим, ожидаемая причина). Получено: {test_data.expected_result}. Ошибка: {error}"
)
control_points = (test_data.params or {}).get(TestConst.CONTROL_POINTS_KEY, [])
if require_control_points and not control_points:
pytest.fail(f"Не заполнены обязательные параметры для теста: {TestConst.CONTROL_POINTS_KEY}")
return expected_stationary_status, expected_stationary_status_reasons, control_points
async def stationary_status_common_scheme(ws_client, cfg: BaseSuiteConfig, test_data: CaseData):
"""
Проверка режима работы и причины режима МТ в сообщении CommonSchemeContent
"""
# Распаковка данных для теста
expected_stationary_status, expected_stationary_status_reasons, _ = _unpack_stationary_status_test_data(test_data)
with allure.step("Подключение по ws, получение и обработка сообщения типа: CommonSchemeContent"):
payload = await t_utils.connect_and_poll_subscribed_msg(
ws_client,
"CommonSchemeContent",
"SubscribeCommonSchemeRequest",
{'tuId': cfg.tu_id, 'additionalProperties': None},
)
parsed_payload = parser.parse_common_scheme_info_msg(payload)
with allure.step("Извлечение и подготовка данных для проверки"):
flow_areas = t_utils.filter_flow_areas_with_available_flow(
getattr(parsed_payload.replyContent, 'flowAreas', [])
)
StepCheck(
"Проверка наличия участков карты течения с доступным течением CommonSchemeContent (ЭФ Схема)", "flowAreas"
).actual(flow_areas).is_not_empty()
longest_flow_area = t_utils.get_longest_flow_area_by_pipes(flow_areas)
StepCheck(
"Проверка наличия самого длинного пути течения CommonSchemeContent (ЭФ Схема)", "longest_flow_area"
).actual(longest_flow_area is not None).is_true_with_details(
expected_text="longest_flow_area определён",
actual_text=(
"longest_flow_area определён" if longest_flow_area is not None else "longest_flow_area не определён"
),
)
if longest_flow_area is not None:
allure.attach(
str(longest_flow_area),
name="CommonSchemeContent: самый длинный путь течения (ЭФ Схема)",
attachment_type=allure.attachment_type.TEXT,
)
diagnostic_areas = getattr(longest_flow_area, 'diagnosticAreas', [])
StepCheck(
"Проверка наличия данных диагностических участков CommonSchemeContent (ЭФ Схема)", "diagnosticAreas"
).actual(diagnostic_areas).is_not_empty()
common_scheme_stationary_statuses = []
for diagnostic_area in diagnostic_areas:
stationary_status_int = getattr(diagnostic_area, 'stationaryStatus', None)
if stationary_status_int is None:
continue
stationary_status = StationaryStatus(stationary_status_int)
common_scheme_stationary_statuses.append(stationary_status)
StepCheck(
"Проверка наличия режимов МТ на ДУ в CommonSchemeContent (ЭФ Схема)",
"stationaryStatus",
).actual(common_scheme_stationary_statuses).is_not_empty()
common_scheme_majority = t_utils.determine_stationary_status_by_majority(common_scheme_stationary_statuses)
StepCheck(
"CommonSchemeContent: общий режим МТ по большинству ДУ (ЭФ Схема)",
"stationaryStatus",
).actual(
common_scheme_majority
).expected(expected_stationary_status).equal_to()
majority_status_areas = []
# Получает все ДУ с ожидаемым режимом МТ
for diagnostic_area in diagnostic_areas:
if diagnostic_area.stationaryStatus == expected_stationary_status.value:
majority_status_areas.append(diagnostic_area)
with SoftAssertions() as soft_failures:
# Проверяет причину режима МТ у всех ДУ с ожидаемым режимом МТ
for diagnostic_area in majority_status_areas:
stationary_status_reasons = t_utils.parse_stationary_status_reasons(
diagnostic_area.stationaryStatus, diagnostic_area.stationaryStatusReasons, soft_failures
)
StepCheck(
f"Проверка причины режима работы МТ на ДУ с id:{diagnostic_area.id}",
"stationaryStatusReasons",
soft_failures,
).contains(stationary_status_reasons, expected_stationary_status_reasons)
async def stationary_status_main_page_info(ws_client, cfg: BaseSuiteConfig, test_data: CaseData):
"""
Проверка установки режима МТ в сообщении MainPageInfoContent
"""
expected_stationary_status, _, _ = _unpack_stationary_status_test_data(test_data)
with allure.step("Подключение по ws, получение и обработка сообщения типа: MainPageInfoContent"):
payload = await t_utils.connect_and_poll_subscribed_msg(
ws_client,
"MainPageInfoContent",
"subscribeMainPageInfoRequest",
{'tuIds': [cfg.tu_id], 'additionalProperties': None},
)
parsed_payload = parser.parse_main_page_msg(payload)
with allure.step("Извлечение и подготовка данных для проверки"):
tu_info = getattr(parsed_payload.replyContent, 'tuInfo', None)
StepCheck("Проверка наличия данных по ТУ", "tuInfo").actual(tu_info).is_not_none()
main_pipeline_stationary_status = (
StationaryStatus(tu_info.stationaryStatus) if tu_info.stationaryStatus else None
)
with SoftAssertions() as soft_failures:
StepCheck("Проверка id полученного ТУ", "tu_id", soft_failures).actual(
parsed_payload.replyContent.tuId
).expected(cfg.tu_id).equal_to()
StepCheck(
f"Проверка установки режима МТ для ТУ {cfg.tu_name}",
"stationaryStatus",
soft_failures,
).actual(
main_pipeline_stationary_status
).expected(expected_stationary_status).equal_to()
async def stationary_status_in_output_signals(ws_client, cfg: BaseSuiteConfig, test_data: CaseData):
"""
Проверка установки режима МТ в сообщении OutputSignalsInfo
"""
# Распаковка тестовых данных
expected_stationary_status, _, control_points = _unpack_stationary_status_test_data(
test_data, require_control_points=True
)
unknown_control_points = [name for name in control_points if name not in TestConst.CONTROLLED_SITE_SEGMENTS]
if unknown_control_points:
pytest.fail(
"Для контрольных участков не найдены controlledSiteId/segmentId "
f"в конфигурации стенда: {unknown_control_points}"
)
# получает часть словаря для всего списка controlled_sites_names
controlled_sites_dict = {
name: TestConst.CONTROLLED_SITE_SEGMENTS[name]
for name in control_points
if name in TestConst.CONTROLLED_SITE_SEGMENTS
}
controlled_sites = [
{'controlledSiteId': controlled_site_id, 'segmentId': segment_id}
for key, (controlled_site_id, segment_id) in controlled_sites_dict.items()
]
with allure.step("Подключение по ws, получение и обработка сообщения типа: OutputSignalsInfo"):
output_signals_payload = await t_utils.connect_and_poll_subscribed_msg(
ws_client,
"OutputSignalsInfo",
"SubscribeOutputSignalsRequest",
{
'objects': {
'linearParts': [],
'controlledSites': controlled_sites,
},
'signalTypes': 1023,
'tuId': cfg.tu_id,
'additionalProperties': None,
},
)
parsed_output_signals = parser.parse_output_signals_info_msg(output_signals_payload)
with allure.step("Извлечение и подготовка данных для проверки"):
controlled_site_signals = getattr(parsed_output_signals.replyContent, 'controlledSiteSignals', [])
StepCheck("Проверка наличия данных выходных сигналов", "controlledSiteSignals").actual(
controlled_site_signals
).is_not_empty()
output_signals_site_stationary_statuses, missed_controlled_points = (
t_utils.collect_stationary_statuses_from_output_signals(controlled_site_signals, controlled_sites_dict)
)
output_signals_details = "\n".join(
f"{controlled_point}: {stationary_status}"
for controlled_point, stationary_status in output_signals_site_stationary_statuses
)
allure.attach(
output_signals_details,
name="OutputSignalsInfo: режимы МТ по участкам КП-КП (ЭФ Выходные сигналы)",
attachment_type=allure.attachment_type.TEXT,
)
with SoftAssertions() as soft_failures:
for item in output_signals_site_stationary_statuses:
control_point, stationary_status = item
StepCheck(
f"Проверка режима МТ на контрольном участке: {control_point}", "stationaryStatus", soft_failures
).actual(stationary_status).expected(expected_stationary_status).equal_to()
missed_controlled_points_is_empty = not missed_controlled_points
StepCheck(
"При обработке Выходных Сигналов найдены записи режима МТ для всех выбранных контрольных участков.",
"участки КП-КП",
soft_failures,
).actual(missed_controlled_points_is_empty).is_true_with_details(
expected_text="Контрольные участки, для которых не найдены записи режима МТ missed_controlled_points = []",
actual_text="Контрольные участки, для которых не найдены записи режима МТ "
f"missed_controlled_points = {missed_controlled_points}",
)
def stationary_status_journal(http_client, cfg: BaseSuiteConfig, test_data: CaseData):
"""
Проверка наличия записи в журнале о режиме МТ.
"""
# Распаковка данных для теста
expected_stationary_status, expected_stationary_status_reasons, control_points = (
_unpack_stationary_status_test_data(test_data, require_control_points=True)
)
with allure.step("Http запрос сообщений журнала с фильтром messageTypes=PUMPING_STATUS"):
end_time = datetime.now()
start_time = t_utils.datetime_minus_seconds(end_time, TestConst.JOURNAL_STATUS_TOTAL_WAIT)
request_body = t_utils.create_journal_req_body(
pagination=Pagination(limit=TestConst.JOURNAL_PAGINATION_STATUS_LIMIT, direction=Direction.FIRST.value),
filtering=Filtering(messageTypes=int(MessageType.PUMPING_STATUS), objects=FilteringObjects(tuId=cfg.tu_id)),
)
response = http_client.post_request(HttpConst.GET_MESSAGES_URL_PATH, request_body)
payload = t_utils.get_json_from_http_response(response)
parsed_payload = parser.parse_journal_msg(payload)
with allure.step("Извлечение и подготовка данных для проверки"):
messages_info = getattr(parsed_payload.replyContent, 'messagesInfo', [])
StepCheck("Проверка наличия сообщений в журнале", "messagesInfo").actual(messages_info).is_not_empty()
with allure.step("Фильтрация сообщений по времени и controlPoint"):
filter_start_msk = t_utils.localize_as_moscow(start_time)
filter_end_msk = t_utils.localize_as_moscow(end_time)
stationary_msg_by_control_points = []
missed_control_points = []
time_filtered = [
msg
for msg in messages_info
if filter_start_msk <= t_utils.ensure_moscow_timezone(msg.time) <= filter_end_msk
]
time_filtered.sort(key=lambda msg: t_utils.ensure_moscow_timezone(msg.time), reverse=True)
# Поиск нужных сообщений по КП
for control_point in control_points:
stationary_msg = next(
(msg for msg in time_filtered if msg.controlPoint == control_point),
None,
)
if stationary_msg:
stationary_msg_by_control_points.append(stationary_msg)
else:
missed_control_points.append(control_point)
StepCheck("Проверка наличия сообщений c controlPoint из списка в журнале", "messagesInfo").actual(
stationary_msg_by_control_points
).is_not_empty()
with SoftAssertions() as soft_failures:
for msg in stationary_msg_by_control_points:
msg_event = getattr(msg, 'event', None)
cp_stationary_status, cp_stationary_status_reasons = t_utils.parse_journal_event(msg_event)
StepCheck(f"Проверка режима работы МТ на КП:{msg.controlPoint}", "event", soft_failures).actual(
cp_stationary_status
).expected(expected_stationary_status).equal_to()
StepCheck(f"Проверка причины режима работы МТ на КП:{msg.controlPoint}", "event", soft_failures).contains(
cp_stationary_status_reasons, expected_stationary_status_reasons
)
missed_control_points_is_empty = not missed_control_points
StepCheck(
"При обработке сообщений журнала найдены сообщения для всех КП.",
"controlPoint",
soft_failures,
).actual(missed_control_points_is_empty).is_true_with_details(
expected_text="КП, для которых не найдены сообщения missed_control_points = []",
actual_text=f"КП, для которых не найдены сообщения missed_control_points = {missed_control_points}",
)
тест смоук
"""
Единый тестовый модуль для всех наборов данных (single-leak и multi-leak).
Архитектура параметризации:
- SUITE_PARAMS: тесты уровня набора (один раз на набор данных)
- LEAK_PARAMS: тесты уровня утечки (один раз на каждую утечку)
Для добавления нового набора:
1. Создать файл в test_config/datasets/
2. Тесты подхватятся автоматически
Запуск:
- Все тесты: pytest tests/test_smoke.py
- Один набор: pytest tests/test_smoke.py --suites=select_4
- Несколько наборов: pytest tests/test_smoke.py --suites=imitative_17,select_19_20
"""
import datetime
from typing import Any, List, Optional
import allure
import pytest
from clients.http_client import StandHttpClient
from clients.websocket_client import WebSocketClient
from constants.test_constants import BaseTN3Constants as Base_const
from test_config.datasets import ALL_SMOKE_CONFIGS
from test_config.models_for_tests import CaseMarkers, LeakTestConfig, SmokeSuiteConfig
from test_scenarios import lds_status_scenarios
from test_scenarios import smoke_scenarios as scenarios
from test_scenarios import stationary_status_scenarios as stationary_scenarios
# ===== ГЕНЕРАЦИЯ ПАРАМЕТРОВ =====
def _get_suite_markers(config: SmokeSuiteConfig) -> List[pytest.MarkDecorator]:
"""Маркеры для тестового набора."""
return [
pytest.mark.test_suite_name(config.suite_name),
pytest.mark.test_suite_data_id(config.suite_data_id),
pytest.mark.test_data_name(config.archive_name),
pytest.mark.tu_id(config.technological_unit.id),
pytest.mark.ost_name(config.ost_name),
]
def _generate_suite_params() -> List[Any]:
"""
Генерирует параметры для тестов уровня набора данных.
Один параметр на каждый config.
"""
return [
pytest.param(config, id=config.suite_name, marks=_get_suite_markers(config)) for config in ALL_SMOKE_CONFIGS
]
def _generate_leak_params() -> List[Any]:
"""
Генерирует параметры для тестов уровня утечки.
Для single-leak конфигов: один параметр (config, leak, 1)
Для multi-leak конфигов: N параметров (config, leak_n, n) для каждой утечки
"""
params: List[Any] = []
for config in ALL_SMOKE_CONFIGS:
# Собираем все утечки из конфига
if config.has_multiple_leaks:
leaks = config.leaks
elif config.leak:
leaks = [config.leak]
else:
continue # Нет утечек в конфиге
# Создаём параметр для каждой утечки
for index, leak in enumerate(leaks):
leak_number = index + 1
# ID для Allure/pytest: select_4 или select_19_20_leak_1
if len(leaks) > 1:
param_id = f"{config.suite_name}_leak_{leak_number}"
else:
param_id = config.suite_name
params.append(
pytest.param(
config,
leak,
leak_number,
id=param_id,
marks=_get_suite_markers(config),
)
)
return params
# ===== ПАРАМЕТРЫ ДЛЯ ТЕСТОВ =====
SUITE_PARAMS: List[Any] = _generate_suite_params()
LEAK_PARAMS: List[Any] = _generate_leak_params()
# ===== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ =====
def _apply_allure_markers(test_config: CaseMarkers, tag: str, title: str, description: Optional[str] = None) -> None:
"""Применяет allure-маркеры из конфига теста."""
if not test_config:
pytest.skip("Не заполнена конфигурация теста: тест пропущен")
allure.dynamic.tag(tag)
allure.dynamic.tag("SMOKE")
allure.dynamic.title(title)
if description:
allure.dynamic.description(description)
# ===== ТЕСТЫ УРОВНЯ НАБОРА =====
# Запускаются один раз для каждого config
@pytest.mark.parametrize("config", SUITE_PARAMS)
class TestSuiteScenarios:
"""
Тесты уровня набора данных.
Запускаются один раз для каждого конфига.
"""
@pytest.mark.critical_stop
def test_basic_info(self, http_client: StandHttpClient, config: SmokeSuiteConfig) -> None:
"""[BasicInfo] Проверка базовой информации СОУ: список ТУ"""
tag = "BasicInfo"
title = f"[{tag}] Проверка списка ТУ. ЭФ: Главная страница"
_apply_allure_markers(config.basic_info_test, tag, title)
scenarios.basic_info(http_client, config)
def test_journal_info(self, http_client: StandHttpClient, config: SmokeSuiteConfig) -> None:
"""[MessagesInfo] Проверка наличия сообщений в журнале"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка наличия сообщений в журнале. ЭФ: Журнал.Реальное время"
_apply_allure_markers(
config.journal_info_test,
tag,
title,
"Проверка наличия сообщений в журнале.\n" "Синхронный запрос типа: MessagesInfo",
)
scenarios.messages_exist_in_journal(http_client)
@pytest.mark.asyncio
async def test_lds_status_initialization(self, ws_client: WebSocketClient, config: SmokeSuiteConfig) -> None:
"""[CommonScheme] Проверка режима работы СОУ: Инициализация"""
tag = "CommonScheme"
title = f"[{tag}] Проверка режима работы СОУ: 'Инициализация'. ЭФ: Схема"
_apply_allure_markers(
config.lds_status_initialization_test,
tag,
title,
(
f"Проверка режима работы СОУ на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки : {config.lds_status_initialization_test.offset} мин.\n"
"Подписка на сообщения типа: CommonScheme\n"
"Ожидаемый режим работы СОУ: Инициализация"
),
)
await scenarios.lds_status_initialization(ws_client, config)
@pytest.mark.asyncio
async def test_diagnostics_of_signals_after_initialization(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig
) -> None:
"""[OutputSignalsInfo] Проверка выходных сигналов после выхода из инициализации"""
tag = "OutputSignalsInfo"
title = f"[{tag}] Проверка выходных сигналов после выхода из инициализации. ЭФ Диагностика сигналов"
_apply_allure_markers(
config.diagnostics_of_signals_after_initialization_test,
tag,
title,
(
f"Проверка состояния СОУ и перекачки на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки : {config.diagnostics_of_signals_after_initialization_test.offset} мин.\n"
),
)
test_data = config.controlled_sites_with_segment
await scenarios.diagnostics_of_signals_after_initialization(ws_client, config, test_data)
@pytest.mark.asyncio
def test_lds_status_init_in_journal(
self, http_client: StandHttpClient, config: SmokeSuiteConfig, imitator_start_time: datetime
) -> None:
"""[MessagesInfo] Проверка записи в журнале о входе СОУ в Инициализацию"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка записи в журнале: СОУ в Инициализации. ЭФ: Журнал. Реальное время"
description = (
f"Проверка записи в журнале о входе СОУ в Инициализацию на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.lds_status_init_in_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
)
_apply_allure_markers(config.lds_status_init_in_journal_test, tag, title, description)
scenarios.lds_status_init_in_journal(http_client, config, imitator_start_time)
@pytest.mark.asyncio
async def test_stationary_status_common_scheme(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig
) -> None:
"""[CommonScheme] Проверка режима работы и причины режима работы МТ на ЭФ: Схема"""
test_data = config.stationary_status_test_data
expected_stationary_status, expected_stationary_status_reasons = (
(test_data.expected_result if test_data else (None, None))
)
tag = "CommonScheme"
title = (
f"[{tag}] Проверка режима работы МТ: {expected_stationary_status},"
f" по причине: {expected_stationary_status_reasons}. ЭФ: Схема"
)
_apply_allure_markers(
config.stationary_status_common_scheme_test,
tag,
title,
(
f"Проверка режима работы МТ, на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.stationary_status_common_scheme_test.offset} мин.\n"
"Подписка на сообщения типа: CommonSchemeContent\n"
f"Ожидаемый режим работы МТ: {expected_stationary_status}\n "
f"Ожидаемая причина режима работы МТ: {expected_stationary_status_reasons}"
),
)
await stationary_scenarios.stationary_status_common_scheme(ws_client, config, test_data)
@pytest.mark.asyncio
async def test_stationary_status_main_page_info(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig
) -> None:
"""[MainPageInfo] Проверка установки режима работы МТ. ЭФ: Главная страница. Контент таблицы с ТУ"""
test_data = config.stationary_status_test_data
expected_stationary_status, expected_stationary_status_reasons = (
(test_data.expected_result if test_data else (None, None))
)
tag = "MainPageInfo"
title = f"[{tag}] Проверка установки режима работы МТ: {expected_stationary_status}. " \
"ЭФ: Главная страница. Контент таблицы с ТУ"
_apply_allure_markers(
config.stationary_status_main_page_info_test,
tag,
title,
(
f"Проверка установки режима работы МТ на данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.stationary_status_main_page_info_test.offset} мин.\n"
"Подписка на сообщения типа: MainPageInfoContent\n"
f"Ожидаемый режим работы МТ: {expected_stationary_status}"
),
)
await stationary_scenarios.stationary_status_main_page_info(ws_client, config, test_data)
@pytest.mark.asyncio
async def test_stationary_status_in_output_signals(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig
) -> None:
"""[OutputSignalsInfo] Проверка установки режима работы МТ. ЭФ: Диагностика сигналов. Выходные сигналы"""
test_data = config.stationary_status_test_data
expected_stationary_status, expected_stationary_status_reasons = (
(test_data.expected_result if test_data else (None, None))
)
tag = "OutputSignalsInfo"
title = f"[{tag}] Проверка режима работы МТ: {expected_stationary_status}. ЭФ: Диагностика сигналов. Выходные сигналы"
_apply_allure_markers(
config.stationary_status_in_output_signals_test,
tag,
title,
(
f"Проверка режима работы МТ, на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.stationary_status_in_output_signals_test.offset} мин.\n"
"Подписка на сообщения типа: OutputSignalsInfo\n"
f"Ожидаемый режим работы МТ: {expected_stationary_status}\n "
),
)
await stationary_scenarios.stationary_status_in_output_signals(ws_client, config, test_data)
@pytest.mark.asyncio
async def test_main_page_info_signals(self, ws_client: WebSocketClient, config: SmokeSuiteConfig) -> None:
"""[MainPageSignalsInfo] Проверка счетчиков состояния сигналов"""
tag = "MainPageSignalsInfo"
title = f"[{tag}] Проверка счетчиков состояния сигналов. ЭФ: Главная страница.Контент таблица по ТУ"
_apply_allure_markers(
config.main_page_info_signals_test,
tag,
title,
(
f"Проверка счетчиков состояния сигналов на данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.main_page_info_signals_test.offset} мин.\n"
"Подписка на сообщения типа: MainPageSignalsInfo\n"
),
)
await scenarios.main_page_info_signals(ws_client, config)
@pytest.mark.asyncio
async def test_imitate_flowmeter_signal(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
imitator_start_time: datetime,
) -> None:
"""[ImitateSignal] Проверка имитации расходомера"""
tag = "ImitateSignal"
title = f"[{tag}] Проверка имитации сигнала расходомера. ЭФ: Схема, Входные сигналы, Журнал"
_apply_allure_markers(
config.imitate_flowmeter_signal_test,
tag,
title,
(
"Проверка работы имитации и снятия имитации c расходомера "
f"на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.imitate_flowmeter_signal_test.offset} мин.\n"
"Синхронные запросы типа: ImitateSignalRequest, UnImitateSignalRequest\n"
"Подписка на сообщения типа: InputSignalsContent\n"
"Проверки:\n"
"Статус-код ответа на синхронный запрос имитации.\n"
"Значения в полях isImitated, quality и imitation.value расходомера "
"во входных сигналах после имитации.\n"
"Статус-код ответа на синхронный запрос снятия имитации.\n"
"Значение в поле isImitated расходомера во входных сигналах после снятия имитации.\n"
"Примечание: что бы не повлиять на проверки утечек, тест на имитацию выполняется во время "
"инициализации"
),
)
test_data = config.imitate_flowmeter_signal_test_data
await scenarios.imitate_sensor_signal(ws_client, http_client, config, test_data, imitator_start_time)
@pytest.mark.asyncio
async def test_imitate_pressure_sensor_signal(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
imitator_start_time: datetime,
) -> None:
"""[ImitateSignal] Проверка имитации датчика давления"""
tag = "ImitateSignal"
title = f"[{tag}] Проверка имитации сигнала датчика давления. ЭФ: Схема, Входные сигналы, Журнал"
_apply_allure_markers(
config.imitate_pressure_sensor_signal_test,
tag,
title,
(
"Проверка работы имитации и снятия имитации c датчика давления "
f"на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.imitate_pressure_sensor_signal_test.offset} мин.\n"
"Синхронные запросы типа: ImitateSignalRequest, UnImitateSignalRequest\n"
"Подписка на сообщения типа: InputSignalsContent\n"
"Проверки:\n"
"Статус-код ответа на синхронный запрос имитации.\n"
"Значения в полях isImitated, quality и imitation.value датчика давления "
"во входных сигналах после имитации.\n"
"Статус-код ответа на синхронный запрос снятия имитации.\n"
"Значение в поле isImitated датчика давления во входных сигналах после снятия имитации.\n"
"Примечание: что бы не повлиять на проверки утечек, тест на имитацию выполняется во время "
"инициализации"
),
)
test_data = config.imitate_pressure_sensor_signal_test_data
await scenarios.imitate_sensor_signal(ws_client, http_client, config, test_data, imitator_start_time)
@pytest.mark.asyncio
async def test_mask_signal(
self, ws_client: WebSocketClient, http_client: StandHttpClient, config: SmokeSuiteConfig
) -> None:
"""[MaskSignal] Проверка маскирования датчиков"""
tag = "MaskSignal"
title = f"[{tag}] проверка маскирования датчиков. ЭФ: Схема"
_apply_allure_markers(
config.mask_signal_test,
tag,
title,
(
f"Проверка работы маскирования и снятия маскирования на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.mask_signal_test.offset} мин.\n"
"Синхронные запросы типа: MaskSignalRequest, UnmaskSignalRequest\n"
"Подписка на сообщения типа: InputSignalsContent\n"
"Проверки:\n"
"Статус-код ответа на синхронный запрос маскирования.\n"
"Значение в поле isMasked сигнала во входных сигналах после маскирования.\n"
"Статус-код ответа на синхронный запрос снятия маскирования.\n"
"Значение в поле isMasked сигнала во входных сигналах после снятия маскирования.\n"
"Примечание: что бы не повлиять на проверки утечек, тест на маскирование выполняется во время "
"инициализации"
),
)
test_data = config.mask_signal_test_data
await scenarios.mask_signal_test(ws_client, http_client, config, test_data)
def test_mask_info_in_journal(
self, http_client: StandHttpClient, config: SmokeSuiteConfig, imitator_start_time: datetime
) -> None:
"""[MessagesInfo] Проверка записей журнала о маскировании и размаскировании"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка записей журнала о маскировании и размаскировании. ЭФ: Журнал.Реальное время"
description = (
f"Проверка записей журнала о маскировании и размаскировании на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.mask_info_in_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo\n"
"Проверки: структура, фильтрация по времени, совпадение тегов между маскированием и снятием.\n"
"Примечание: тест выполняется после теста маскирования, чтобы записи успели попасть в журнал"
)
_apply_allure_markers(config.mask_info_in_journal_test, tag, title, description)
scenarios.mask_info_in_journal(http_client, config, imitator_start_time)
@pytest.mark.asyncio
async def test_mask_du_on_mini_scheme(
self, ws_client: WebSocketClient, http_client: StandHttpClient, config: SmokeSuiteConfig
) -> None:
"""Проверка маскирования ДУ"""
tag = "MaskDuOnMiniScheme"
title = f"[{tag}] проверка маскирования линейного участка. ЭФ: Схема"
description = (
f"Проверка маскирования линейного участка, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.mask_signal_test.offset} мин.\n"
"Синхронные запросы типа: MaskLdsCommandRequest\n"
"Проверки:\n"
"Статус-код ответа на синхронный запрос маскирования.\n"
"Проверка маскирования ДУ в выходных сигналах.\n"
"Проверка маскирования на схеме.\n"
"Проверка сообщения о маскировании в журнале.\n"
)
_apply_allure_markers(config.mask_du_on_mini_scheme_test, tag, title, description)
await scenarios.mask_du_on_mini_scheme(ws_client, http_client, config)
@pytest.mark.asyncio
async def test_unmask_du_on_mini_scheme(
self, ws_client: WebSocketClient, http_client: StandHttpClient, config: SmokeSuiteConfig
) -> None:
"""Проверка размаскирования ДУ"""
tag = "UnmaskDuOnMiniScheme"
title = f"[{tag}] проверка снятия маскирования линейному участку. ЭФ: Схема"
description = (
f"Проверка снятия маскирования линейному участку, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.unmask_du_on_mini_scheme_test.offset} мин.\n"
"Синхронные запросы типа: UnmaskDuOnMiniScheme\n"
"Проверки:\n"
"Статус-код ответа на синхронный запрос снятия маски.\n"
"Проверка тега с маской в выходных сигналах.\n"
"Проверка сообщения о снятии маскирования в журнале.\n"
)
_apply_allure_markers(config.unmask_du_on_mini_scheme_test, tag, title, description)
await scenarios.unmask_du_on_mini_scheme(ws_client, http_client, config)
@pytest.mark.asyncio
async def test_lds_status_initialization_out(self, ws_client: WebSocketClient, config: SmokeSuiteConfig) -> None:
"""[CommonScheme] Проверка выхода СОУ из Инициализации"""
tag = "CommonScheme"
title = f"[{tag}] Проверка выхода СОУ из Инициализации. ЭФ: Схема"
_apply_allure_markers(
config.lds_status_initialization_out_test,
tag,
title,
(
f"Проверка выхода СОУ из Инициализации на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.lds_status_initialization_out_test.offset} мин.\n"
"Подписка на сообщения типа: CommonScheme\n"
"Ожидаемый режим работы СОУ: не Инициализация"
),
)
await scenarios.lds_status_initialization_out(ws_client, config)
def test_lds_status_init_out_in_journal(
self, http_client: StandHttpClient, config: SmokeSuiteConfig, imitator_start_time: datetime
) -> None:
"""[MessagesInfo] Проверка записи в журнале о выходе СОУ из Инициализации"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка записи в журнале: выход СОУ из Инициализации. ЭФ: Журнал. Реальное время"
description = (
f"Проверка записи в журнале о выходе СОУ из Инициализации на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.lds_status_init_out_in_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
)
_apply_allure_markers(config.lds_status_init_out_in_journal_test, tag, title, description)
scenarios.lds_status_init_out_in_journal(http_client, config, imitator_start_time)
@pytest.mark.asyncio
async def test_main_page_info_unstationary(self, ws_client: WebSocketClient, config: SmokeSuiteConfig) -> None:
"""[MainPageInfo] Проверка установки режима Нестационарный (для multi-leak)"""
tag = "MainPageInfo"
title = (
f"[{tag}] Проверка установки режима работы МТ: нестационарный. ЭФ: Главная страница. Контент таблица по ТУ"
)
_apply_allure_markers(
config.main_page_info_unstationary_test,
tag,
title,
(
f"Проверка установки режима работы МТ: нестационарный на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.main_page_info_unstationary_test.offset} мин.\n"
"Подписка на сообщения типа: MainPageInfo\n"
"Ожидаемый режим работы МТ: Нестационарный"
),
)
await scenarios.main_page_info_unstationary(ws_client, config)
def test_stationary_status_journal(
self,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
) -> None:
"""[MessagesInfo] Проверка режима работы МТ и причины режима работы МТ на ЭФ: Журнал. Реальное время"""
test_data = config.stationary_status_journal_test_data
expected_stationary_status, expected_stationary_status_reasons = (
(test_data.expected_result if test_data else (None, None))
)
tag = "MessagesInfo"
title = (
f"[{tag}] Проверка режима работы МТ: {expected_stationary_status},"
f" по причине: {expected_stationary_status_reasons}. ЭФ: Журнал. Реальное время"
)
_apply_allure_markers(
config.stationary_status_journal_test,
tag,
title,
(
f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {config.stationary_status_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo с фильтром messageTypes=PUMPING_STATUS\n"
f"Ожидаемый режим работы МТ: {expected_stationary_status}\n "
f"Ожидаемая причина режима работы МТ: {expected_stationary_status_reasons}"
),
)
stationary_scenarios.stationary_status_journal(http_client, config, test_data)
@pytest.mark.asyncio
async def test_export_lds_status_report(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
imitator_start_time: datetime,
) -> None:
tag = "ExportReports"
title = f"[{tag}] Проверка формирования отчёта о режиме работы СОУ. ЭФ: Выпадашка отчётов"
_apply_allure_markers(
config.export_lds_status_report_test,
tag,
title,
(
f"Проверка формирования и содержимого xlsx-отчёта о режиме работы СОУ на наборе данных "
f"{config.suite_name},\n"
f"на технологическом участке {config.tu_name}\n"
f"Период отчёта: от старта имитатора до старта + сдвиг теста "
f"{config.export_lds_status_report_test.offset} мин.\n"
"Этапы сценария:\n"
"1) SubscribeReportsDataExportedRequest - подписка на пуш-нотификации\n"
"2) ExportReportsCommandRequest - запрос формирования отчёта (тип LdsStateReport, фильтр по периоду)\n"
"3) Ожидание ReportDataExportedNotification\n"
"4) Лонг-поллинг GetExportedDataListRequest - поиск отчёта в списке\n"
"5) DownloadExportedDataRequest (StreamInvocation) - скачивание по exportedDataId\n"
"6) Проверка xlsx: участки, длительности режимов СОУ, суммарное время работы\n"
"7) Проверка двойной шапки и названий колонок\n"
"8) Проверка имени файла (.xlsx, название отчёта, ТУ, период +-1 мин)\n"
"Во вложениях Allure xlsx прикладывается только при падении теста"
),
)
await scenarios.export_lds_status_report(ws_client, http_client, config, imitator_start_time)
@pytest.mark.asyncio
async def test_export_mt_mode_report(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
imitator_start_time: datetime,
) -> None:
tag = "ExportReports"
title = f"[{tag}] Проверка формирования отчёта о режиме работы МТ. ЭФ: Выпадашка отчётов"
_apply_allure_markers(
config.export_mt_mode_report_test,
tag,
title,
(
f"Проверка формирования и содержимого xlsx-отчёта о режиме работы МТ на наборе данных "
f"{config.suite_name},\n"
f"на технологическом участке {config.tu_name}\n"
f"Период отчёта: от старта имитатора до старта + сдвиг теста "
f"{config.export_mt_mode_report_test.offset} мин.\n"
"Этапы сценария:\n"
"1) SubscribeReportsDataExportedRequest - подписка на пуш-нотификации\n"
"2) ExportReportsCommandRequest - запрос формирования отчёта (тип StationaryStatusReport)\n"
"3) Ожидание ReportDataExportedNotification\n"
"4) Лонг-поллинг GetExportedDataListRequest - поиск отчёта в списке\n"
"5) DownloadExportedDataRequest (StreamInvocation) - скачивание по exportedDataId\n"
"6) Проверка xlsx: участки, длительности режимов МТ, суммарное время, доминирующий режим\n"
"7) Проверка двойной шапки и названий колонок\n"
"8) Проверка имени файла (.xlsx, название отчёта, ТУ, период +-1 мин)\n"
"Во вложениях Allure xlsx прикладывается только при падении теста"
),
)
await scenarios.export_mt_mode_report(ws_client, http_client, config, imitator_start_time)
# ===== ТЕСТЫ УРОВНЯ УТЕЧКИ =====
# Запускаются для каждой утечки в конфиге
@pytest.mark.parametrize("config, leak, leak_number", LEAK_PARAMS)
class TestLeakScenarios:
"""
Тесты уровня утечки.
Для single-leak: запускаются один раз.
Для multi-leak: запускаются для каждой утечки отдельно.
"""
@pytest.mark.asyncio
async def test_all_leaks_info(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[AllLeaksInfo] Проверка утечки в пуше"""
tag = "AllLeaksInfo"
title = f"[{tag}] Проверка сообщения об утечке. ЭФ: Пуш-сообщение об утечке на всех ЭФ"
_apply_allure_markers(
leak.all_leaks_info_test,
tag,
title,
(
f"Проверка пуш-сообщения об утечке на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.all_leaks_info_test.offset} мин.\n"
"Подписка на сообщения типа: AllLeaksInfo\n"
f"Допустимое время обнаружения {leak.allowed_time_diff_minutes} мин. с момента начала утечки, "
f"т к для данных {config.suite_name} интенсивность утечки {leak.leak_rate_percentages}%.\n"
"Примечание: тесты сообщений об утечке должны выполняться раньше теста на квитирование"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.all_leaks_info(ws_client, config, leak, imitator_start_time)
@pytest.mark.asyncio
async def test_all_leaks_is_empty(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""[AllLeaksInfo] Проверка отсутствия информации об утечке"""
tag = "AllLeaksInfo"
title = f"[{tag}] Проверка отсутствия информации об утечке в сообщении. ЭФ: Пуш-сообщение об утечке"
_apply_allure_markers(
leak.all_leaks_is_empty_test,
tag,
title,
(
"Проверка отсутствия информации об утечке в сообщении, \n"
f"Время проведения проверки: {leak.all_leaks_is_empty_test.offset} мин.\n"
"Подписка на сообщения типа: AllLeaksInfo\n"
"Примечание: проверяем, когда в КГ табличный вид список пуст"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.all_leaks_is_empty(ws_client, config)
@pytest.mark.asyncio
async def test_leaks_content(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[LeaksContent] Проверка сообщения об утечке в таблице КГ"""
tag = "LeaksContent"
title = f"[{tag}] Проверка сообщения об утечке. ЭФ: КГ.Табличное представление"
_apply_allure_markers(
leak.leaks_content_test,
tag,
title,
(
f"Проверка сообщения об утечке в таблице КГ на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.leaks_content_test.offset} мин.\n"
"Подписка на сообщения типа: LeaksContent\n"
f"Допустимое время обнаружения {leak.allowed_time_diff_minutes} мин. с момента начала утечки, "
f"т к для данных {config.suite_name} интенсивность утечки {leak.leak_rate_percentages}%.\n"
"Примечание: тесты сообщений об утечке должны выполняться раньше теста на квитирование"
),
)
# Добавляем номер утечки в title для multi-leak
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.leaks_content(ws_client, config, leak, imitator_start_time)
def test_leak_info_in_journal(
self,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[MessagesInfo] Проверка сообщения об утечке в журнале"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка сообщения об утечке в журнале. ЭФ: Журнал.Реальное время"
_apply_allure_markers(
leak.leak_info_in_journal,
tag,
title,
(
f"Проверка сообщения об утечке в журнале на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.leak_info_in_journal.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo\n"
f"Допустимое время обнаружения {leak.allowed_time_diff_minutes} мин. с момента начала утечки, "
f"т к для данных {config.suite_name} интенсивность утечки {leak.leak_rate_percentages}%.\n"
"Примечание: тесты сообщений об утечке должны выполняться раньше теста на квитирование"
),
)
# Добавляем номер утечки в title для multi-leak
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
scenarios.leak_info_in_journal(http_client, config, leak, imitator_start_time)
def test_completed_leak_info_in_journal(
self,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[MessagesInfo] Проверка сообщения о завершенной утечке в журнале"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка сообщения о завершенной утечке в журнале. ЭФ: Журнал.Реальное время"
description = (
f"Проверка сообщения о завершенной утечке в журнале на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.completed_leak_info_in_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo\n"
)
_apply_allure_markers(
leak.completed_leak_info_in_journal_test,
tag,
title,
description,
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
scenarios.completed_leak_info_in_journal(http_client, config, leak, imitator_start_time)
def test_possible_leak_in_journal(
self,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[MessagesInfo] Проверка наличия сообщения 'Возможна утечка' в журнале"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка сообщения 'Возможна утечка' в журнале. ЭФ: Журнал. Реальное время"
description = (
f"Проверка наличия сообщения 'Возможна утечка' в журнале на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.possible_leak_in_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo"
)
_apply_allure_markers(leak.possible_leak_in_journal_test, tag, title, description)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
scenarios.possible_leak_in_journal(http_client, config, imitator_start_time)
@pytest.mark.asyncio
async def test_tu_leaks_info(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[TuLeaksInfo] Проверка утечки на ТУ"""
tag = "TuLeaksInfo"
title = f"[{tag}] Проверка сообщения об утечке. Сообщения на ЭФ: Схема, Минисхема, Гидроуклон"
_apply_allure_markers(
leak.tu_leaks_info_test,
tag,
title,
(
f"Проверка сообщения об утечке на схемах и гидроуклоне на наборе данных {config.suite_name}, \n"
f"на технологическом участке {leak.diagnostic_area_name}\n"
f"Время проведения проверки: {leak.tu_leaks_info_test.offset} мин.\n"
"Подписка на сообщения типа: TuLeaksInfo\n"
f"Допустимое время обнаружения {leak.allowed_time_diff_minutes} мин. с момента начала утечки, "
f"т к для данных {config.suite_name} интенсивность утечки {leak.leak_rate_percentages}%.\n"
"Примечание: тесты сообщений об утечке должны выполняться раньше теста на квитирование"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.tu_leaks_info(ws_client, config, leak, imitator_start_time)
@pytest.mark.asyncio
async def test_lds_status_during_leak(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""[CommonScheme] Проверка режима работы СОУ во время утечки"""
tag = "CommonScheme"
title = f"[{tag}] Проверка режима работы СОУ во время утечки. ЭФ: Схема"
_apply_allure_markers(
leak.lds_status_during_leak_test,
tag,
title,
(
f"Проверка режима работы СОУ во время утечки на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.lds_status_during_leak_test.offset} мин.\n"
"Подписка на сообщения типа: CommonScheme\n"
"Примечание: проверка режимов СОУ во время утечки должна выполняться раньше теста на квитирование\n"
"В рамках данного теста проверяется режим СОУ на ДУ с утечкой и на соседних ДУ"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.lds_status_during_leak(ws_client, config, leak)
@pytest.mark.asyncio
async def test_acknowledge_leak_info(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""[AcknowledgeLeak] Проверка квитирования утечки"""
tag = "AcknowledgeLeak"
title = f"[{tag}] Проверка квитирования утечки. Отсутствие Пуш-сообщений об утечке на всех ЭФ"
_apply_allure_markers(
leak.acknowledge_leak_test,
tag,
title,
(
"Проверка квитирования утечки на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.acknowledge_leak_test.offset} мин.\n"
"Синхронный запрос типа: AcknowledgeLeak\n"
"Подписка на сообщения типа: TuLeaksInfo, AllLeaksInfo\n"
"Проверки:\n"
"Статус-код ответа на синхронный запрос о квитировании,\n"
"Отсутствие пуш-сообщений об утечках после квитирования"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.acknowledge_leak_info(ws_client, http_client, config, leak)
def test_acknowledge_leak_in_journal(
self,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[MessagesInfo] Проверка записи в журнале о квитировании утечки"""
tag = "MessagesInfo"
title = f"[{tag}] Проверка записи в журнале о квитировании утечки. ЭФ: Журнал. Реальное время"
description = (
f"Проверка записи о квитировании утечки в журнале на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.acknowledge_leak_in_journal_test.offset} мин.\n"
"Синхронный запрос типа: MessagesInfo с фильтром userActions=LEAK_ACK\n"
)
_apply_allure_markers(leak.acknowledge_leak_in_journal_test, tag, title, description)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
scenarios.acknowledge_leak_in_journal(http_client, config, imitator_start_time)
@pytest.mark.asyncio
async def test_output_signals(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[OutputSignalsInfo] Проверка данных об утечке в выходных сигналах"""
tag = "OutputSignalsInfo"
title = (
f"[{tag}] Проверка наличия данных об утечке в выходных сигналах. ЭФ: Диагностика сигналов.Выходные "
f"сигналы"
)
_apply_allure_markers(
leak.output_signals_test,
tag,
title,
(
f"Проверка наличия данных об утечке в выходных сигналах на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.output_signals_test.offset} мин.\n"
"Синхронный запрос типа: GetOutputSignals\n"
"Подписка на сообщения типа: SubscribeOutputSignals\n"
f"Допустимое время обнаружения {leak.allowed_time_diff_minutes} мин. с момента начала утечки, "
f"т к для данных {config.suite_name} интенсивность утечки {leak.leak_rate_percentages}%.\n"
"Примечание: "
"В offset указано время проверок сообщения выходных сигналов + 1 минута "
"для корректной отработки проверок.\n"
"Данный тест так же проверяет квитирование, offset выставлять после запуска теста на квитирование "
"утечки"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.output_signals(ws_client, http_client, config, leak, imitator_start_time)
@pytest.mark.asyncio
async def test_balance_algorithm_leak_waiting(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
"""[BalanceAlgorithmResultsContent] Проверка сообщения 'подозрение на утечку' в таблице КГ"""
tag = "BalanceAlgorithmResultsContent"
title = f"[{tag}] Проверка сообщения 'подозрение на утечку'. ЭФ: КГ.Графическое представление"
_apply_allure_markers(
leak.balance_algorithm_leak_waiting_test,
tag,
title,
(
f"Проверка сообщения 'подозрение на утечку' в таблице КГ, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: "
f"{leak.balance_algorithm_leak_waiting_test.offset} - "
f"{leak.balance_algorithm_leak_waiting_test.offset + Base_const.BALANCE_ALGORITHM_TOTAL_WAIT / 60} "
f"мин.\n"
"Подписка на сообщения типа: BalanceAlgorithmResultsContent\n"
),
)
# Добавляем номер утечки в title для multi-leak
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.balance_algorithm_leak_waiting(ws_client, config, leak, imitator_start_time)
@pytest.mark.asyncio
async def test_balance_algorithm_leak_detected(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""[BalanceAlgorithmResultsContent] Проверка наличия утечки (isLeakDetected) в графическом представлении КГ"""
tag = "BalanceAlgorithmResultsContent"
title = f"[{tag}] Проверка наличия утечки (isLeakDetected). ЭФ: КГ Графическое представление"
_apply_allure_markers(
leak.balance_algorithm_leak_detected_test,
tag,
title,
(
f"Проверка наличия утечки (isLeakDetected) в графическом представлении КГ, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.balance_algorithm_leak_detected_test.offset} мин.\n"
"Подписка на сообщения типа: BalanceAlgorithmResultsContent\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.balance_algorithm_leak_detected(ws_client, config, leak)
@pytest.mark.asyncio
async def test_balance_algorithm_leak_completed(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""
[BalanceAlgorithmResultsContent] Проверка отсутствия утечки (isLeakDetected) в графическом представлении КГ
"""
tag = "BalanceAlgorithmResultsContent"
title = (
f"[{tag}] Проверка отсутствия утечки (isLeakDetected) после завершения утечки. "
f"ЭФ: КГ Графическое представление"
)
_apply_allure_markers(
leak.balance_algorithm_leak_detected_test,
tag,
title,
(
f"Проверка отсутствия утечки (isLeakDetected) в графическом представлении КГ, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.balance_algorithm_leak_detected_test.offset} мин.\n"
"Подписка на сообщения типа: BalanceAlgorithmResultsContent\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.balance_algorithm_leak_completed(ws_client, config)
@pytest.mark.asyncio
async def test_lds_status_after_confirming_leak(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig, leak: LeakTestConfig, leak_number: int
) -> None:
"""
[CommonScheme] Проверка режима работы СОУ: Инициализация
Причина: Накопление данных
"""
tag = "CommonScheme"
title = f"[{tag}] Проверка режима работы СОУ: Инициализация, по причине: Накопление данных. ЭФ: Схема"
_apply_allure_markers(
leak.lds_status_after_confirming_leak_test,
tag,
title,
(
f"Проверка режима работы СОУ на выбранном ДУ, на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
"Время проведения проверки : "
f"{leak.lds_status_after_confirming_leak_test.offset} мин.\n"
"Подписка на сообщения типа: CommonScheme\n"
"Ожидаемый режим работы СОУ: Инициализация\n "
"Ожидаемая причина режима работы СОУ: Накопление данных"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
test_data = leak.lds_status_after_confirming_leak_data
await lds_status_scenarios.lds_status_check_with_reasons(ws_client, config, test_data)
await lds_status_scenarios.lds_status_check_with_reasons(ws_client, config, test_data)
@pytest.mark.asyncio
async def test_lds_status_completed_leak(
self, ws_client: WebSocketClient, config: SmokeSuiteConfig, leak: LeakTestConfig, leak_number: int
) -> None:
"""
[CommonScheme] Проверка режима работы СОУ после завершения утечки: Инициализация
Причина: Накопление данных
"""
tag = "CommonScheme"
title = (
f"[{tag}] Проверка режима работы СОУ после завершения утечки: Инициализация"
"Причина: Накопление данных. ЭФ: Схема"
)
_apply_allure_markers(
leak.lds_status_after_confirming_leak_test,
tag,
title,
(
f"Проверка режима работы СОУ на выбранном ДУ, на наборе данных {config.suite_name}, \n"
f"на технологическом участке {config.tu_name}\n"
"Время проведения проверки : "
f"{leak.lds_status_completed_leak_test.offset} мин.\n"
"Подписка на сообщения типа: CommonScheme\n"
"Ожидаемый режим работы СОУ: Инициализация\n "
"Ожидаемая причина режима работы СОУ: Накопление данных"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
test_data = leak.lds_status_after_completed_leak_data
await lds_status_scenarios.lds_status_check_with_reasons(ws_client, config, test_data)
@pytest.mark.asyncio
async def test_leak_is_complete_on_main_page(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""Проверка отсутствия утечки на ЭФ Состояние МТ"""
tag = "MainPageInfoContent"
title = f"[{tag}] Проверка отсутствия утечки на ЭФ Состояние МТ."
_apply_allure_markers(
leak.leak_is_complete_on_main_page_test,
tag,
title,
(
f"Проверка отсутствия утечки на ЭФ Состояние МТ\n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.leak_is_complete_on_main_page_test.offset} мин.\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.leak_is_complete_on_main_page(ws_client, config)
@pytest.mark.asyncio
async def test_leak_is_confirm_on_main_page(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""Проверка подтвержденной утечки на ЭФ Состояние МТ"""
tag = "MainPageInfoContent"
title = f"[{tag}] Проверка подтвержденной утечки на ЭФ Состояние МТ"
_apply_allure_markers(
leak.leak_is_confirm_on_main_page_test,
tag,
title,
(
f"Проверка наличия утечки на ЭФ Состояние МТ \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.leak_is_confirm_on_main_page_test.offset} мин.\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.leak_is_confirm_on_main_page(ws_client, config)
@pytest.mark.asyncio
async def test_the_leak_is_complete_on_kg(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""Проверка события завершения утечки в контроле герметичности"""
tag = "LeaksContent"
title = f"[{tag}] Проверка cобытия завершения утечки ЭФ КГ табличный вид."
_apply_allure_markers(
leak.the_leak_is_complete_on_kg_test,
tag,
title,
(
f"Проверка ЭФ КГ табличное представление, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.the_leak_is_complete_on_kg_test.offset} мин.\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.leak_is_complete_on_kg(ws_client, config, leak)
@pytest.mark.asyncio
async def test_leak_is_complete_in_output_signals(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""Проверка отсутствия утечки в выходных сигналах"""
tag = "OutputSignalsInfo"
title = f"[{tag}] Проверка отсутствия утечки в выходных сигналах."
_apply_allure_markers(
leak.leak_is_complete_in_output_signals_test,
tag,
title,
(
f"Проверка ЭФ Выходные сигналы \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.leak_is_complete_in_output_signals_test.offset} мин.\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.leak_is_complete_in_output_signals(ws_client, http_client, config, leak)
@pytest.mark.asyncio
async def test_complete_tu_leaks_info_content(
self,
ws_client: WebSocketClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
) -> None:
"""Проверка сообщения в журнале о завершении утечки"""
tag = "TuLeaksInfoContent"
title = f"[{tag}] Проверка отсутствия утечки на схеме"
_apply_allure_markers(
leak.complete_tu_leaks_info_content_test,
tag,
title,
(
f"Проверка ЭФ Схема, \n"
f"на технологическом участке {config.tu_name}\n"
f"Время проведения проверки: {leak.complete_tu_leaks_info_content_test.offset} мин.\n"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.complete_tu_leaks_info_content(ws_client, config)
@pytest.mark.asyncio
async def test_export_leaks_report(
self,
ws_client: WebSocketClient,
http_client: StandHttpClient,
config: SmokeSuiteConfig,
leak: LeakTestConfig,
leak_number: int,
imitator_start_time: datetime,
) -> None:
tag = "ExportReports"
title = f"[{tag}] Проверка формирования отчёта об утечках. ЭФ: Выпадашка отчётов"
_apply_allure_markers(
leak.export_leaks_report_test,
tag,
title,
(
f"Проверка формирования и содержимого xlsx-отчёта об утечках на наборе данных "
f"{config.suite_name},\n"
f"на технологическом участке {config.tu_name}\n"
f"Период отчёта: от старта имитатора до старта + сдвиг теста"
f"{leak.export_leaks_report_test.offset} мин.\n"
"Этапы сценария:\n"
"1) SubscribeReportsDataExportedRequest - подписка на пуш-нотификации\n"
"2) ExportReportsCommandRequest - запрос формирования отчёта (тип LeaksReport, фильтр по периоду)\n"
"3) Ожидание ReportDataExportedNotification - пуш-нотификация о формировании отчёта\n"
"4) Лонг-поллинг GetExportedDataListRequest - поиск отчёта в списке "
"(имя, ТУ, период start/end с погрешностью +-1 мин)\n"
"5) DownloadExportedDataRequest (StreamInvocation) - скачивание по exportedDataId\n"
"6) Приём fileChunk, проверка формата xlsx (zip-сигнатура, контент существует)\n"
"7) Проверка имени файла: .xlsx, 'Отчет об утечках', название ТУ, "
"диапазон дат в имени (+-1 мин)\n"
"8) Проверка шапки xlsx: заголовок с периодом (+-1 мин), названия колонок\n"
"9) Проверка строки утечки: дата в периоде, объект, режим СОУ, маскирование, "
"координата, объём, режим работы МТ\n"
"Во вложениях Allure xlsx прикладывается только при падении теста"
),
)
if config.has_multiple_leaks:
allure.dynamic.title(f"{title} (утечка #{leak_number})")
await scenarios.export_leaks_report(ws_client, http_client, config, leak, imitator_start_time)