Загрузка данных




async def lds_status_in_journal(ws_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("Запрос сообщений журнала с фильтром messageTypes=LDS_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.LDS_STATUS), objects=FilteringObjects(tuId=cfg.tu_id)),
        )
        payload = await t_utils.connect_and_get_msg(ws_client, "GetMessagesRequest", request_body)
        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,
            )
            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(
                    "Проверка причины режима работы СОУ на КП:{msg.controlPoint}", "event", soft_failures
                ).contains(cp_lds_status_reasons, expected_lds_status_reasons)










def parse_event(event_value: str) -> tuple[str | None, str | None]:
    """
    Разделяет строку события на имя и причину, вложенную в скобки
    """
    if not event_value:
        return None, None

    # Поиск открывающей скобки
    open_idx = event_value.find('(')
    if open_idx == -1:
        return event_value.strip(), None

    # Поиск закрывающей скобки ПОСЛЕ открывающей
    close_idx = event_value.find(')', open_idx + 1)
    if close_idx == -1:
        return event_value.strip(), None

    mode_part = event_value[:open_idx].strip()
    reason_part = event_value[open_idx + 1 : close_idx].strip()  # noqa: E203
    return mode_part, reason_part




    @pytest.mark.asyncio
    async def test_lds_status_init_accumulation_data_in_journal(
        self, ws_client: WebSocketClient, config: LDSStatusConfig, imitator_start_time: datetime
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Инициализация,
        Причина: Накопление данных
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: "
            "'Инициализация', по причине: 'Накопление данных'. ЭФ: Журнал. Реальное время"
        )
        _apply_allure_markers(
            config.init_accumulation_data_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                f"Время проведения проверки : {config.init_accumulation_data_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Инициализация\n Ожидаемая причина режима работы СОУ: Накопление данных"
            ),
        )
        test_data = config.init_accumulation_data_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_init_cold_start_in_journal(
        self, ws_client: WebSocketClient, config: LDSStatusConfig, imitator_start_time: datetime
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Инициализация,
        Причина: Холодный пуск
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: "
            "'Инициализация', по причине: 'Холодный пуск'. ЭФ: Журнал. Реальное время"
        )
        _apply_allure_markers(
            config.init_cold_start_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                f"Время проведения проверки : {config.init_cold_start_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Инициализация\n Ожидаемая причина режима работы СОУ: Холодный пуск"
            ),
        )
        await smoke_scenarios.lds_status_init_in_journal(ws_client, config, imitator_start_time)

    @pytest.mark.asyncio
    async def test_lds_status_init_switching_shut_off_in_journal(
        self, ws_client: WebSocketClient, config: LDSStatusConfig
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Инициализация,
        Причина: Переключение запорной арматуры
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: "
            "'Инициализация', по причине: 'Переключение запорной арматуры'. ЭФ: Журнал. Реальное время"
        )
        _apply_allure_markers(
            config.init_switching_shut_off_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.init_switching_shut_off_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Инициализация\n "
                "Ожидаемая причина режима работы СОУ: Переключение запорной арматуры"
            ),
        )
        test_data = config.init_switching_shut_off_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_serviceable_after_cold_start_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Исправна.
        Установка режима Исправна после Инициализации, по причине Холодный пуск.
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: "
            "'Исправна', после Инициализации. ЭФ: Журнал. Реальное время"
        )

        _apply_allure_markers(
            config.serviceable_after_cold_start_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.serviceable_after_cold_start_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Исправна\n"
            ),
        )
        test_data = config.serviceable_all_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_serviceable_after_switching_shut_off_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Исправна.
        Установка режима Исправна после Инициализации, по причине Переключение запорной арматуры.
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: "
            "'Исправна', после Инициализации. ЭФ: Журнал. Реальное время"
        )

        _apply_allure_markers(
            config.serviceable_after_switching_shut_off_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.serviceable_after_switching_shut_off_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Исправна\n"
            ),
        )
        test_data = config.serviceable_all_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_serviceable_after_deg_faulty_pressure_sensors_at_pump_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Исправна.
        Установка режима Исправна после режима Ухудшение характеристик.
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: "
            "'Исправна', после режима Ухудшение характеристик. ЭФ: Журнал. Реальное время"
        )

        _apply_allure_markers(
            config.serviceable_after_deg_faulty_pressure_sensors_at_pump_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.serviceable_after_deg_faulty_pressure_sensors_at_pump_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Исправна\n"
            ),
        )
        test_data = config.serviceable_all_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_degradation_gravity_section_pumping_in_stopping_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Ухудшение характеристик
        Причина: Наличие самотечного участка в режиме остановленной перекачки
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: 'Ухудшение характеристик', "
            "по причине: 'Наличие самотечного участка в режиме остановленной перекачки'"
        )

        _apply_allure_markers(
            config.deg_gravity_section_pumping_in_stopping_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.deg_gravity_section_pumping_in_stopping_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Ухудшение характеристик\n "
                "Ожидаемая причина режима работы СОУ: Наличие самотечного участка в режиме остановленной перекачки "
            ),
        )
        test_data = config.deg_gravity_section_pumping_in_stopping_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_degradation_exceeding_distance_between_pressure_sensors_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Ухудшение характеристик
        Причина: расстояние между СИ давления более 50 км
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: 'Ухудшение характеристик', "
            "по причине: 'Расстояние между СИ давления более 50 км'"
        )

        _apply_allure_markers(
            config.deg_exceeding_distance_between_pressure_sensors_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.deg_exceeding_distance_between_pressure_sensors_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Ухудшение характеристик\n "
                "Ожидаемая причина режима работы СОУ: Расстояние между СИ давления более 50 км "
            ),
        )
        test_data = config.deg_exceeding_distance_between_pressure_sensors_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_degradation_faulty_pressure_sensors_at_pump_station_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Ухудшение характеристик
        Причина: Отказ СИ давления на входе/выходе НПС
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: 'Ухудшение характеристик', "
            "по причине: 'Отказ СИ давления на входе/выходе НПС'"
        )

        _apply_allure_markers(
            config.deg_faulty_pressure_sensors_at_pump_station_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.deg_faulty_pressure_sensors_at_pump_station_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Ухудшение характеристик\n "
                "Ожидаемая причина режима работы СОУ: Отказ СИ давления на входе/выходе НПС "
            ),
        )
        test_data = config.deg_faulty_pressure_sensors_at_pump_station_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)

    @pytest.mark.asyncio
    async def test_lds_status_faulty_absence_min_pressure_sensors_in_journal(
        self,
        ws_client: WebSocketClient,
        config: LDSStatusConfig,
    ) -> None:
        """
        [MessagesInfo] Проверка режима работы СОУ в журнале: Неисправна
        Причина: Менее 4 КП с достоверными СИ давления
        """
        tag = "MessagesInfo"
        title = (
            f"[{tag}] Проверка записи в журнале о режиме работы СОУ: 'Неисправна', "
            "по причине: 'Менее 4 КП с достоверными СИ давления'"
        )

        _apply_allure_markers(
            config.faulty_absence_min_pressure_sensors_in_journal_test,
            tag,
            title,
            (
                f"Проверка записи в журнале о режиме работы СОУ, на наборе данных {config.suite_name}, \n"
                f"на технологическом участке {config.technological_unit.description}\n"
                "Время проведения проверки : "
                f"{config.faulty_absence_min_pressure_sensors_in_journal_test.offset} мин.\n"
                "Синхронный запрос типа: MessagesInfo с фильтром messageTypes=LDS_STATUS\n"
                "Ожидаемый режим работы СОУ: Неисправна\n "
                "Ожидаемая причина режима работы СОУ: Менее 4 КП с достоверными СИ давления "
            ),
        )
        test_data = config.faulty_absence_min_pressure_sensors_in_journal_test_data
        await scenarios.lds_status_in_journal(ws_client, config, test_data)