test: privatehd icin live e2e testlerini ve test dokumantasyonunu ekle
This commit is contained in:
99
README.md
99
README.md
@@ -227,6 +227,105 @@ Bu script:
|
|||||||
|
|
||||||
Kurulum daha önce tamamsa script aynı işlemleri baştan yapmaz; sadece eksikleri tamamlar.
|
Kurulum daha önce tamamsa script aynı işlemleri baştan yapmaz; sadece eksikleri tamamlar.
|
||||||
|
|
||||||
|
## Testler
|
||||||
|
|
||||||
|
`wscraper` içinde canlı sistemlere karşı çalışan `pytest` tabanlı e2e testleri vardır. Bunlar varsayılan olarak kapalıdır; yalnızca açıkça etkinleştirildiğinde çalışırlar.
|
||||||
|
|
||||||
|
Test dosyaları:
|
||||||
|
|
||||||
|
- `tests/e2e/test_happyfappy_live.py`
|
||||||
|
- `tests/e2e/test_privatehd_live.py`
|
||||||
|
- `tests/e2e/_helpers.py`
|
||||||
|
|
||||||
|
### Testleri Etkinleştirme
|
||||||
|
|
||||||
|
Tüm live testler için:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export WSCRAPER_E2E=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Bu değişken yoksa veya `1` değilse, e2e testleri `skip` olur.
|
||||||
|
|
||||||
|
### HappyFappy Live Testleri
|
||||||
|
|
||||||
|
Mevcut test kapsamı:
|
||||||
|
|
||||||
|
- `get-bookmarks`
|
||||||
|
- `download-torrent-files`
|
||||||
|
|
||||||
|
Kullanılan env değişkenleri:
|
||||||
|
|
||||||
|
- `WSCRAPER_COOKIE_FILE`
|
||||||
|
- `WSCRAPER_TEST_TORRENT_URL`
|
||||||
|
|
||||||
|
Örnek:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export WSCRAPER_E2E=1
|
||||||
|
export WSCRAPER_COOKIE_FILE=/absolute/path/to/happyfappy-cookies.txt
|
||||||
|
export WSCRAPER_TEST_TORRENT_URL="https://www.happyfappy.net/torrents.php?id=110178"
|
||||||
|
pytest tests/e2e/test_happyfappy_live.py -m e2e -s
|
||||||
|
```
|
||||||
|
|
||||||
|
### PrivateHD Live Testleri
|
||||||
|
|
||||||
|
PrivateHD için eklenen test kapsamı:
|
||||||
|
|
||||||
|
- `get-bookmarks`
|
||||||
|
- `download-torrent-files`
|
||||||
|
- `remove-bookmark`
|
||||||
|
|
||||||
|
Kullanılan env değişkenleri:
|
||||||
|
|
||||||
|
- `WSCRAPER_PRIVATEHD_COOKIE_FILE`
|
||||||
|
- `WSCRAPER_PRIVATEHD_WISHLIST_URL`
|
||||||
|
- `WSCRAPER_PRIVATEHD_TEST_TORRENT_URL`
|
||||||
|
- `WSCRAPER_PRIVATEHD_TEST_DOWNLOAD_URL`
|
||||||
|
- `WSCRAPER_PRIVATEHD_TEST_REMOVE_URL`
|
||||||
|
- `WSCRAPER_PRIVATEHD_TEST_REMOVE_TOKEN`
|
||||||
|
|
||||||
|
Fallback kuralı:
|
||||||
|
|
||||||
|
- `WSCRAPER_PRIVATEHD_COOKIE_FILE` yoksa `WSCRAPER_COOKIE_FILE` kullanılır
|
||||||
|
|
||||||
|
Örnek:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export WSCRAPER_E2E=1
|
||||||
|
export WSCRAPER_PRIVATEHD_COOKIE_FILE=/absolute/path/to/privatehd-cookies.txt
|
||||||
|
export WSCRAPER_PRIVATEHD_WISHLIST_URL="https://privatehd.to/profile/blackdockers/wishlist"
|
||||||
|
export WSCRAPER_PRIVATEHD_TEST_TORRENT_URL="https://privatehd.to/torrent/12345-example"
|
||||||
|
export WSCRAPER_PRIVATEHD_TEST_DOWNLOAD_URL="https://privatehd.to/download/torrent/12345.example.torrent"
|
||||||
|
pytest tests/e2e/test_privatehd_live.py -m e2e -s
|
||||||
|
```
|
||||||
|
|
||||||
|
### remove-bookmark Testi Hakkında
|
||||||
|
|
||||||
|
`PrivateHD remove-bookmark` testi gerçek wishlist kaydını sildiği için özellikle dikkatli kullanılmalıdır.
|
||||||
|
|
||||||
|
Bu test:
|
||||||
|
|
||||||
|
- yalnızca `WSCRAPER_PRIVATEHD_TEST_REMOVE_URL` ve `WSCRAPER_PRIVATEHD_TEST_REMOVE_TOKEN` verilirse çalışır
|
||||||
|
- aksi halde güvenli şekilde `skip` olur
|
||||||
|
|
||||||
|
Örnek:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export WSCRAPER_E2E=1
|
||||||
|
export WSCRAPER_PRIVATEHD_COOKIE_FILE=/absolute/path/to/privatehd-cookies.txt
|
||||||
|
export WSCRAPER_PRIVATEHD_WISHLIST_URL="https://privatehd.to/profile/blackdockers/wishlist"
|
||||||
|
export WSCRAPER_PRIVATEHD_TEST_REMOVE_URL="https://privatehd.to/torrent/12345-example"
|
||||||
|
export WSCRAPER_PRIVATEHD_TEST_REMOVE_TOKEN="467471"
|
||||||
|
pytest tests/e2e/test_privatehd_live.py -m e2e -s -k remove
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notlar
|
||||||
|
|
||||||
|
- Bu testler gerçek tracker hesaplarına ve geçerli cookie'lere ihtiyaç duyar
|
||||||
|
- `remove-bookmark` testi mutasyon yapar; test datası bilinçli seçilmelidir
|
||||||
|
- `tests/e2e/_helpers.py`, tüm tracker live testlerinde ortak CLI çalıştırma ve loglama yardımcılarını içerir
|
||||||
|
|
||||||
## Dizin Yapısı
|
## Dizin Yapısı
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
75
tests/e2e/_helpers.py
Normal file
75
tests/e2e/_helpers.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def e2e_enabled() -> bool:
|
||||||
|
return os.getenv("WSCRAPER_E2E", "").strip() == "1"
|
||||||
|
|
||||||
|
|
||||||
|
def base_env() -> dict[str, str]:
|
||||||
|
env = os.environ.copy()
|
||||||
|
src_path = str(Path.cwd() / "src")
|
||||||
|
current_pythonpath = env.get("PYTHONPATH", "").strip()
|
||||||
|
env["PYTHONPATH"] = f"{src_path}{os.pathsep}{current_pythonpath}" if current_pythonpath else src_path
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def log(tr, message: str, kind: str = "info") -> None:
|
||||||
|
icon = "•"
|
||||||
|
style: dict[str, bool] = {}
|
||||||
|
if kind == "ok":
|
||||||
|
icon = "✅"
|
||||||
|
style = {"green": True}
|
||||||
|
elif kind == "err":
|
||||||
|
icon = "❌"
|
||||||
|
style = {"red": True}
|
||||||
|
elif kind == "warn":
|
||||||
|
icon = "⚠️"
|
||||||
|
style = {"yellow": True}
|
||||||
|
elif kind == "run":
|
||||||
|
icon = "🚀"
|
||||||
|
style = {"cyan": True}
|
||||||
|
|
||||||
|
if tr is not None:
|
||||||
|
tr.write_line(f"{icon} {message}", **style)
|
||||||
|
else:
|
||||||
|
print(f"{icon} {message}")
|
||||||
|
|
||||||
|
|
||||||
|
def run_cli_live(args: list[str], tr, timeout: int = 900) -> tuple[int, str]:
|
||||||
|
cmd = [sys.executable, "-m", "wscraper"] + args
|
||||||
|
log(tr, f"Running: {' '.join(cmd)}", kind="run")
|
||||||
|
|
||||||
|
started = time.time()
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
text=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
env=base_env(),
|
||||||
|
)
|
||||||
|
|
||||||
|
output_lines: list[str] = []
|
||||||
|
assert proc.stdout is not None
|
||||||
|
for line in proc.stdout:
|
||||||
|
output_lines.append(line)
|
||||||
|
clean = line.rstrip("\n")
|
||||||
|
if clean:
|
||||||
|
if tr is not None:
|
||||||
|
tr.write_line(f" {clean}")
|
||||||
|
else:
|
||||||
|
print(f" {clean}")
|
||||||
|
|
||||||
|
return_code = proc.wait(timeout=timeout)
|
||||||
|
duration = time.time() - started
|
||||||
|
if return_code == 0:
|
||||||
|
log(tr, f"Command finished successfully in {duration:.2f}s", kind="ok")
|
||||||
|
else:
|
||||||
|
log(tr, f"Command failed with exit code {return_code} in {duration:.2f}s", kind="err")
|
||||||
|
|
||||||
|
return return_code, "".join(output_lines)
|
||||||
@@ -2,100 +2,32 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import time
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from tests.e2e._helpers import e2e_enabled
|
||||||
|
from tests.e2e._helpers import log
|
||||||
|
from tests.e2e._helpers import run_cli_live
|
||||||
|
|
||||||
pytestmark = [pytest.mark.e2e]
|
pytestmark = [pytest.mark.e2e]
|
||||||
|
|
||||||
|
|
||||||
def _e2e_enabled() -> bool:
|
|
||||||
return os.getenv("WSCRAPER_E2E", "").strip() == "1"
|
|
||||||
|
|
||||||
|
|
||||||
def _base_env() -> dict[str, str]:
|
|
||||||
env = os.environ.copy()
|
|
||||||
src_path = str(Path.cwd() / "src")
|
|
||||||
current_pythonpath = env.get("PYTHONPATH", "").strip()
|
|
||||||
env["PYTHONPATH"] = f"{src_path}{os.pathsep}{current_pythonpath}" if current_pythonpath else src_path
|
|
||||||
return env
|
|
||||||
|
|
||||||
|
|
||||||
def _log(tr, message: str, kind: str = "info") -> None:
|
|
||||||
icon = "•"
|
|
||||||
style: dict[str, bool] = {}
|
|
||||||
if kind == "ok":
|
|
||||||
icon = "✅"
|
|
||||||
style = {"green": True}
|
|
||||||
elif kind == "err":
|
|
||||||
icon = "❌"
|
|
||||||
style = {"red": True}
|
|
||||||
elif kind == "warn":
|
|
||||||
icon = "⚠️"
|
|
||||||
style = {"yellow": True}
|
|
||||||
elif kind == "run":
|
|
||||||
icon = "🚀"
|
|
||||||
style = {"cyan": True}
|
|
||||||
|
|
||||||
if tr is not None:
|
|
||||||
tr.write_line(f"{icon} {message}", **style)
|
|
||||||
else:
|
|
||||||
print(f"{icon} {message}")
|
|
||||||
|
|
||||||
|
|
||||||
def _run_cli_live(args: list[str], tr, timeout: int = 900) -> tuple[int, str]:
|
|
||||||
cmd = [sys.executable, "-m", "wscraper"] + args
|
|
||||||
_log(tr, f"Running: {' '.join(cmd)}", kind="run")
|
|
||||||
|
|
||||||
started = time.time()
|
|
||||||
proc = subprocess.Popen(
|
|
||||||
cmd,
|
|
||||||
text=True,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.STDOUT,
|
|
||||||
env=_base_env(),
|
|
||||||
)
|
|
||||||
|
|
||||||
output_lines: list[str] = []
|
|
||||||
assert proc.stdout is not None
|
|
||||||
for line in proc.stdout:
|
|
||||||
output_lines.append(line)
|
|
||||||
clean = line.rstrip("\n")
|
|
||||||
if clean:
|
|
||||||
if tr is not None:
|
|
||||||
tr.write_line(f" {clean}")
|
|
||||||
else:
|
|
||||||
print(f" {clean}")
|
|
||||||
|
|
||||||
return_code = proc.wait(timeout=timeout)
|
|
||||||
duration = time.time() - started
|
|
||||||
if return_code == 0:
|
|
||||||
_log(tr, f"Command finished successfully in {duration:.2f}s", kind="ok")
|
|
||||||
else:
|
|
||||||
_log(tr, f"Command failed with exit code {return_code} in {duration:.2f}s", kind="err")
|
|
||||||
|
|
||||||
return return_code, "".join(output_lines)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def tr(request):
|
def tr(request):
|
||||||
return request.config.pluginmanager.getplugin("terminalreporter")
|
return request.config.pluginmanager.getplugin("terminalreporter")
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not _e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
@pytest.mark.skipif(not e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
||||||
def test_get_bookmarks_live(tmp_path: Path, tr) -> None:
|
def test_get_bookmarks_live(tmp_path: Path, tr) -> None:
|
||||||
cookie_file = Path(os.getenv("WSCRAPER_COOKIE_FILE", "cookies.txt"))
|
cookie_file = Path(os.getenv("WSCRAPER_COOKIE_FILE", "cookies.txt"))
|
||||||
if not cookie_file.exists():
|
if not cookie_file.exists():
|
||||||
pytest.skip(f"Cookie file not found: {cookie_file}")
|
pytest.skip(f"Cookie file not found: {cookie_file}")
|
||||||
|
|
||||||
output_file = tmp_path / "bookmarks.json"
|
output_file = tmp_path / "bookmarks.json"
|
||||||
_log(tr, f"Output file: {output_file}")
|
log(tr, f"Output file: {output_file}")
|
||||||
|
|
||||||
return_code, output_text = _run_cli_live(
|
return_code, output_text = run_cli_live(
|
||||||
[
|
[
|
||||||
"happyfappy",
|
"happyfappy",
|
||||||
"--action",
|
"--action",
|
||||||
@@ -113,7 +45,7 @@ def test_get_bookmarks_live(tmp_path: Path, tr) -> None:
|
|||||||
data = json.loads(output_file.read_text(encoding="utf-8"))
|
data = json.loads(output_file.read_text(encoding="utf-8"))
|
||||||
assert isinstance(data, list), "bookmarks output must be a JSON list"
|
assert isinstance(data, list), "bookmarks output must be a JSON list"
|
||||||
assert len(data) >= 1, "expected at least one bookmark record"
|
assert len(data) >= 1, "expected at least one bookmark record"
|
||||||
_log(tr, f"Extracted records: {len(data)}", kind="ok")
|
log(tr, f"Extracted records: {len(data)}", kind="ok")
|
||||||
|
|
||||||
first = data[0]
|
first = data[0]
|
||||||
assert isinstance(first, dict), "bookmark entry must be an object"
|
assert isinstance(first, dict), "bookmark entry must be an object"
|
||||||
@@ -124,7 +56,7 @@ def test_get_bookmarks_live(tmp_path: Path, tr) -> None:
|
|||||||
assert isinstance(first["title"], str) and first["title"].strip() != ""
|
assert isinstance(first["title"], str) and first["title"].strip() != ""
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not _e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
@pytest.mark.skipif(not e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
||||||
def test_download_torrent_file_live(tmp_path: Path, tr) -> None:
|
def test_download_torrent_file_live(tmp_path: Path, tr) -> None:
|
||||||
cookie_file = Path(os.getenv("WSCRAPER_COOKIE_FILE", "cookies.txt"))
|
cookie_file = Path(os.getenv("WSCRAPER_COOKIE_FILE", "cookies.txt"))
|
||||||
if not cookie_file.exists():
|
if not cookie_file.exists():
|
||||||
@@ -135,9 +67,9 @@ def test_download_torrent_file_live(tmp_path: Path, tr) -> None:
|
|||||||
"https://www.happyfappy.net/torrents.php?id=110178",
|
"https://www.happyfappy.net/torrents.php?id=110178",
|
||||||
)
|
)
|
||||||
output_dir = tmp_path / "torrent"
|
output_dir = tmp_path / "torrent"
|
||||||
_log(tr, f"Output dir: {output_dir}")
|
log(tr, f"Output dir: {output_dir}")
|
||||||
|
|
||||||
return_code, output_text = _run_cli_live(
|
return_code, output_text = run_cli_live(
|
||||||
[
|
[
|
||||||
"happyfappy",
|
"happyfappy",
|
||||||
"--action",
|
"--action",
|
||||||
@@ -156,7 +88,7 @@ def test_download_torrent_file_live(tmp_path: Path, tr) -> None:
|
|||||||
|
|
||||||
torrent_files = list(output_dir.glob("*.torrent"))
|
torrent_files = list(output_dir.glob("*.torrent"))
|
||||||
assert len(torrent_files) >= 1, "expected at least one .torrent file"
|
assert len(torrent_files) >= 1, "expected at least one .torrent file"
|
||||||
_log(tr, f"Downloaded .torrent files: {len(torrent_files)}", kind="ok")
|
log(tr, f"Downloaded .torrent files: {len(torrent_files)}", kind="ok")
|
||||||
|
|
||||||
content = torrent_files[0].read_bytes()
|
content = torrent_files[0].read_bytes()
|
||||||
assert content.startswith(b"d"), "torrent file should start with bencode dictionary token 'd'"
|
assert content.startswith(b"d"), "torrent file should start with bencode dictionary token 'd'"
|
||||||
|
|||||||
158
tests/e2e/test_privatehd_live.py
Normal file
158
tests/e2e/test_privatehd_live.py
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from tests.e2e._helpers import e2e_enabled
|
||||||
|
from tests.e2e._helpers import log
|
||||||
|
from tests.e2e._helpers import run_cli_live
|
||||||
|
|
||||||
|
|
||||||
|
pytestmark = [pytest.mark.e2e]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def tr(request):
|
||||||
|
return request.config.pluginmanager.getplugin("terminalreporter")
|
||||||
|
|
||||||
|
|
||||||
|
def _privatehd_cookie_file() -> Path:
|
||||||
|
path = os.getenv("WSCRAPER_PRIVATEHD_COOKIE_FILE") or os.getenv("WSCRAPER_COOKIE_FILE", "cookies.txt")
|
||||||
|
return Path(path)
|
||||||
|
|
||||||
|
|
||||||
|
def _privatehd_wishlist_url() -> str:
|
||||||
|
return os.getenv("WSCRAPER_PRIVATEHD_WISHLIST_URL", "").strip()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
||||||
|
def test_get_bookmarks_live(tmp_path: Path, tr) -> None:
|
||||||
|
cookie_file = _privatehd_cookie_file()
|
||||||
|
if not cookie_file.exists():
|
||||||
|
pytest.skip(f"Cookie file not found: {cookie_file}")
|
||||||
|
|
||||||
|
wishlist_url = _privatehd_wishlist_url()
|
||||||
|
if not wishlist_url:
|
||||||
|
pytest.skip("Set WSCRAPER_PRIVATEHD_WISHLIST_URL to run PrivateHD live bookmark test")
|
||||||
|
|
||||||
|
output_file = tmp_path / "bookmarks.json"
|
||||||
|
log(tr, f"Output file: {output_file}")
|
||||||
|
|
||||||
|
return_code, output_text = run_cli_live(
|
||||||
|
[
|
||||||
|
"privatehd",
|
||||||
|
"--action",
|
||||||
|
"get-bookmarks",
|
||||||
|
"-c",
|
||||||
|
str(cookie_file),
|
||||||
|
"--wishlist-url",
|
||||||
|
wishlist_url,
|
||||||
|
"-o",
|
||||||
|
str(output_file),
|
||||||
|
],
|
||||||
|
tr,
|
||||||
|
)
|
||||||
|
assert return_code == 0, f"CLI failed:\n{output_text}"
|
||||||
|
assert output_file.exists(), "bookmarks.json was not created"
|
||||||
|
|
||||||
|
data = json.loads(output_file.read_text(encoding="utf-8"))
|
||||||
|
assert isinstance(data, list), "bookmarks output must be a JSON list"
|
||||||
|
assert len(data) >= 1, "expected at least one bookmark record"
|
||||||
|
log(tr, f"Extracted records: {len(data)}", kind="ok")
|
||||||
|
|
||||||
|
first = data[0]
|
||||||
|
assert isinstance(first, dict), "bookmark entry must be an object"
|
||||||
|
for required_key in ("pageURL", "title", "backgroundImage", "downloadURL", "removeToken"):
|
||||||
|
assert required_key in first, f"missing key: {required_key}"
|
||||||
|
assert isinstance(first["pageURL"], str) and first["pageURL"].startswith("http")
|
||||||
|
assert isinstance(first["title"], str) and first["title"].strip() != ""
|
||||||
|
assert isinstance(first["downloadURL"], str) and first["downloadURL"].startswith("http")
|
||||||
|
assert isinstance(first["removeToken"], str) and first["removeToken"].strip() != ""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
||||||
|
def test_download_torrent_file_live(tmp_path: Path, tr) -> None:
|
||||||
|
cookie_file = _privatehd_cookie_file()
|
||||||
|
if not cookie_file.exists():
|
||||||
|
pytest.skip(f"Cookie file not found: {cookie_file}")
|
||||||
|
|
||||||
|
wishlist_url = _privatehd_wishlist_url()
|
||||||
|
if not wishlist_url:
|
||||||
|
pytest.skip("Set WSCRAPER_PRIVATEHD_WISHLIST_URL to run PrivateHD live download test")
|
||||||
|
|
||||||
|
test_url = os.getenv("WSCRAPER_PRIVATEHD_TEST_TORRENT_URL", "").strip()
|
||||||
|
download_url = os.getenv("WSCRAPER_PRIVATEHD_TEST_DOWNLOAD_URL", "").strip()
|
||||||
|
if not test_url or not download_url:
|
||||||
|
pytest.skip("Set WSCRAPER_PRIVATEHD_TEST_TORRENT_URL and WSCRAPER_PRIVATEHD_TEST_DOWNLOAD_URL")
|
||||||
|
|
||||||
|
output_dir = tmp_path / "torrent"
|
||||||
|
log(tr, f"Output dir: {output_dir}")
|
||||||
|
|
||||||
|
return_code, output_text = run_cli_live(
|
||||||
|
[
|
||||||
|
"privatehd",
|
||||||
|
"--action",
|
||||||
|
"download-torrent-files",
|
||||||
|
"-u",
|
||||||
|
test_url,
|
||||||
|
"--download-url",
|
||||||
|
download_url,
|
||||||
|
"-c",
|
||||||
|
str(cookie_file),
|
||||||
|
"--wishlist-url",
|
||||||
|
wishlist_url,
|
||||||
|
"-o",
|
||||||
|
str(output_dir),
|
||||||
|
],
|
||||||
|
tr,
|
||||||
|
)
|
||||||
|
assert return_code == 0, f"CLI failed:\n{output_text}"
|
||||||
|
assert output_dir.exists(), "torrent output directory was not created"
|
||||||
|
|
||||||
|
torrent_files = list(output_dir.glob("*.torrent"))
|
||||||
|
assert len(torrent_files) >= 1, "expected at least one .torrent file"
|
||||||
|
log(tr, f"Downloaded .torrent files: {len(torrent_files)}", kind="ok")
|
||||||
|
|
||||||
|
content = torrent_files[0].read_bytes()
|
||||||
|
assert content.startswith(b"d"), "torrent file should start with bencode dictionary token 'd'"
|
||||||
|
assert b"4:info" in content[:4096], "torrent file should include 'info' dictionary marker"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not e2e_enabled(), reason="Set WSCRAPER_E2E=1 to run live tests")
|
||||||
|
def test_remove_bookmark_live(tr) -> None:
|
||||||
|
cookie_file = _privatehd_cookie_file()
|
||||||
|
if not cookie_file.exists():
|
||||||
|
pytest.skip(f"Cookie file not found: {cookie_file}")
|
||||||
|
|
||||||
|
wishlist_url = _privatehd_wishlist_url()
|
||||||
|
if not wishlist_url:
|
||||||
|
pytest.skip("Set WSCRAPER_PRIVATEHD_WISHLIST_URL to run PrivateHD live remove test")
|
||||||
|
|
||||||
|
test_url = os.getenv("WSCRAPER_PRIVATEHD_TEST_REMOVE_URL", "").strip()
|
||||||
|
remove_token = os.getenv("WSCRAPER_PRIVATEHD_TEST_REMOVE_TOKEN", "").strip()
|
||||||
|
if not test_url or not remove_token:
|
||||||
|
pytest.skip("Set WSCRAPER_PRIVATEHD_TEST_REMOVE_URL and WSCRAPER_PRIVATEHD_TEST_REMOVE_TOKEN")
|
||||||
|
|
||||||
|
return_code, output_text = run_cli_live(
|
||||||
|
[
|
||||||
|
"privatehd",
|
||||||
|
"--action",
|
||||||
|
"remove-bookmark",
|
||||||
|
"-u",
|
||||||
|
test_url,
|
||||||
|
"--remove-token",
|
||||||
|
remove_token,
|
||||||
|
"-c",
|
||||||
|
str(cookie_file),
|
||||||
|
"--wishlist-url",
|
||||||
|
wishlist_url,
|
||||||
|
],
|
||||||
|
tr,
|
||||||
|
timeout=240,
|
||||||
|
)
|
||||||
|
assert return_code == 0, f"CLI failed:\n{output_text}"
|
||||||
|
assert "Bookmark removed successfully." in output_text
|
||||||
|
log(tr, "PrivateHD bookmark removal completed", kind="ok")
|
||||||
Reference in New Issue
Block a user