diff --git a/tradein-mvp/backend/tests/services/test_proxy_egress.py b/tradein-mvp/backend/tests/services/test_proxy_egress.py index b123bb9c..a82d28e2 100644 --- a/tradein-mvp/backend/tests/services/test_proxy_egress.py +++ b/tradein-mvp/backend/tests/services/test_proxy_egress.py @@ -420,8 +420,10 @@ def test_all_candidates_banned_raises_pool_exhausted_not_env_fallback( assert exc_info.value.pool_total == 2 assert exc_info.value.banned_for_source == 2 assert exc_info.value.unhealthy_or_disabled == 0 - errors = [rec for rec in caplog.records if rec.levelname == "ERROR"] - assert any("fail-closed" in rec.message.lower() for rec in errors) + # fail-closed без здорового узла — штатный исход скрапинга, а не инцидент; + # понижено до warning, чтобы не шуметь в GlitchTip (было logger.error). + warnings = [rec for rec in caplog.records if rec.levelname == "WARNING"] + assert any("fail-closed" in rec.message.lower() for rec in warnings) # НЕ должно быть "обход пула" / "static-fallback" в логах — env не тронут. assert not any("static-fallback" in rec.message for rec in caplog.records) @@ -429,8 +431,10 @@ def test_all_candidates_banned_raises_pool_exhausted_not_env_fallback( def test_exhausted_and_empty_pool_log_texts_are_distinct( monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture ) -> None: - """Регрессия на замечание ревью: "пуст" и "все отсеяны" — РАЗНЫЕ формулировки И - разные уровни (WARNING vs ERROR), иначе их нельзя различить в логах/алертах.""" + """Регрессия на замечание ревью: "пуст" и "все отсеяны" — РАЗНЫЕ формулировки, + иначе их нельзя различить в логах/алертах. Оба сценария — штатный исход + скрапинга, поэтому оба теперь warning (было WARNING vs ERROR), различимость + держится на тексте, не на уровне.""" now = datetime.now(UTC) with caplog.at_level("WARNING"): @@ -452,8 +456,8 @@ def test_exhausted_and_empty_pool_log_texts_are_distinct( exhausted_messages = {rec.levelname: rec.message for rec in caplog.records} assert "ERROR" not in empty_pool_messages - assert "ERROR" in exhausted_messages - assert empty_pool_messages.get("WARNING") != exhausted_messages.get("ERROR") + assert "ERROR" not in exhausted_messages + assert empty_pool_messages.get("WARNING") != exhausted_messages.get("WARNING") def test_disabled_proxy_raises_pool_exhausted() -> None: diff --git a/tradein-mvp/backend/tests/tasks/test_avito_detail_backfill.py b/tradein-mvp/backend/tests/tasks/test_avito_detail_backfill.py index 3a40aed6..9e963679 100644 --- a/tradein-mvp/backend/tests/tasks/test_avito_detail_backfill.py +++ b/tradein-mvp/backend/tests/tasks/test_avito_detail_backfill.py @@ -348,7 +348,9 @@ async def test_backfill_abort_log_has_no_ip_rate_limited_literal(caplog: Any) -> patch(_RESOLVE_PROXY_URL, MagicMock(return_value="http://test-proxy.local:8080")), patch(_FETCH, mock_fetch), patch(_SLEEP, new_callable=AsyncMock), - caplog.at_level("ERROR"), + # серия подтверждённых блоков площадки -- штатный исход скрапинга, не + # инцидент; понижено до warning, чтобы не шуметь в GlitchTip. + caplog.at_level("WARNING"), ): await run_avito_detail_backfill( db, run_id=3, params={"batch_size": 10, "budget_sec": 3600, "max_consecutive_blocks": 5} @@ -1354,7 +1356,9 @@ async def test_backfill_ratio_abort_log_names_the_ratio_not_the_streak(caplog: A patch(_FETCH, mock_fetch), patch(_SAVE, return_value=True), patch(_SLEEP, new_callable=AsyncMock), - caplog.at_level("ERROR"), + # ABORT по доле блоков -- штатный исход скрапинга, не инцидент; понижено + # до warning, чтобы не шуметь в GlitchTip. + caplog.at_level("WARNING"), ): result = await run_avito_detail_backfill( db, run_id=110, params={"batch_size": total, "budget_sec": 3600} @@ -1396,7 +1400,9 @@ async def test_backfill_safety_net_abort_log_names_the_streak(caplog: Any) -> No patch(_FETCH, mock_fetch), patch(_SAVE, return_value=True), patch(_SLEEP, new_callable=AsyncMock), - caplog.at_level("ERROR"), + # ABORT по safety-net серии -- штатный исход скрапинга, не инцидент; + # понижено до warning, чтобы не шуметь в GlitchTip. + caplog.at_level("WARNING"), ): result = await run_avito_detail_backfill( db, run_id=111, params={"batch_size": total, "budget_sec": 3600} diff --git a/tradein-mvp/backend/tests/tasks/test_domclick_detail_backfill.py b/tradein-mvp/backend/tests/tasks/test_domclick_detail_backfill.py index dc68ad7c..0e100ecc 100644 --- a/tradein-mvp/backend/tests/tasks/test_domclick_detail_backfill.py +++ b/tradein-mvp/backend/tests/tasks/test_domclick_detail_backfill.py @@ -287,7 +287,9 @@ async def test_backfill_abort_log_has_no_qrator_literal(caplog: pytest.LogCaptur patch(_BROWSER_FETCHER, mock_bf_cls), patch(_FETCH, mock_fetch), patch(_SLEEP, new_callable=AsyncMock), - caplog.at_level("ERROR"), + # серия подтверждённых блоков площадки -- штатный исход скрапинга, не + # инцидент; понижено до warning, чтобы не шуметь в GlitchTip. + caplog.at_level("WARNING"), ): await run_domclick_detail_backfill( db, diff --git a/tradein-mvp/backend/tests/test_cian_session.py b/tradein-mvp/backend/tests/test_cian_session.py index 9f293e17..d1c07414 100644 --- a/tradein-mvp/backend/tests/test_cian_session.py +++ b/tradein-mvp/backend/tests/test_cian_session.py @@ -446,8 +446,9 @@ async def test_verify_session_pool_exhausted_returns_source_unavailable_with_err ) -> None: """#2825 fail-closed (#2616): пул scrape_proxies исчерпан для cian (все узлы забанены/нездоровы) — session.get НЕ вызывается (никуда не ходим без egress), - возвращается VERIFY_SOURCE_UNAVAILABLE_SENTINEL, но с ERROR-логом (не warning, - отдельным от обычного network-error пути) — явная деградация, а не проглатывание.""" + возвращается VERIFY_SOURCE_UNAVAILABLE_SENTINEL, с явным логом (не тихое + проглатывание). Штатный исход скрапинга -- warning, не error (было error; + понижено, чтобы не шуметь в GlitchTip).""" from app.services.proxy_egress import ProxyPoolExhaustedError def _raise(source: str) -> str | None: @@ -470,8 +471,8 @@ async def test_verify_session_pool_exhausted_returns_source_unavailable_with_err assert result is VERIFY_SOURCE_UNAVAILABLE_SENTINEL mock_session.get.assert_not_called() - errors = [rec for rec in caplog.records if rec.levelname == "ERROR"] - assert any("пул прокси исчерпан" in rec.message.lower() for rec in errors) + warnings = [rec for rec in caplog.records if rec.levelname == "WARNING"] + assert any("пул прокси исчерпан" in rec.message.lower() for rec in warnings) @pytest.mark.asyncio