Загрузка данных
lds_status_regress_bik.py lfnfctn
"""
Конфигурация тестового набора Lds_status_regress_in_flow
Особенности набора:
- В течении
- Проверка режимов работы СОУ
- Проверка группы причин режимов работы СОУ, связанных с БИК
"""
from constants.enums import TU, AdminTU, LdsStatus, LdsStatusDegradation, LdsStatusInitialization, MeasureConversionRule
from constants.test_constants import BaseTN3Constants as TestConst
from test_config.models_for_tests import CaseData, CaseMarkers, LDSStatusConfig
# ===== Константы набора =====
SUITE_NAME = "Lds_status_regress_bik"
SUITE_DATA_ID = 18
ARCHIVE_NAME = f"{SUITE_NAME}.tar.gz"
DIAGNOSTIC_AREA_2_PIPE_ID = 1463
DIAGNOSTIC_AREA_3_PIPE_ID = 474
DIAGNOSTIC_AREA_5_PIPE_ID = 1474
# Технологический участок
TECHNOLOGICAL_UNIT = TU.TIKHORETSK_NOVOROSSIYSK_3
# Название МН
MAIN_PIPELINE = "МН Тихорецк-Новороссийск-3"
# ===== Конфигурация набора =====
LDS_STATUS_BIK_CONFIG = LDSStatusConfig(
# ----- Метаданные -----
ost_name=TestConst.CHTN_OST_NAME,
suite_name=SUITE_NAME,
suite_data_id=SUITE_DATA_ID,
archive_name=ARCHIVE_NAME,
technological_unit=TECHNOLOGICAL_UNIT,
measure_conversion_rules=MeasureConversionRule.KG_CM_MEASURE,
# ===== LDS Configurator =====
use_lds_configurator=True,
admin_tu=AdminTU.TIKHORETSK_NOVOROSSIYSK_3_AUTOTEST_DATA_ABSENCE_FALSE,
main_pipeline=MAIN_PIPELINE,
init_cold_start_test_data=CaseData(
expected_result=(LdsStatus.INITIALIZATION, LdsStatusInitialization.COLD_START_OF_SERVERS),
),
deg_rejection_temperature_sensor_on_du_2_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_2_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.REJECTION_TEMPERATURE_SENSOR,
),
),
deg_rejection_temperature_sensor_on_du_3_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_3_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.REJECTION_TEMPERATURE_SENSOR,
),
),
deg_rejection_temperature_sensor_on_du_5_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_5_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.REJECTION_TEMPERATURE_SENSOR,
),
),
deg_rejection_density_and_viscosity_on_du_2_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_2_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.REJECTION_DENSITY_SENSOR,
LdsStatusDegradation.REJECTION_VISCOSITY_SENSOR,
),
),
deg_rejection_density_and_viscosity_on_du_3_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_3_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.REJECTION_DENSITY_SENSOR,
LdsStatusDegradation.REJECTION_VISCOSITY_SENSOR,
),
),
deg_rejection_density_and_viscosity_on_du_5_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_5_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.REJECTION_DENSITY_SENSOR,
LdsStatusDegradation.REJECTION_VISCOSITY_SENSOR,
),
),
# ===== ТЕСТЫ =====
lds_status_basic_info_test=CaseMarkers(test_case_id="1", offset=5),
init_cold_start_test=CaseMarkers(test_case_id="18", offset=7),
init_cold_start_in_journal_test=CaseMarkers(test_case_id="228", offset=7),
deg_rejection_temperature_sensor_on_du_2_test=CaseMarkers(test_case_id="179", offset=25),
deg_rejection_density_and_viscosity_on_du_2_test=CaseMarkers(test_case_id="181", offset=35),
deg_rejection_temperature_sensor_on_du_3_test=CaseMarkers(test_case_id="179", offset=58),
deg_rejection_density_and_viscosity_on_du_3_test=CaseMarkers(test_case_id="181", offset=68),
)
lds_status_regress_in_flow
"""
Конфигурация тестового набора Lds_status_regress_in_flow
Особенности набора:
- В течении
- Проверка режимов работы СОУ
- Проверка причин режимов работы СОУ
"""
from constants.enums import (
TU,
AdminTU,
LdsStatus,
LdsStatusDegradation,
LdsStatusFaulty,
LdsStatusInitialization,
MeasureConversionRule,
StationaryStatus,
UnStationaryReason,
)
from constants.test_constants import BaseTN3Constants as TestConst
from test_config.models_for_tests import CaseData, CaseMarkers, LDSStatusConfig
# ===== Константы набора =====
SUITE_NAME = "Lds_status_regress_in_flow"
SUITE_DATA_ID = 17
ARCHIVE_NAME = f"{SUITE_NAME}.tar.gz"
DIAGNOSTIC_AREA_2_PIPE_ID = 1463
DIAGNOSTIC_AREA_3_PIPE_ID = 474
DIAGNOSTIC_AREA_5_PIPE_ID = 1478
PIG_TRAP_ID = 344
# Технологический участок
TECHNOLOGICAL_UNIT = TU.TIKHORETSK_NOVOROSSIYSK_3
# Название МН
MAIN_PIPELINE = "МН Тихорецк-Новороссийск-3"
# ===== Конфигурация набора =====
LDS_STATUS_INFLOW_CONFIG = LDSStatusConfig(
# ----- Метаданные -----
ost_name=TestConst.CHTN_OST_NAME,
suite_name=SUITE_NAME,
suite_data_id=SUITE_DATA_ID,
archive_name=ARCHIVE_NAME,
main_pipeline=MAIN_PIPELINE,
technological_unit=TECHNOLOGICAL_UNIT,
measure_conversion_rules=MeasureConversionRule.KG_CM_MEASURE,
# ===== LDS Configurator =====
use_lds_configurator=True,
admin_tu=AdminTU.TIKHORETSK_NOVOROSSIYSK_3_AUTOTEST_DATA_ABSENCE_FALSE,
init_cold_start_test_data=CaseData(
expected_result=(LdsStatus.INITIALIZATION, LdsStatusInitialization.COLD_START_OF_SERVERS),
),
serviceable_all_in_journal_test_data=CaseData(
expected_result=(LdsStatus.INITIALIZATION, LdsStatusInitialization.COLD_START_OF_SERVERS),
),
serviceable_all_test_data=CaseData(
params={"pipe_ids": [DIAGNOSTIC_AREA_2_PIPE_ID, DIAGNOSTIC_AREA_3_PIPE_ID]},
expected_result=LdsStatus.SERVICEABLE,
),
deg_additive_injectors_operation_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_3_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.ADDITIVE_INJECTORS_OPERATION,
),
),
deg_exceeding_distance_between_pressure_sensors_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_3_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.EXCEEDING_DISTANCE_BETWEEN_SERVICEABLE_PRESSURE_SENSORS,
),
),
deg_absence_min_pressure_sensors_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_5_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.ABSENCE_MIN_PRESSURE_SENSORS_REQUIRED_NUMBER,
),
),
deg_faulty_pressure_sensors_at_pump_station_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_2_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.FAULTY_PRESSURE_SENSORS_AT_PUMP_STATION_NODES,
),
),
deg_gravity_section_pumping_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_5_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.GRAVITY_SECTION_IN_PUMPING_MODE,
),
),
deg_pig_sensor_passage_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_2_PIPE_ID, "pig_trap_id": PIG_TRAP_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.PIG_SENSOR_PASSAGE,
),
),
deg_starting_pumping_out_pumps_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_2_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.STARTING_PUMPING_OUT_PUMPS,
StationaryStatus.UNSTATIONARY,
UnStationaryReason.CHANGING_WORKING_OF_PUMPING_OUT_PUMPS,
),
),
faulty_absence_min_flow_meters_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_5_PIPE_ID},
expected_result=(
LdsStatus.FAULTY,
LdsStatusFaulty.ABSENCE_MIN_FLOW_METERS_REQUIRED_NUMBER,
),
),
deg_exceeding_distance_between_flow_meters_test_data=CaseData(
params={"pipe_id": DIAGNOSTIC_AREA_3_PIPE_ID},
expected_result=(
LdsStatus.DEGRADATION,
LdsStatusDegradation.EXCEEDING_DISTANCE_BETWEEN_FLOW_METERS,
),
),
# ===== ТЕСТЫ =====
lds_status_basic_info_test=CaseMarkers(test_case_id="1", offset=5),
init_cold_start_test=CaseMarkers(test_case_id="17", offset=7),
init_cold_start_in_journal_test=CaseMarkers(test_case_id="228", offset=7),
serviceable_after_cold_start_test=CaseMarkers(test_case_id="186", offset=22),
deg_exceeding_distance_between_pressure_sensors_test=CaseMarkers(test_case_id="164", offset=32),
deg_gravity_section_pumping_test=CaseMarkers(test_case_id="167", offset=34),
deg_absence_min_pressure_sensors_test=CaseMarkers(test_case_id="166", offset=38.5),
serviceable_after_deg_absence_min_pressure_sensors_test=CaseMarkers(test_case_id="186", offset=43),
deg_starting_pumping_out_pumps_test=CaseMarkers(test_case_id="174", offset=46),
serviceable_after_deg_starting_pumping_out_pumps_test=CaseMarkers(test_case_id="186", offset=52.5),
faulty_absence_min_flow_meters_test=CaseMarkers(test_case_id="170", offset=60),
faulty_absence_min_flow_meters_continuous_test=CaseMarkers(test_case_id="170", offset=73),
serviceable_after_faulty_test=CaseMarkers(test_case_id="186", offset=76),
deg_exceeding_distance_between_flow_meters_test=CaseMarkers(test_case_id="169", offset=107),
# serviceable_after_deg_exceeding_distance_between_flow_meters_test=CaseMarkers(test_case_id="186", offset=114.5),
# TODO разобраться в LDS-14444
deg_faulty_pressure_sensors_at_pump_station_test=CaseMarkers(test_case_id="184", offset=122),
serviceable_after_deg_faulty_pressure_sensors_at_pump_test=CaseMarkers(test_case_id="186", offset=126),
deg_additive_injectors_operation_test=CaseMarkers(test_case_id="188", offset=132),
deg_pig_sensor_passage_test=CaseMarkers(test_case_id="165", offset=140),
)
models_for_tests
"""
Датаклассы для конфигурации тестовых наборов.
Архитектура:
- TestSuiteConfig - главный конфиг набора, содержит всё для запуска тестов
- LeakTestConfig - конфиг утечки с параметрами и тест-кейсами
- TestCaseMarkers - маркеры для allure и pytest
Принцип: один файл конфига select_xx.py в папке datasets = один набор данных.
"""
from dataclasses import asdict, dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional
from constants.enums import (
TU,
AdminTU,
ConfirmationStatus,
LdsStatus,
MeasureConversionRule,
RejectionCriteria,
RejectionSensorTag,
ReservedType,
StationaryStatus,
)
from constants.test_constants import BaseTN3Constants
from models.export_reports_model import ReportDataExportedNotification
from models.get_exported_files_list_model import ExportedDataItem
from models.subscribe_main_page_signals_info_model import SignalsInfo
from models.upload_exported_file_model import DownloadExportedDataReply
from utils.helpers.report_xlsx_utils import LeakReportRow, ReportTitleInfo
@dataclass
class CaseMarkers:
"""
Маркеры тест-кейса для pytest и allure.
"""
test_case_id: str
offset: float
class SuiteTuIdentityMixin:
"""
Идентификация ТУ для WS-тестов и legacy-стенда.
Поля technological_unit, use_lds_configurator, admin_tu, resolved_tu_id
объявляются в BaseSuiteConfig.
"""
technological_unit: TU
use_lds_configurator: bool
admin_tu: Optional[AdminTU]
resolved_tu_id: Optional[int]
@property
def admin_tu_name(self) -> str:
"""tuName для поиска ТУ в Администрировании."""
if self.admin_tu is None:
return ""
return self.admin_tu.admin_name
@property
def legacy_tu_id(self) -> int:
"""Legacy id ТУ для имитатора, tags.txt и конфигурации стенда."""
return self.technological_unit.id
@property
def legacy_tu_name(self) -> str:
"""Legacy имя ТУ из enum TU."""
return self.technological_unit.description
@property
def tu_name(self) -> str:
"""Имя ТУ для WS-тестов и отчётов: admin при configurator, иначе legacy."""
if self.use_lds_configurator:
if self.admin_tu is None:
return ""
return self.admin_tu.admin_name
return self.technological_unit.description
@property
def tu_id(self) -> int:
"""ID ТУ для WS-тестов: resolved из Администрирования при configurator, иначе legacy."""
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
return self.technological_unit.id
@property
def configurator_tu_id(self) -> int:
"""tuId из Администрирования после configurator setup (LaunchLds/StopLds)."""
if self.resolved_tu_id is None:
raise RuntimeError(
"resolved_tu_id не установлен - выполнить lds_configurator_admin_setup "
"перед операциями Администрирования"
)
return self.resolved_tu_id
@property
def infra_tu_id(self) -> int:
"""Алиас legacy_tu_id (обратная совместимость)."""
return self.technological_unit.id
@dataclass
class BaseSuiteConfig(SuiteTuIdentityMixin):
"""
Структура:
1. Метаданные набора (имя, id, архив)
2. Технологический участок (из enum TU)
"""
# ===== Метаданные набора =====
ost_name: str
suite_name: str
suite_data_id: int
archive_name: str = "" # Автоматически вычисляется из suite_name
# ===== Технологический участок =====
technological_unit: TU = TU.TIKHORETSK_NOVOROSSIYSK_3
# ===== LDS Configurator (Администрирование) =====
use_lds_configurator: bool = False
admin_tu: Optional[AdminTU] = None
resolved_tu_id: Optional[int] = None
# ===== Название Магистрального Нефтепровода =====
main_pipeline: Optional[str] = None
# ===== Правила конвертации единиц измерения давления на стенде =====
measure_conversion_rules: Optional[MeasureConversionRule] = None
# ===== Общие константы (можно переопределить) =====
allowed_distance_diff_meters: int = BaseTN3Constants.ALLOWED_DISTANCE_DIFF_METERS
precision: int = BaseTN3Constants.PRECISION
basic_message_timeout: float = BaseTN3Constants.BASIC_MESSAGE_TIMEOUT
mask_message_timeout: float = BaseTN3Constants.MASK_MESSAGE_TIMEOUT
mask_du_name: Optional[str] = None
main_pipe_line: Optional[str] = None
mask_du_event: Optional[str] = None
unmask_du_event: Optional[str] = None
def __post_init__(self) -> None:
self.validate_lds_configurator_config()
def validate_lds_configurator_config(self) -> None:
"""Проверяет согласованность полей LDS Configurator в датасете."""
if not self.use_lds_configurator:
return
if self.admin_tu is None:
raise ValueError(f"Набор '{self.suite_name}': admin_tu обязателен при use_lds_configurator=True")
if self.admin_tu.legacy_tu != self.technological_unit:
raise ValueError(
f"Набор '{self.suite_name}': admin_tu.legacy_tu ({self.admin_tu.legacy_tu}) "
f"не совпадает с technological_unit ({self.technological_unit})"
)
# ===== Свойства для удобства =====
@property
def has_multiple_leaks(self) -> bool:
return False
@dataclass
class CaseData:
"""
Данные тест-кейса.
"""
name: str = ""
params: Optional[Dict[str, Any]] = None
expected_result: Optional[Any] = None
description: str = ""
@dataclass
class DiagnosticAreaStatusConfig:
"""
Конфигурация ожидаемых статусов СОУ для диагностического участка.
Используется в тесте lds_status_during_leak.
"""
leak_diagnostic_area_name: str
leak_du_expected_lds_status: Any
neighbors_du_expected_lds_status: Any
leak_diagnostic_area_id: Optional[int] = None
@dataclass
class LeakTestConfig:
"""
Полная конфигурация утечки со всеми параметрами и тест-кейсами.
Все данные для тестов утечки:
- Параметры утечки (координата, объём)
- Временные интервалы
- Ожидаемые значения
- Маркеры тестов (AllLeaksInfo, TuLeaksInfo, и т.д.)
"""
# ===== Идентификаторы =====
control_site_id: Optional[int] = None
diagnostic_area_id: Optional[int] = None
diagnostic_area_name: Optional[str] = None
linear_part_id: Optional[int] = None
technological_object: Optional[str] = None
message_event_leak_completion: Optional[str] = None
# ===== Параметры утечки =====
coordinate_meters: float = None
volume_m3: float = None
max_pumping_m3: int = 2500 # Производительность(максимальная перекачка)
flow_rate_settings_threshold: Optional[float] = None # Порог объема дебаланса для текущего ДУ в текущем режиме
# ===== Временные интервалы (секунды) =====
leak_start_interval_seconds: int = BaseTN3Constants.LEAK_START_INTERVAL
allowed_time_diff_seconds: int = 0 # Допустимое время обнаружения
output_test_delay_seconds: int = BaseTN3Constants.OUTPUT_TEST_DELAY
# ===== Ожидаемые статусы =====
expected_lds_status: Any = LdsStatus.SERVICEABLE
# Режим СОУ в xlsx export_leaks_report (колонка 'Режим работы СОУ')
expected_lds_status_in_leaks_report: Optional[int] = None
expected_report_stationary_status: int = StationaryStatus.STATIONARY.value
expected_stationary_status: Any = StationaryStatus.STATIONARY
expected_algorithm_type: Any = ReservedType.STATIONARY_FLOW
expected_leak_status: Any = ConfirmationStatus.CONFIRMED
expected_complete_leak_status: Any = ConfirmationStatus.CONFIRMED_AND_LEAK_CLOSED
# ===== Конфигурация статусов СОУ во время утечки =====
lds_status_during_leak_config: Optional[DiagnosticAreaStatusConfig] = None
# ===== Данные тест-кейсов =====
lds_status_after_confirming_leak_data: Optional[CaseData] = None
lds_status_after_completed_leak_data: Optional[CaseData] = None
# ===== Тест-кейсы для этой утечки =====
balance_algorithm_leak_waiting_test: Optional[CaseMarkers] = None
balance_algorithm_leak_detected_test: Optional[CaseMarkers] = None
leaks_content_test: Optional[CaseMarkers] = None
all_leaks_info_test: Optional[CaseMarkers] = None
all_leaks_is_empty_test: Optional[CaseMarkers] = None
tu_leaks_info_test: Optional[CaseMarkers] = None
leak_info_in_journal: Optional[CaseMarkers] = None
possible_leak_in_journal_test: Optional[CaseMarkers] = None
acknowledge_leak_test: Optional[CaseMarkers] = None
acknowledge_leak_in_journal_test: Optional[CaseMarkers] = None
output_signals_test: Optional[CaseMarkers] = None
lds_status_during_leak_test: Optional[CaseMarkers] = None
lds_status_after_confirming_leak_test: Optional[CaseMarkers] = None
lds_status_completed_leak_test: Optional[CaseMarkers] = None
the_leak_is_complete_on_kg_test: Optional[CaseMarkers] = None
leak_is_complete_in_output_signals_test: Optional[CaseMarkers] = None
leak_is_complete_on_main_page_test: Optional[CaseMarkers] = None
leak_is_confirm_on_main_page_test: Optional[CaseMarkers] = None
complete_tu_leaks_info_content_test: Optional[CaseMarkers] = None
completed_leak_info_in_journal_test: Optional[CaseMarkers] = None
balance_algorithm_leak_completed_test: Optional[CaseMarkers] = None
export_leaks_report_test: Optional[CaseMarkers] = None
@property
def leak_diagnostic_area_id(self) -> Optional[int]:
"""ID диагностического участка с утечкой из lds_status_during_leak_config"""
if self.lds_status_during_leak_config is not None:
return self.lds_status_during_leak_config.leak_diagnostic_area_id
return None
@property
def allowed_volume_m3(self) -> float:
"""Допустимая погрешность объёма"""
return self.volume_m3 * BaseTN3Constants.ALLOWED_VOLUME_DIFF
@property
def leak_rate_percentages(self) -> float:
"""Интенсивность утечки в процентах"""
return round((self.volume_m3 / self.max_pumping_m3) * 100, 2)
@property
def allowed_time_diff_minutes(self) -> float:
"""Допустимое время обнаружения утечки в минутах"""
return round(self.allowed_time_diff_seconds / 60, 2)
@property
def output_allowed_time_diff_seconds(self) -> int:
"""Допустимое время для теста выходных сигналов"""
return self.allowed_time_diff_seconds + self.output_test_delay_seconds
@dataclass
class SmokeSuiteConfig(BaseSuiteConfig):
"""
Полная конфигурация тестового набора.
Один конфиг = один набор данных = один файл в test_config/datasets/
Структура:
1. Базовые тесты с маркерами
2. Конфигурации утечек (LeakTestConfig)
"""
# ===== Ожидаемый статусы для main_page_info =====
expected_stationary_status: Any = StationaryStatus.STATIONARY
expected_main_page_signals: dict = field(default_factory=lambda: asdict(SignalsInfo()))
# ===== Ожидаемые переменные при маскировании ДУ =====
mask_reason: Optional[str] = None
unmask_reason: Optional[str] = None
mask_one_du: Optional[int] = None
not_mask_du: Optional[int] = None
linear_part_identifier_for_mask: Optional[int] = None
technological_section: Optional[str] = None
imitate_flowmeter_signal_test_data: Optional[CaseData] = None
imitate_pressure_sensor_signal_test_data: Optional[CaseData] = None
exp_mode_mt_message: Optional[CaseData] = None
# Режим МТ в xlsx export_leaks_report
expected_report_stationary_status: int = StationaryStatus.STATIONARY.value
# ===== Данные участков КП-КП =====
controlled_sites_with_segment: Optional[CaseData] = None
# дефолтные значения для датчиков маскирования
mask_signal_test_data: Optional[CaseData] = CaseData(
params={
"pressure_sensor_address": BaseTN3Constants.PRESSURE_SENSOR_ADDRESS,
"flowmeter_address": BaseTN3Constants.FLOWMETER_ADDRESS,
}
)
# ===== Базовые тесты =====
basic_info_test: Optional[CaseMarkers] = None
imitate_flowmeter_signal_test: Optional[CaseMarkers] = None
imitate_pressure_sensor_signal_test: Optional[CaseMarkers] = None
journal_info_test: Optional[CaseMarkers] = None
lds_status_initialization_test: Optional[CaseMarkers] = None
lds_status_init_in_journal_test: Optional[CaseMarkers] = None
main_page_info_test: Optional[CaseMarkers] = None
main_page_info_signals_test: Optional[CaseMarkers] = None
mask_signal_test: Optional[CaseMarkers] = None
mask_info_in_journal_test: Optional[CaseMarkers] = None
lds_status_initialization_out_test: Optional[CaseMarkers] = None
lds_status_init_out_in_journal_test: Optional[CaseMarkers] = None
mask_du_on_mini_scheme_test: Optional[CaseMarkers] = None
unmask_du_on_mini_scheme_test: Optional[CaseMarkers] = None
diagnostics_of_signals_after_initialization_test: Optional[CaseMarkers] = None
mode_mt_in_journal_test: Optional[CaseMarkers] = None
export_lds_status_report_test: Optional[CaseMarkers] = None
export_mt_mode_report_test: Optional[CaseMarkers] = None
# ===== Конфигурации утечек =====
# Для наборов с одной утечкой
leak: Optional[LeakTestConfig] = None
# Для наборов с несколькими утечками (select_19_20)
leaks: list[LeakTestConfig] = field(default_factory=list)
# Участки в xlsx-отчёте о режиме работы СОУ (export_lds_status_report)
lds_status_report_section_names: list[str] = field(default_factory=list)
# ===== Дополнительные тесты для двух утечек =====
main_page_info_unstationary_test: Optional[CaseMarkers] = None
def get_leak(self, index: int = 0) -> Optional[LeakTestConfig]:
"""Получить конфигурацию утечки по индексу"""
if self.leak and index == 0:
return self.leak
if self.leaks and index < len(self.leaks):
return self.leaks[index]
return None
@property
def has_multiple_leaks(self) -> bool:
"""Проверить, есть ли несколько утечек"""
return len(self.leaks) > 1
@property
def allowed_volume_diff(self) -> float:
"""Относительная погрешность по объёму"""
return BaseTN3Constants.ALLOWED_VOLUME_DIFF
@dataclass
class LDSStatusConfig(BaseSuiteConfig):
"""
Полная конфигурация тестового набора.
Один конфиг = один набор данных = один файл в test_config/datasets/
Структура:
1. Данные для тестов(параметры и ожидаемый результат)
2. Тесты с маркерами
"""
# ===== Данные для тестов =====
init_accumulation_data_test_data: Optional[CaseData] = None
init_accumulation_data_in_journal_test_data: Optional[CaseData] = None
init_cold_start_test_data: Optional[CaseData] = None
init_exiting_faulty_test_data: Optional[CaseData] = None
init_switching_shut_off_test_data: Optional[CaseData] = None
init_switching_shut_off_in_journal_test_data: Optional[CaseData] = None
serviceable_all_test_data: Optional[CaseData] = None
serviceable_all_in_journal_test_data: Optional[CaseData] = None
serviceable_after_switching_shut_off_test_data: Optional[CaseData] = None
serviceable_after_switching_shut_off_in_journal_test_data: Optional[CaseData] = None
serviceable_after_deg_faulty_pressure_sensors_at_pump_test_data: Optional[CaseData] = None
serviceable_after_deg_faulty_pressure_sensors_at_pump_in_journal_test_data: Optional[CaseData] = None
deg_faulty_pressure_sensors_at_pump_station_test_data: Optional[CaseData] = None
deg_faulty_pressure_sensors_at_pump_station_in_journal_test_data: Optional[CaseData] = None
deg_additive_injectors_operation_test_data: Optional[CaseData] = None
deg_absence_min_pressure_sensors_test_data: Optional[CaseData] = None
deg_exceeding_distance_between_pressure_sensors_test_data: Optional[CaseData] = None
deg_exceeding_distance_between_pressure_sensors_in_journal_test_data: Optional[CaseData] = None
deg_gravity_section_pumping_test_data: Optional[CaseData] = None
deg_gravity_section_pumping_in_stopping_test_data: Optional[CaseData] = None
deg_gravity_section_pumping_in_stopping_in_journal_test_data: Optional[CaseData] = None
deg_pig_sensor_passage_test_data: Optional[CaseData] = None
deg_starting_pumping_out_pumps_test_data: Optional[CaseData] = None
deg_exceeding_distance_between_flow_meters_test_data: Optional[CaseData] = None
deg_rejection_temperature_sensor_on_du_2_test_data: Optional[CaseData] = None
deg_rejection_temperature_sensor_on_du_3_test_data: Optional[CaseData] = None
deg_rejection_temperature_sensor_on_du_5_test_data: Optional[CaseData] = None
deg_rejection_density_and_viscosity_on_du_2_test_data: Optional[CaseData] = None
deg_rejection_density_and_viscosity_on_du_3_test_data: Optional[CaseData] = None
deg_rejection_density_and_viscosity_on_du_5_test_data: Optional[CaseData] = None
faulty_absence_min_flow_meters_test_data: Optional[CaseData] = None
faulty_absence_min_pressure_sensors_test_data: Optional[CaseData] = None
faulty_absence_min_pressure_sensors_in_journal_test_data: Optional[CaseData] = None
# ===== Тесты =====
lds_status_basic_info_test: Optional[CaseMarkers] = None
init_accumulation_data_test: Optional[CaseMarkers] = None
init_accumulation_data_in_journal_test: Optional[CaseMarkers] = None
init_cold_start_test: Optional[CaseMarkers] = None
init_cold_start_in_journal_test: Optional[CaseMarkers] = None
init_exiting_faulty_test: Optional[CaseMarkers] = None
init_switching_shut_off_test: Optional[CaseMarkers] = None
init_switching_shut_off_in_journal_test: Optional[CaseMarkers] = None
serviceable_after_cold_start_test: Optional[CaseMarkers] = None
serviceable_after_cold_start_in_journal_test: Optional[CaseMarkers] = None
serviceable_after_switching_shut_off_test: Optional[CaseMarkers] = None
serviceable_after_switching_shut_off_in_journal_test: Optional[CaseMarkers] = None
serviceable_after_deg_absence_min_pressure_sensors_test: Optional[CaseMarkers] = None
serviceable_after_deg_additive_injectors_operation_test: Optional[CaseMarkers] = None
serviceable_after_deg_starting_pumping_out_pumps_test: Optional[CaseMarkers] = None
serviceable_after_deg_faulty_pressure_sensors_at_pump_test: Optional[CaseMarkers] = None
serviceable_after_deg_faulty_pressure_sensors_at_pump_in_journal_test: Optional[CaseMarkers] = None
serviceable_after_deg_exceeding_distance_between_flow_meters_test: Optional[CaseMarkers] = None
serviceable_after_faulty_test: Optional[CaseMarkers] = None
deg_additive_injectors_operation_test: Optional[CaseMarkers] = None
deg_exceeding_distance_between_pressure_sensors_test: Optional[CaseMarkers] = None
deg_exceeding_distance_between_pressure_sensors_in_journal_test: Optional[CaseMarkers] = None
deg_absence_min_pressure_sensors_test: Optional[CaseMarkers] = None
deg_faulty_pressure_sensors_at_pump_station_test: Optional[CaseMarkers] = None
deg_faulty_pressure_sensors_at_pump_station_in_journal_test: Optional[CaseMarkers] = None
deg_gravity_section_pumping_test: Optional[CaseMarkers] = None
deg_gravity_section_pumping_in_stopping_test: Optional[CaseMarkers] = None
deg_gravity_section_pumping_in_stopping_in_journal_test: Optional[CaseMarkers] = None
deg_pig_sensor_passage_test: Optional[CaseMarkers] = None
deg_starting_pumping_out_pumps_test: Optional[CaseMarkers] = None
deg_exceeding_distance_between_flow_meters_test: Optional[CaseMarkers] = None
deg_rejection_temperature_sensor_on_du_2_test: Optional[CaseMarkers] = None
deg_rejection_temperature_sensor_on_du_3_test: Optional[CaseMarkers] = None
deg_rejection_temperature_sensor_on_du_5_test: Optional[CaseMarkers] = None
deg_rejection_density_and_viscosity_on_du_2_test: Optional[CaseMarkers] = None
deg_rejection_density_and_viscosity_on_du_3_test: Optional[CaseMarkers] = None
deg_rejection_density_and_viscosity_on_du_5_test: Optional[CaseMarkers] = None
faulty_absence_min_flow_meters_test: Optional[CaseMarkers] = None
faulty_absence_min_flow_meters_continuous_test: Optional[CaseMarkers] = None
faulty_absence_min_pressure_sensors_test: Optional[CaseMarkers] = None
faulty_absence_min_pressure_sensors_in_journal_test: Optional[CaseMarkers] = None
@dataclass
class StationaryStatusConfig(BaseSuiteConfig):
# ===== Данные для тестов =====
stationary_status_with_reason_test_data: Optional[CaseData] = None
stationary_status_journal_test_data: Optional[CaseData] = None
# ===== Тесты =====
stationary_status_basic_info_test: Optional[CaseMarkers] = None
stationary_status_journal_test: Optional[CaseMarkers] = None
stationary_status_common_scheme_test: Optional[CaseMarkers] = None
stationary_status_main_page_info_test: Optional[CaseMarkers] = None
@dataclass
class RejectionTestCase:
"""
Описание одного события отбраковки для тестирования.
Содержит:
- Тег и id датчика (из RejectionSensorTag)
- Ожидаемые значения для проверок журнала и схемы
- Маркеры (offset и test_case_id)
"""
name: str = ""
sensor: RejectionSensorTag = ""
expected_event: str = ""
expected_signal_name: str = ""
expected_criteria_names: Optional[RejectionCriteria] = None
expected_is_rejected: bool = True
time_range_start_s: float = 0
time_range_end_s: float = 0
rejection_input_signals_test: Optional[CaseMarkers] = None
rejection_journal_test: Optional[CaseMarkers] = None
rejection_main_page_test: Optional[CaseMarkers] = None
rejection_scheme_signals_state_test: Optional[CaseMarkers] = None
@dataclass
class RejectionReportRow:
"""Разобранная строка отчёта об отбракованных входных данных."""
row_index: int
datetime_value: Optional[datetime] = None
object_value: str = ""
event_value: str = ""
value_text: str = ""
duration_seconds: int = 0
tag_value: str = ""
@dataclass
class IsRejectedConfig(BaseSuiteConfig):
"""
Конфигурация тестового набора отбраковки сигналов.
Структура:
1. Название МН
2. Список случаев отбраковки (RejectionTestCase)
"""
rejection_cases: list[RejectionTestCase] = field(default_factory=list)
rejection_report_test: Optional[CaseMarkers] = None
@dataclass
class ExportLeaksReportState:
"""
Состояние сценария формирования xlsx-отчёта об утечках между allure-шагами.
Заполняется по ходу export_leaks_report в smoke_scenarios.
"""
report_test: Optional[CaseMarkers] = None
period_start: Optional[datetime] = None
period_end: Optional[datetime] = None
period_start_naive: Optional[datetime] = None
period_end_naive: Optional[datetime] = None
expected_mt_mode: Optional[str] = None
expected_lds_status_text: Optional[str] = None
time_offset_hours: Optional[int] = None
tu_description_lower: str = ""
notification: Optional[ReportDataExportedNotification] = None
report_item: Optional[ExportedDataItem] = None
report_file_name: str = ""
download_invocation_id: Optional[str] = None
download_payload: Optional[list] = None
download_reply: Optional[DownloadExportedDataReply] = None
file_bytes: Optional[bytes] = None
temp_file_path: Optional[Path] = None
worksheet: Any = None
title_info: Optional[ReportTitleInfo] = None
data_rows: list[LeakReportRow] = field(default_factory=list)
target_row: Optional[LeakReportRow] = None
@dataclass
class ExportLdsStatusReportState:
"""Состояние сценария формирования xlsx-отчёта о режиме работы СОУ."""
report_test: Optional[CaseMarkers] = None
period_start: Optional[datetime] = None
period_end: Optional[datetime] = None
period_start_naive: Optional[datetime] = None
period_end_naive: Optional[datetime] = None
time_offset_hours: Optional[int] = None
tu_description_lower: str = ""
notification: Optional[ReportDataExportedNotification] = None
report_item: Optional[ExportedDataItem] = None
report_file_name: str = ""
download_invocation_id: Optional[str] = None
download_reply: Optional[DownloadExportedDataReply] = None
file_bytes: Optional[bytes] = None
temp_file_path: Optional[Path] = None
worksheet: Any = None
parsed_report: Any = None
@dataclass
class ExportRejectedReportState:
"""
Состояние сценария формирования xlsx-отчёта об отбракованных входных данных.
Поля с префиксом expected_ - из конфигурации теста, actual_ - из ответов бэка и разбора xlsx.
"""
# --- expected: конфигурация теста и расчётные ожидания ---
expected_report_test: Optional[CaseMarkers] = None
expected_period_start: Optional[datetime] = None
expected_period_end: Optional[datetime] = None
expected_period_start_naive: Optional[datetime] = None
expected_period_end_naive: Optional[datetime] = None
expected_tu_description_lower: str = ""
expected_file_name: str = ""
# --- actual: ответы бэка ---
actual_time_offset_hours: Optional[int] = None
actual_notification: Optional[ReportDataExportedNotification] = None
actual_report_item: Optional[ExportedDataItem] = None
actual_download_invocation_id: Optional[str] = None
actual_download_reply: Optional[DownloadExportedDataReply] = None
actual_file_bytes: Optional[bytes] = None
# --- actual: разбор xlsx ---
actual_temp_file_path: Optional[Path] = None
actual_worksheet: Any = None
actual_title_info: Optional[ReportTitleInfo] = None
actual_data_rows: list[RejectionReportRow] = field(default_factory=list)
actual_monitored_tag_rows: list[RejectionReportRow] = field(default_factory=list)
actual_header_column_headers: list[str] = field(default_factory=list)
actual_header_period_start: Optional[datetime] = None
actual_header_period_end: Optional[datetime] = None
actual_header_contains_expected_title: bool = False
actual_case_checks: list = field(default_factory=list)
@dataclass
class ExportMtModeReportState:
"""
Состояние сценария формирования xlsx-отчёта о режиме работы МТ.
Поля с префиксом expected_ - из конфигурации теста, actual_ - из ответов бэка и разбора xlsx.
"""
# --- expected: конфигурация теста и расчётные ожидания ---
expected_report_test: Optional[CaseMarkers] = None
expected_period_start: Optional[datetime] = None
expected_period_end: Optional[datetime] = None
expected_period_start_naive: Optional[datetime] = None
expected_period_end_naive: Optional[datetime] = None
expected_tu_description_lower: str = ""
expected_file_name: str = ""
expected_section_names: list[str] = field(default_factory=list)
expected_dominant_mode_column: str = ""
# --- actual: ответы бэка ---
actual_time_offset_hours: Optional[int] = None
actual_notification: Optional[ReportDataExportedNotification] = None
actual_report_item: Optional[ExportedDataItem] = None
actual_download_invocation_id: Optional[str] = None
actual_download_reply: Optional[DownloadExportedDataReply] = None
actual_file_bytes: Optional[bytes] = None
# --- actual: разбор xlsx ---
actual_temp_file_path: Optional[Path] = None
actual_worksheet: Any = None
actual_parsed_report: Any = None
lds_status_scenarios
"""
Сценарии тестов по режимам СОУ - функции-обёртки без pytest маркеров.
Каждая функция содержит логику одного теста.
Pytest маркеры и allure декораторы применяются в тестовых файлах.
"""
import time
from datetime import datetime
import allure
from constants.architecture_constants import HTTPClientConstants as HttpConst
from constants.enums import Direction, LdsStatus, MessageType, ReplyStatus, 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 CaseData, LDSStatusConfig, SmokeSuiteConfig
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
async def lds_status_check_on_longest_flow_area(ws_client, cfg: LDSStatusConfig, test_data: CaseData):
"""
Проверка Инициализации и причины инициализации СОУ на самом протяженном участке карты течений
"""
# Распаковка данных для теста
expected_lds_status, expected_lds_status_reasons = test_data.expected_result
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 = getattr(parsed_payload.replyContent, 'flowAreas', [])
# Получает самый протяженный участок карты течения
longest_flow_area = t_utils.get_longest_flow_area(flow_areas)
# Получает список ДУ
diagnostic_areas = getattr(longest_flow_area, 'diagnosticAreas', [])
StepCheck("Проверка наличия данных диагностических участков", "diagnosticAreas").actual(
diagnostic_areas
).is_not_empty()
for diagnostic_area in diagnostic_areas:
diagnostic_area_lds_status = LdsStatus(diagnostic_area.ldsStatus) if diagnostic_area.ldsStatus else None
StepCheck(f"Проверка режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatus").actual(
diagnostic_area_lds_status
).expected(expected_lds_status).equal_to()
lds_status_reasons = t_utils.parse_lds_status_reasons(
diagnostic_area.ldsStatus, diagnostic_area.ldsStatusReasons
)
StepCheck(f"Проверка причины режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatusReasons").contains(
lds_status_reasons, expected_lds_status_reasons
)
async def lds_status_check_with_reasons(ws_client, cfg: SmokeSuiteConfig | LDSStatusConfig, test_data: CaseData):
"""
Проверка режима работы и причины режима СОУ на заданном ДУ
"""
# Распаковка данных для теста
pipe_id = test_data.params.get("pipe_id")
expected_lds_status, expected_lds_status_reasons = test_data.expected_result
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 = getattr(parsed_payload.replyContent, 'flowAreas', [])
# Получает ДУ
diagnostic_area = t_utils.find_diagnostic_area_by_pipe_id(flow_areas, pipe_id)
StepCheck("Проверка наличия данных диагностического участка", "diagnosticAreas").actual(
diagnostic_area
).is_not_none()
diagnostic_area_lds_status = LdsStatus(diagnostic_area.ldsStatus) if diagnostic_area.ldsStatus else None
StepCheck(f"Проверка режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatus").actual(
diagnostic_area_lds_status
).expected(expected_lds_status).equal_to()
if diagnostic_area_lds_status != LdsStatus.SERVICEABLE:
lds_status_reasons = t_utils.parse_lds_status_reasons(
diagnostic_area.ldsStatus, diagnostic_area.ldsStatusReasons
)
StepCheck(f"Проверка причины режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatusReasons").contains(
lds_status_reasons, expected_lds_status_reasons
)
async def lds_status_check_with_2_reasons(ws_client, cfg: SmokeSuiteConfig | LDSStatusConfig, test_data: CaseData):
"""
Проверка режима работы СОУ и двух причин режима работы СОУ на заданном ДУ
"""
# Распаковка данных для теста
pipe_id = test_data.params.get("pipe_id")
expected_lds_status, expected_lds_status_reason_1, expected_lds_status_reason_2 = test_data.expected_result
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 = getattr(parsed_payload.replyContent, 'flowAreas', [])
# Получает ДУ
diagnostic_area = t_utils.find_diagnostic_area_by_pipe_id(flow_areas, pipe_id)
StepCheck("Проверка наличия данных диагностического участка", "diagnosticAreas").actual(
diagnostic_area
).is_not_none()
diagnostic_area_lds_status = LdsStatus(diagnostic_area.ldsStatus) if diagnostic_area.ldsStatus else None
StepCheck(f"Проверка режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatus").actual(
diagnostic_area_lds_status
).expected(expected_lds_status).equal_to()
if diagnostic_area_lds_status != LdsStatus.SERVICEABLE:
with SoftAssertions() as soft_failures:
lds_status_reasons = t_utils.parse_lds_status_reasons(
diagnostic_area.ldsStatus, diagnostic_area.ldsStatusReasons, soft_failures
)
StepCheck(
f"Проверка причины режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatusReasons", soft_failures
).contains(lds_status_reasons, expected_lds_status_reason_1)
StepCheck(
f"Проверка причины режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatusReasons", soft_failures
).contains(lds_status_reasons, expected_lds_status_reason_2)
async def lds_status_check_on_multiple_diagnostic_areas(
ws_client, cfg: SmokeSuiteConfig | LDSStatusConfig, test_data: CaseData
):
"""
Проверка режима работы и причины режима СОУ на заданных ДУ
"""
# Распаковка данных для теста
pipe_ids = test_data.params.get("pipe_ids")
expected_result = test_data.expected_result
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 = getattr(parsed_payload.replyContent, 'flowAreas', [])
diagnostic_areas = t_utils.find_diagnostic_areas_by_pipe_ids(flow_areas, pipe_ids)
StepCheck("Проверка наличия данных диагностических участков", "diagnosticAreas").actual(
diagnostic_areas
).is_not_empty()
lds_status_set = {diagnostic_area.ldsStatus for diagnostic_area in diagnostic_areas}
lds_status_int = t_utils.determine_lds_status_by_priority(lds_status_set)
lds_status = LdsStatus(lds_status_int) if lds_status_int else None
StepCheck(
"Проверка режима работы СОУ на заданных ДУ",
"ldsStatus",
).actual(
lds_status
).expected(expected_result).equal_to()
async def lds_and_stationary_status_check_with_reasons(
ws_client, cfg: SmokeSuiteConfig | LDSStatusConfig, test_data: CaseData
):
"""
Проверка режима работы и причины режима СОУ и МТ на заданном ДУ
"""
# Распаковка данных для теста
pipe_id = test_data.params.get("pipe_id")
(
expected_lds_status,
expected_lds_status_reasons,
expected_stationary_status,
expected_stationary_status_reasons,
) = test_data.expected_result
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 = getattr(parsed_payload.replyContent, 'flowAreas', [])
# Получает ДУ
diagnostic_area = t_utils.find_diagnostic_area_by_pipe_id(flow_areas, pipe_id)
StepCheck("Проверка наличия данных диагностического участка", "diagnosticAreas").actual(
diagnostic_area
).is_not_none()
diagnostic_area_lds_status = LdsStatus(diagnostic_area.ldsStatus) if diagnostic_area.ldsStatus else None
diagnostic_area_stationary_status = (
StationaryStatus(diagnostic_area.stationaryStatus) if diagnostic_area.stationaryStatus else None
)
StepCheck(f"Проверка режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatus").actual(
diagnostic_area_lds_status
).expected(expected_lds_status).equal_to()
StepCheck(f"Проверка режима работы МТ на ДУ с id:{diagnostic_area.id}", "stationaryStatus").actual(
diagnostic_area_stationary_status
).expected(expected_stationary_status).equal_to()
with SoftAssertions() as soft_failures:
lds_status_reasons = t_utils.parse_lds_status_reasons(
diagnostic_area.ldsStatus, diagnostic_area.ldsStatusReasons, soft_failures
)
stationary_status_reasons = t_utils.parse_stationary_status_reasons(
diagnostic_area.stationaryStatus, diagnostic_area.stationaryStatusReasons, soft_failures
)
StepCheck(
f"Проверка причины режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatusReasons", soft_failures
).contains(lds_status_reasons, expected_lds_status_reasons)
StepCheck(
f"Проверка причины режима работы МТ на ДУ с id:{diagnostic_area.id}",
"stationaryStatusReasons",
soft_failures,
).contains(stationary_status_reasons, expected_stationary_status_reasons)
async def lds_status_check_degradation_pig_sensor_passage(
ws_client, http_client, cfg: SmokeSuiteConfig | LDSStatusConfig, test_data: CaseData
):
"""
Проверка режима работы и причины режима СОУ на заданном ДУ, с командой на включение СОД
"""
# Распаковка данных для теста
pipe_id = test_data.params.get("pipe_id")
pig_trap_id = test_data.params.get("pig_trap_id")
expected_lds_status, expected_lds_status_reasons = test_data.expected_result
with allure.step("Http запрос, получение и обработка ответа о запуске СОД: LaunchPigRequest"):
request_body = {'pigTrapId': pig_trap_id, 'timeToLaunch': 0, 'tuId': cfg.tu_id}
response = http_client.post_request(HttpConst.LAUNCH_PIG_URL_PATH, request_body)
launch_pig_reply_status = response.status_code
StepCheck("Проверка кода ответа на запрос о запуске СОД", "replyStatus").actual(
launch_pig_reply_status
).expected(ReplyStatus.OK.value).equal_to()
time.sleep(cfg.basic_message_timeout)
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 = getattr(parsed_payload.replyContent, 'flowAreas', [])
# Получает ДУ
diagnostic_area = t_utils.find_diagnostic_area_by_pipe_id(flow_areas, pipe_id)
StepCheck("Проверка наличия данных диагностического участка", "diagnosticAreas").actual(
diagnostic_area
).is_not_none()
diagnostic_area_lds_status = LdsStatus(diagnostic_area.ldsStatus) if diagnostic_area.ldsStatus else None
StepCheck(f"Проверка режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatus").actual(
diagnostic_area_lds_status
).expected(expected_lds_status).equal_to()
lds_status_reasons = t_utils.parse_lds_status_reasons(diagnostic_area.ldsStatus, diagnostic_area.ldsStatusReasons)
StepCheck(f"Проверка причины режима работы СОУ на ДУ с id:{diagnostic_area.id}", "ldsStatusReasons").contains(
lds_status_reasons, expected_lds_status_reasons
)
def lds_status_in_journal(http_client, cfg: LDSStatusConfig, test_data: CaseData):
"""
Проверка наличия записи в журнале о выходе СОУ из режима Инициализация.
"""
# Распаковка данных для теста
control_points = test_data.params.get("control_points")
if isinstance(test_data.expected_result, tuple):
expected_lds_status, expected_lds_status_reasons = test_data.expected_result
else:
expected_lds_status, expected_lds_status_reasons = test_data.expected_result, None
with allure.step("Http запрос сообщений журнала с фильтром messageTypes=MASKING_LDS"):
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.LDS_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)
lds_msg_by_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:
lds_msg = next(
(msg for msg in time_filtered if msg.controlPoint == control_point),
None,
)
if lds_msg:
lds_msg_by_control_points.append(lds_msg)
StepCheck(
f"Проверка наличия сообщений c controlPoint из списка {control_points} в журнале", "messagesInfo"
).actual(lds_msg_by_control_points).is_not_empty()
with SoftAssertions() as soft_failures:
for msg in lds_msg_by_control_points:
msg_event = getattr(msg, 'event', None)
cp_lds_status, cp_lds_status_reasons = t_utils.parse_event(msg_event)
StepCheck(f"Проверка режима работы СОУ на КП:{msg.controlPoint}", "event", soft_failures).actual(
cp_lds_status
).expected(expected_lds_status).equal_to()
if cp_lds_status != LdsStatus.SERVICEABLE.report_text:
StepCheck(
f"Проверка причины режима работы СОУ на КП:{msg.controlPoint}", "event", soft_failures
).contains(cp_lds_status_reasons, expected_lds_status_reasons)