화면 녹화 테스트
이 테스트는 헤드 모드 브라우저 세션을 MP4 파일로 녹화하여 전체 VNC/브라우저 스택을 검증합니다. 다음 사항을 증명합니다:
- Xvfb가 실행 중이며
:99에서 연결을 수락하고 있음 - Chromium이 가상 디스플레이에서 헤드 모드로 실행될 수 있음
- ffmpeg가 x11grab을 통해 디스플레이를 캡처할 수 있음
- 생성된 MP4가 유효하고 재생 가능한 비디오임
작동 방식
섹션 제목: “작동 방식”- X 디스플레이가 준비될 때까지
xdpyinfo -display :99를 폴링합니다 (엔트리포인트와 동일한 패턴) - 10 fps로 디스플레이를 녹화하는 ffmpeg를 시작합니다
- Playwright의
sync_api를 통해 헤드 모드 Chromium을 실행합니다 https://example.com으로 이동하고 (3초 대기), 그 다음https://httpbin.org으로 이동합니다 (3초 대기)- 깔끔한 MP4 마무리를 위해 ffmpeg에 SIGTERM을 보냅니다
- 출력 경로와 파일 크기를 보고합니다
스크립트
섹션 제목: “스크립트”다음 내용을 컨테이너 내부에 vnc-browser-test.py로 저장하거나, 이 저장소의 docs/tests/ 디렉터리에서 복사하세요:
#!/usr/bin/env python3"""VNC/browser stack integration test.
Proves that Xvfb, headed Chromium (via Playwright), and ffmpeg screenrecording all work together inside the devcontainer by recording abrowser navigating to two websites and producing an MP4 video.
Usage: python3 vnc-browser-test.py [output_path]Default output: /tmp/recording.mp4"""
import osimport signalimport subprocessimport sysimport time
DISPLAY = os.environ.get("DISPLAY", ":99")DEFAULT_OUTPUT = "/tmp/recording.mp4"RESOLUTION = "1280x1024"FRAMERATE = "10"XVFB_TIMEOUT = 50 # iterations (~5 s at 0.1 s each)SITES = [ ("https://example.com", 3), ("https://httpbin.org", 3),]
def wait_for_xvfb(): """Poll xdpyinfo until the X display is ready (mirrors entrypoint.sh).""" print(f"Waiting for Xvfb on {DISPLAY} ...") for i in range(XVFB_TIMEOUT): result = subprocess.run( ["xdpyinfo", "-display", DISPLAY], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) if result.returncode == 0: print(f" Display ready after {i * 0.1:.1f}s") return time.sleep(0.1) sys.exit(f"ERROR: Xvfb display {DISPLAY} not ready after {XVFB_TIMEOUT * 0.1:.1f}s")
def start_recording(output_path): """Start ffmpeg x11grab recording and return the process.""" cmd = [ "ffmpeg", "-y", "-f", "x11grab", "-video_size", RESOLUTION, "-framerate", FRAMERATE, "-i", f"{DISPLAY}.0", "-c:v", "libx264", "-preset", "ultrafast", "-pix_fmt", "yuv420p", output_path, ] print(f"Starting ffmpeg recording -> {output_path}") return subprocess.Popen( cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, )
def stop_recording(proc): """Send SIGTERM and wait for ffmpeg to finalize the MP4.""" print("Stopping ffmpeg ...") proc.send_signal(signal.SIGTERM) try: proc.wait(timeout=10) except subprocess.TimeoutExpired: proc.kill() proc.wait()
def browse_sites(): """Launch headed Chromium via Playwright and visit each site.""" from playwright.sync_api import sync_playwright # noqa: PLC0415
with sync_playwright() as pw: browser = pw.chromium.launch( headless=False, args=[ "--no-sandbox", "--disable-gpu", f"--display={DISPLAY}", ], ) page = browser.new_page(viewport={"width": 1280, "height": 1024})
for url, pause in SITES: print(f" Navigating to {url} ...") try: page.goto(url, timeout=15000) except Exception as exc: # noqa: BLE001 print(f" Warning: navigation error ({exc}), continuing") time.sleep(pause)
browser.close()
def main(): output_path = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_OUTPUT
wait_for_xvfb()
ffmpeg = start_recording(output_path) # Give ffmpeg a moment to initialize before browser activity time.sleep(1)
try: browse_sites() finally: stop_recording(ffmpeg)
if os.path.isfile(output_path): size = os.path.getsize(output_path) print(f"\nSUCCESS: {output_path} ({size:,} bytes)") else: sys.exit(f"ERROR: output file not created: {output_path}")
if __name__ == "__main__": main()테스트 실행
섹션 제목: “테스트 실행”python3 vnc-browser-test.py /tmp/recording.mp4podman run --rm \ -v $(pwd)/output:/output \ ghcr.io/f5-sales-demo/devcontainer:latest \ python3 vnc-browser-test.py /output/recording.mp4예상 출력
섹션 제목: “예상 출력”Waiting for Xvfb on :99 ... Display ready after 0.3sStarting ffmpeg recording -> /tmp/recording.mp4 Navigating to https://example.com ... Navigating to https://httpbin.org ...Stopping ffmpeg ...
SUCCESS: /tmp/recording.mp4 (1,234,567 bytes)MP4에는 fluxbox 데스크톱에서 두 웹사이트를 렌더링하는 Chromium 창이 표시되어야 합니다. ffplay, vlc로 재생하거나, 컨테이너에서 다운로드하여 확인하세요.
실패 시 의미
섹션 제목: “실패 시 의미”| 증상 | 예상 원인 |
|---|---|
Xvfb display :99 not ready | Xvfb가 시작되지 않음 — 엔트리포인트가 VNC 스택을 실행했는지 확인하세요 |
ffmpeg: x11grab error | 디스플레이 불일치 또는 ffmpeg에 x11grab 지원이 없음 |
Playwright launch error | Chromium이 설치되지 않았거나 --no-sandbox가 누락됨 |
| MP4가 0 바이트 | 쓰기 전에 ffmpeg가 종료됨 — SIGTERM 처리를 확인하세요 |