Skip to content

Commit ec09608

Browse files
Run isolated live video delivery smoke for PR 15
1 parent 4724f75 commit ec09608

2 files changed

Lines changed: 236 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: PR 15 Live Video Delivery E2E
2+
3+
on:
4+
push:
5+
branches:
6+
- fix/daily-video-delivery-v3
7+
paths:
8+
- tools/run_video_delivery_live_smoke.py
9+
- .github/workflows/pr15-live-video-e2e.yml
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
live-video-delivery:
16+
if: github.repository == 'hiidkaboutyou-spec/jeonghan-daily-review-bot' && github.ref == 'refs/heads/fix/daily-video-delivery-v3'
17+
runs-on: ubuntu-latest
18+
timeout-minutes: 15
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v6
22+
23+
- name: Python
24+
uses: actions/setup-python@v6
25+
with:
26+
python-version: "3.11"
27+
cache: pip
28+
29+
- name: FFmpeg
30+
timeout-minutes: 8
31+
shell: bash
32+
run: |
33+
set -euo pipefail
34+
verify_ffmpeg() {
35+
command -v ffmpeg >/dev/null 2>&1 &&
36+
command -v ffprobe >/dev/null 2>&1 &&
37+
ffmpeg -version | head -n 1 &&
38+
ffprobe -version | head -n 1
39+
}
40+
if verify_ffmpeg; then
41+
exit 0
42+
fi
43+
for attempt in 1 2; do
44+
if timeout 90s sudo apt-get \
45+
-o Acquire::Retries=2 \
46+
-o Acquire::ForceIPv4=true \
47+
-o Acquire::http::Timeout=15 \
48+
-o Acquire::https::Timeout=15 \
49+
update -qq && \
50+
timeout 90s sudo apt-get \
51+
-o Dpkg::Use-Pty=0 \
52+
install -y -qq --no-install-recommends ffmpeg && \
53+
verify_ffmpeg; then
54+
exit 0
55+
fi
56+
sleep 3
57+
done
58+
BREW_BIN="/home/linuxbrew/.linuxbrew/bin/brew"
59+
if [ -x "$BREW_BIN" ]; then
60+
eval "$("$BREW_BIN" shellenv)"
61+
export HOMEBREW_NO_AUTO_UPDATE=1
62+
export HOMEBREW_NO_INSTALL_CLEANUP=1
63+
timeout 240s brew install ffmpeg
64+
verify_ffmpeg
65+
echo "$(dirname "$(command -v ffmpeg)")" >> "$GITHUB_PATH"
66+
exit 0
67+
fi
68+
echo "::error::Could not bootstrap FFmpeg for isolated PR #15 live smoke."
69+
exit 1
70+
71+
- name: Install
72+
run: |
73+
python -m pip install --upgrade "pip>=26.1.2"
74+
python -m pip install -r requirements.txt
75+
python -m pip check
76+
77+
- name: Isolated live video delivery smoke
78+
env:
79+
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
80+
TELEGRAM_ADMIN_USER_ID: ${{ secrets.TELEGRAM_ADMIN_USER_ID }}
81+
TELEGRAM_REVIEW_CHAT_ID: ${{ secrets.TELEGRAM_REVIEW_CHAT_ID }}
82+
run: python -m tools.run_video_delivery_live_smoke
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
from __future__ import annotations
2+
3+
import asyncio
4+
import hashlib
5+
import os
6+
import shutil
7+
import subprocess
8+
import tempfile
9+
from datetime import datetime, timezone
10+
from pathlib import Path
11+
12+
from app.media import MediaManager
13+
from app.media_delivery import MediaDeliveryLedger
14+
from app.media_delivery_runtime import MediaDedupReviewApplication
15+
from app.media_file_cache import MediaFileCache
16+
from app.models import MediaItem, Update
17+
from app.private_telegram import PrivateReviewTelegramBot
18+
19+
20+
def _required_env(name: str) -> str:
21+
value = os.environ.get(name, "").strip()
22+
if not value:
23+
raise RuntimeError(f"{name} is required for the isolated live video smoke")
24+
return value
25+
26+
27+
def _make_source_video(path: Path) -> None:
28+
subprocess.run(
29+
[
30+
"ffmpeg",
31+
"-hide_banner",
32+
"-loglevel",
33+
"error",
34+
"-y",
35+
"-f",
36+
"lavfi",
37+
"-i",
38+
"testsrc=size=320x180:rate=25",
39+
"-f",
40+
"lavfi",
41+
"-i",
42+
"sine=frequency=880:sample_rate=48000",
43+
"-t",
44+
"1.2",
45+
"-c:v",
46+
"libx264",
47+
"-pix_fmt",
48+
"yuv420p",
49+
"-c:a",
50+
"aac",
51+
"-b:a",
52+
"96k",
53+
str(path),
54+
],
55+
check=True,
56+
timeout=30,
57+
)
58+
59+
60+
def main() -> int:
61+
token = _required_env("TELEGRAM_BOT_TOKEN")
62+
admin_id = int(_required_env("TELEGRAM_ADMIN_USER_ID"))
63+
review_chat_id = int(_required_env("TELEGRAM_REVIEW_CHAT_ID"))
64+
if not shutil.which("ffmpeg") or not shutil.which("ffprobe"):
65+
raise RuntimeError("ffmpeg and ffprobe are required")
66+
67+
with tempfile.TemporaryDirectory(prefix="pr15-live-video-e2e-") as temp:
68+
root = Path(temp)
69+
db_path = root / "private-review.sqlite3"
70+
source = root / "source.mp4"
71+
_make_source_video(source)
72+
73+
item = MediaItem(
74+
kind="video",
75+
url="https://video.twimg.com/ext_tw_video/1/pu/vid/pr15-live-e2e.mp4",
76+
)
77+
update = Update(
78+
id="pr15-live-video-e2e",
79+
url="https://x.com/i/web/status/1",
80+
author="pr15-e2e",
81+
author_name="PR #15 E2E",
82+
text="isolated video delivery smoke",
83+
created_at=datetime.now(timezone.utc),
84+
media=[item],
85+
)
86+
87+
app = object.__new__(MediaDedupReviewApplication)
88+
app.media_cache = MediaFileCache(db_path)
89+
app.media_delivery = MediaDeliveryLedger(db_path)
90+
manager = MediaManager({})
91+
download_calls: list[str] = []
92+
93+
def local_download(url: str, target: Path, max_bytes: int, *, attempts: int = 2) -> None:
94+
del max_bytes, attempts
95+
download_calls.append(url)
96+
shutil.copyfile(source, target)
97+
98+
manager._stream_download = local_download
99+
app.media = manager
100+
telegram = PrivateReviewTelegramBot(
101+
token,
102+
admin_id,
103+
review_chat_id,
104+
send_pacing_seconds=0,
105+
)
106+
app.telegram = telegram
107+
108+
v2_key = hashlib.sha256(
109+
f"telegram-ios-video-v2\n{item.kind}\n{item.url}".encode("utf-8")
110+
).hexdigest()
111+
with app.media_cache.conn:
112+
app.media_cache.conn.execute(
113+
"INSERT INTO telegram_media_cache(media_key,kind,original_url,file_id,file_unique_id) "
114+
"VALUES(?,?,?,?,?)",
115+
(
116+
v2_key,
117+
item.kind,
118+
item.url,
119+
"stale-v2-file-id",
120+
"stale-v2-unique-id",
121+
),
122+
)
123+
124+
try:
125+
if app.media_cache.get(item) is not None:
126+
raise RuntimeError("v2 cache entry unexpectedly survived the v3 lookup")
127+
if not asyncio.run(app._deliver_private_media(update)):
128+
raise RuntimeError("isolated video delivery returned false")
129+
if download_calls != [item.url]:
130+
raise RuntimeError("video was not re-retrieved exactly once after the v2 cache miss")
131+
132+
cached = app.media_cache.get(item)
133+
if cached is None or not cached.file_id or not cached.file_unique_id:
134+
raise RuntimeError("Telegram success was not persisted into the v3 cache")
135+
if cached.media_key == v2_key:
136+
raise RuntimeError("fresh Telegram file_id was stored under the stale v2 key")
137+
138+
remote = telegram.api("getFile", data={"file_id": cached.file_id}, timeout=30)
139+
if not isinstance(remote, dict) or not remote.get("file_path"):
140+
raise RuntimeError("Telegram getFile could not resolve the newly uploaded video")
141+
142+
telegram.send_message(
143+
"✅ PR #15 live video delivery E2E passed: v2 cache was bypassed, the video was normalized and uploaded with sendVideo, and Telegram resolved the fresh file_id.",
144+
disable_preview=True,
145+
)
146+
print("LIVE_VIDEO_DELIVERY_E2E_OK")
147+
return 0
148+
finally:
149+
app.media_delivery.close()
150+
app.media_cache.close()
151+
152+
153+
if __name__ == "__main__":
154+
raise SystemExit(main())

0 commit comments

Comments
 (0)