This commit is contained in:
@@ -278,6 +278,80 @@ try:
|
||||
except ImportError:
|
||||
print("SKIP emit tests (PyYAML not installed)")
|
||||
|
||||
# ── txid indices deep scan ──
|
||||
# X が 2026-07 に未ログインページを x-web SSR 化し、indices ファイル (sign.o-*.js) が
|
||||
# entry チャンクの動的 import 先 (assets/*.js) に移った。twscrape 0.19.1 はページ直下の
|
||||
# スクリプトしか走査しないため到達できない。以下はもう 1 ホップ潜る実装のテスト。
|
||||
|
||||
ENTRY = "https://abs.twimg.com/x-web/x-web/entry-client-logged-out-B9F1BBbe.js"
|
||||
|
||||
check("chunkrefs: resolves ./assets relative to entry",
|
||||
"https://abs.twimg.com/x-web/x-web/assets/a-1234.js"
|
||||
in xa.collect_chunk_refs('import("./assets/a-1234.js")', ENTRY))
|
||||
check("chunkrefs: resolves parent-relative",
|
||||
"https://abs.twimg.com/x-web/messages/ja.js"
|
||||
in xa.collect_chunk_refs('x="../messages/ja.js"', ENTRY))
|
||||
check("chunkrefs: assets sorted ahead of non-assets",
|
||||
xa.collect_chunk_refs('"../messages/ja.js";"./assets/z-9.js"', ENTRY)[0].endswith("/assets/z-9.js"))
|
||||
check("chunkrefs: dedupes",
|
||||
len(xa.collect_chunk_refs('"./assets/a-1.js" "./assets/a-1.js"', ENTRY)) == 1)
|
||||
check("chunkrefs: ignores absolute cross-origin",
|
||||
xa.collect_chunk_refs('"https://evil.example/x.js"', ENTRY) == [])
|
||||
check("chunkrefs: caps fan-out",
|
||||
len(xa.collect_chunk_refs(" ".join(f'"./assets/c-{i}.js"' for i in range(500)), ENTRY))
|
||||
<= xa.CHUNK_SCAN_CAP)
|
||||
|
||||
|
||||
class _FakeClient:
|
||||
"""twscrape の HttpClient 代替。get(url).text を返すだけ。"""
|
||||
|
||||
def __init__(self, bodies):
|
||||
self.bodies = bodies
|
||||
self.fetched = []
|
||||
|
||||
async def get(self, url):
|
||||
self.fetched.append(url)
|
||||
return types.SimpleNamespace(text=self.bodies.get(url, ""))
|
||||
|
||||
|
||||
def _run(coro):
|
||||
import asyncio
|
||||
return asyncio.run(coro)
|
||||
|
||||
|
||||
SIGN_O = "https://abs.twimg.com/x-web/x-web/assets/sign.o-BS4wvWaM.js"
|
||||
SUB = "https://abs.twimg.com/x-web/x-web/assets/sentry-filter-CAS6J6cR.js"
|
||||
|
||||
# 1 段目に直接ある場合 (旧 = 上流と同じ挙動) は 1 ホップで返す。
|
||||
# entry と同じ階層で解決されるので assets/ は挟まらない。
|
||||
c = _FakeClient({ENTRY: 'import("./sign.o-BS4wvWaM.js")'})
|
||||
check("deepscan: level-1 hit",
|
||||
_run(xa.find_indices_url_deep([ENTRY], c))
|
||||
== "https://abs.twimg.com/x-web/x-web/sign.o-BS4wvWaM.js")
|
||||
|
||||
# 2 段目 (今回の実際の構造): entry -> assets/sentry-filter -> sign.o
|
||||
c = _FakeClient({ENTRY: 'import("./assets/sentry-filter-CAS6J6cR.js")',
|
||||
SUB: 'import("./sign.o-BS4wvWaM.js")'})
|
||||
check("deepscan: level-2 hit",
|
||||
_run(xa.find_indices_url_deep([ENTRY], c)) == SIGN_O)
|
||||
|
||||
# どこにも無ければ例外を上げ、txid 失敗を記録する (静かな空振りにしない)
|
||||
xa.TXID_STATE["failed"] = False
|
||||
c = _FakeClient({ENTRY: 'import("./assets/nothing-here.js")'})
|
||||
_raised = False
|
||||
try:
|
||||
_run(xa.find_indices_url_deep([ENTRY], c))
|
||||
except Exception:
|
||||
_raised = True
|
||||
check("deepscan: raises when absent", _raised)
|
||||
check("deepscan: records txid failure", xa.TXID_STATE["failed"] is True)
|
||||
|
||||
# 成功時は失敗フラグをクリアする (再試行で回復したケース)
|
||||
xa.TXID_STATE["failed"] = True
|
||||
c = _FakeClient({ENTRY: 'import("./sign.o-BS4wvWaM.js")'})
|
||||
_run(xa.find_indices_url_deep([ENTRY], c))
|
||||
check("deepscan: clears flag on success", xa.TXID_STATE["failed"] is False)
|
||||
|
||||
print()
|
||||
if _fails:
|
||||
print(f"{len(_fails)} FAILED: {_fails}")
|
||||
|
||||
Reference in New Issue
Block a user