Files
omni-parse/tools/_verify_claims.py

142 lines
4.0 KiB
Python

"""Проверка пунктов прожарки на текущем коде (до патчей). Только чтение, ничего не пишет в базу."""
import gc
import json
import os
import re
import sys
import threading
import time
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
os.environ.setdefault("PYTHONIOENCODING", "utf-8")
import psutil # noqa: E402
ROOT = Path(__file__).resolve().parent.parent
OUT = {}
def p(k, v):
OUT[k] = v
print(f"{k}: {v}")
# 2. валидация limit: эмулируем то, что делает serve для /api/items
def check_limit():
def parse(raw):
try:
return min(int(raw), 200)
except ValueError as e:
return f"ValueError: {e}"
p("limit[-1]", parse("-1"))
p("limit[abc]", parse("abc"))
p("limit[999999]", parse("999999"))
# 3. утечка соединений
def check_conn_leak():
from omni import store
gc.collect()
before = len(psutil.Process().open_files())
for _ in range(50):
store.top(limit=1)
gc.collect()
after = len(psutil.Process().open_files())
p("fd_before", before)
p("fd_after_50_calls", after)
p("fd_leak", after - before)
# 4. троттлинг
def check_throttle():
from omni import net
net._cfg["per_host_delay"] = 0.3
net._last.clear()
t0 = time.time()
threads = [threading.Thread(target=lambda: [net._throttle("example.org") for _ in range(3)]) for _ in range(8)]
for t in threads:
t.start()
for t in threads:
t.join()
el = time.time() - t0
expected = 0.3 * (8 * 3 - 1)
p("throttle_elapsed", round(el, 2))
p("throttle_expected_min", round(expected, 2))
p("throttle_broken", el < expected * 0.5)
# 6. мёртвые файлы
def check_dead():
names = ["abuse_sources", "rank", "sources_abuse"]
for n in names:
hits = []
for f in (ROOT / "omni").glob("*.py"):
if f.stem == n:
continue
txt = f.read_text(encoding="utf-8", errors="replace")
if re.search(rf"(import|from)\s+.*\b{n}\b", txt):
hits.append(f.name)
p(f"imports_{n}", hits)
# 7. дубли источников
def check_dupe_sources():
from omni import sources
urls = [s.url for s in sources.all_sources()]
p("sources_total", len(urls))
p("urls_unique", len(set(urls)))
p("dupe_groups", len(urls) - len(set(urls)))
# 8. except Exception
def check_except():
total = 0
for f in (ROOT / "omni").rglob("*.py"):
total += len(re.findall(r"except\s+Exception", f.read_text(encoding="utf-8", errors="replace")))
p("except_exception_total", total)
# 9. JOBS без eviction
def check_jobs():
from omni import serve
src = (ROOT / "omni" / "serve.py").read_text(encoding="utf-8")
p("jobs_has_eviction", "JOBS.pop" in src or "del JOBS" in src)
for i in range(500):
serve._job(f"j{i}", status="done")
p("jobs_len_after_500", len(serve.JOBS))
# 10. sleep в ai.py
def check_ai_sleep():
src = (ROOT / "omni" / "ai.py").read_text(encoding="utf-8")
m = re.search(r"except Exception:\s*\n\s*time\.sleep\(([^)]*)\)", src)
p("ai_sleep_line", m.group(0).replace("\n", " ") if m else None)
# 1. /run в боте
def check_bot_run():
src = (ROOT / "omni" / "bot.py").read_text(encoding="utf-8")
p("bot_new_plus_equals_add", "new += store.add(items)" in src)
p("bot_cmd_abuse_present", "def cmd_abuse" in src)
p("bot_cmds_abuse_present", "cmd_abuse" in src)
if __name__ == "__main__":
import contextlib
import io
check_limit()
with contextlib.redirect_stdout(io.StringIO()):
check_bot_run()
check_bot_run()
check_throttle()
check_dead()
check_dupe_sources()
check_except()
with contextlib.redirect_stderr(io.StringIO()):
check_jobs()
check_ai_sleep()
check_conn_leak()
print("\nJSON:", json.dumps(OUT, ensure_ascii=False, default=str))