"""UA 플랫폼 보정 테스트 — 네이버가 리눅스 데스크톱 Chrome 을 405 로 거부하는 문제 대응. 여기서 지키는 계약: - 리눅스에서만 보정한다(맥·윈도우는 이미 통과 — 굳이 위장하면 나머지 지문과 어긋나 오히려 튄다) - **버전은 실제 Chrome 값**을 쓴다(하드코딩하면 업데이트 시 불일치가 새 신호가 된다) - 조회 실패해도 크롤을 막지 않는다 """ from services.search import user_agent as ua_mod from services.search.user_agent import mac_ua, needs_mac_ua, parse_major, resolve_ua def test_only_linux_gets_the_override(): """맥·윈도우를 위장하면 UA 와 실제 플랫폼 지문이 어긋나 오히려 봇 신호가 된다.""" assert needs_mac_ua("linux") is True assert needs_mac_ua("darwin") is False assert needs_mac_ua("win32") is False def test_resolve_returns_none_off_linux(): assert resolve_ua("/opt/google/chrome/chrome", platform="darwin") is None assert resolve_ua(None, platform="win32") is None def test_resolve_on_linux_produces_a_mac_ua(monkeypatch): monkeypatch.setattr(ua_mod, "chrome_major", lambda _exe: "150") ua = resolve_ua("/opt/google/chrome/chrome", platform="linux") assert "Macintosh; Intel Mac OS X" in ua assert "Linux" not in ua and "X11" not in ua def test_ua_keeps_the_real_chrome_major(monkeypatch): """UA 버전이 실제 엔진과 어긋나면 그 불일치가 새로운 지문이 된다.""" monkeypatch.setattr(ua_mod, "chrome_major", lambda _exe: "150") assert "Chrome/150.0.0.0" in resolve_ua("/x", platform="linux") monkeypatch.setattr(ua_mod, "chrome_major", lambda _exe: "151") assert "Chrome/151.0.0.0" in resolve_ua("/x", platform="linux") def test_ua_shape_matches_real_chrome(): """형식이 어긋나면 그 자체로 탐지된다 — 실제 Chrome 의 reduced UA 형태를 지킨다.""" ua = mac_ua("150") assert ua.startswith("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)") assert "AppleWebKit/537.36 (KHTML, like Gecko)" in ua assert ua.endswith("Safari/537.36") def test_parse_major_from_chrome_version_output(): assert parse_major("Google Chrome 150.0.7258.66 ") == "150" assert parse_major("Chromium 138.0.7204.100") == "138" assert parse_major("") is None assert parse_major("no version here") is None def test_version_lookup_failure_still_yields_a_valid_ua(monkeypatch): """--version 조회가 실패해도 크롤이 멈추면 안 된다 — 형식이 온전한 UA 를 낸다.""" monkeypatch.setattr(ua_mod.subprocess, "run", lambda *a, **k: (_ for _ in ()).throw(OSError("no chrome"))) ua_mod.chrome_major.cache_clear() ua = resolve_ua("/nonexistent", platform="linux") assert "Macintosh" in ua and "Chrome/" in ua ua_mod.chrome_major.cache_clear() def test_naver_opts_in_and_coupang_does_not(): """UA 보정은 네이버만 켠다 — 쿠팡은 지금 잘 통과하므로 건드리지 않는다.""" from services.search.coupang.adapter import CoupangAdapter from services.search.naver_shop.adapter import NaverShopAdapter assert NaverShopAdapter.mac_ua_on_linux is True assert CoupangAdapter.mac_ua_on_linux is False