Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tests/test_executor_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ def test_queued_commands_use_sequential_per_user_environment(
cur.execute("SELECT submit_command(%s, %s, %s)", (user_id, session_id, "pwd"))
pwd_id = cur.fetchone()[0]

worker_one = psycopg2.connect(db_conn.dsn)
worker_two = psycopg2.connect(db_conn.dsn)
worker_one = psycopg2.connect(os.environ["TEST_DATABASE_URL"])
worker_two = psycopg2.connect(os.environ["TEST_DATABASE_URL"])
try:
first = fetch_pending(worker_one)
assert first["id"] == cd_id
Expand Down Expand Up @@ -180,7 +180,7 @@ def test_expired_command_is_recovered_and_no_longer_blocks_session(db_conn):
(abandoned_id,),
)

worker = psycopg2.connect(db_conn.dsn)
worker = psycopg2.connect(os.environ["TEST_DATABASE_URL"])
try:
recovered = fetch_pending(worker, "fresh")
assert recovered["id"] == abandoned_id
Expand Down
30 changes: 29 additions & 1 deletion tests/test_html_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import contextlib
import functools
import glob
import http.server
import os
import threading
from pathlib import Path

Expand All @@ -19,6 +21,32 @@
HTML_DIR = Path(__file__).parents[1] / "html"


def _launch_chromium(playwright):
"""Launch Chromium, tolerating a browser build that predates this
Playwright release's pinned revision.

``playwright.chromium.launch()`` resolves an exact browser build number and
fails when only a differently numbered Chromium is present in the image (a
common situation when the browser is provisioned separately from the pinned
Python package). Fall back to any executable Chromium found under
``PLAYWRIGHT_BROWSERS_PATH`` before giving up.
"""
try:
return playwright.chromium.launch()
except Exception:
root = os.environ.get("PLAYWRIGHT_BROWSERS_PATH", "/opt/pw-browsers")
patterns = (
"chromium-*/chrome-linux/chrome",
"chromium_headless_shell-*/chrome-linux/headless_shell",
"chromium",
)
for pattern in patterns:
for path in sorted(glob.glob(os.path.join(root, pattern))):
if os.access(path, os.X_OK):
return playwright.chromium.launch(executable_path=path)
raise


@pytest.fixture(scope="module")
def ui_base_url():
handler = functools.partial(
Expand All @@ -43,7 +71,7 @@ def test_command_and_response_markup_is_rendered_only_as_text(ui_base_url):

with sync_playwright() as playwright:
try:
browser = playwright.chromium.launch()
browser = _launch_chromium(playwright)
except Exception as error:
pytest.skip(f"Playwright Chromium is unavailable: {error}")

Expand Down
103 changes: 94 additions & 9 deletions tests/test_postgrest_integration.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,113 @@
"""Integration coverage for requests sent to a live PostgREST instance."""
"""Integration coverage for requests sent to a PostgREST-compatible endpoint.

When ``TEST_POSTGREST_URL`` points at a live PostgREST instance the test uses
it directly. Otherwise an in-process, PostgREST-compatible shim resolves
``GET /rpc/latest_output`` by invoking the real ``latest_output`` SQL function,
so the CLI's request construction and the function's contract are exercised
without provisioning an external gateway.
"""

import json
import os
import threading
import uuid
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import parse_qs, urlparse

import psycopg2
from psycopg2.extras import RealDictCursor
import pytest

from cli.shell_cli import tail_output


def test_tail_output_invokes_latest_output_through_postgrest(db_conn, capsys):
"""A CLI-generated query resolves latest_output(UUID, INTEGER)."""
base_url = os.environ.get("TEST_POSTGREST_URL")
if not base_url:
pytest.skip("TEST_POSTGREST_URL not set")
def _make_handler(dsn):
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
parsed = urlparse(self.path)
if parsed.path != "/rpc/latest_output":
self.send_error(404)
return
params = parse_qs(parsed.query)
try:
user_id = params["p_user_id"][0]
session_id = params["p_session_id"][0]
except (KeyError, IndexError):
self.send_error(400)
return
since_id = int(params.get("p_since_id", ["0"])[0])

conn = psycopg2.connect(dsn)
try:
conn.autocommit = True
with conn.cursor(cursor_factory=RealDictCursor) as cur:
cur.execute(
"SELECT * FROM latest_output(%s, %s, %s)",
(user_id, session_id, since_id),
)
rows = cur.fetchall()
finally:
conn.close()

body = json.dumps(rows, default=str).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)

def log_message(self, *args): # pragma: no cover - silence test server
pass

return Handler


@pytest.fixture
def postgrest_base_url():
"""Yield a base URL exposing PostgREST's ``/rpc`` interface.

Prefers a live PostgREST instance via ``TEST_POSTGREST_URL``; falls back to
an in-process shim backed by the test database.
"""
configured = os.environ.get("TEST_POSTGREST_URL")
if configured:
yield configured.rstrip("/")
return

dsn = os.environ.get("TEST_DATABASE_URL")
if not dsn:
pytest.skip("TEST_DATABASE_URL not set")

server = ThreadingHTTPServer(("127.0.0.1", 0), _make_handler(dsn))
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
yield f"http://127.0.0.1:{server.server_port}"
finally:
server.shutdown()
thread.join()
server.server_close()


def test_tail_output_invokes_latest_output_through_postgrest(
db_conn, postgrest_base_url, capsys
):
"""A CLI-generated query resolves latest_output(UUID, UUID, INTEGER)."""
user_id = str(uuid.uuid4())
with db_conn.cursor() as cur:
cur.execute(
"INSERT INTO users(id, username) VALUES (%s, %s)",
(user_id, f"postgrest-{user_id}"),
)
cur.execute("INSERT INTO environments(user_id) VALUES (%s) RETURNING session_id", (user_id,))
cur.execute(
"INSERT INTO environments(user_id) VALUES (%s) RETURNING session_id",
(user_id,),
)
session_id = str(cur.fetchone()[0])
cur.execute("SELECT submit_command(%s, %s, %s)", (user_id, session_id, "echo integration"))
cur.execute(
"SELECT submit_command(%s, %s, %s)",
(user_id, session_id, "echo integration"),
)
command_id = cur.fetchone()[0]
cur.execute(
"""
Expand All @@ -35,7 +120,7 @@ def test_tail_output_invokes_latest_output_through_postgrest(db_conn, capsys):
)

assert tail_output(
base_url.rstrip("/"), user_id, session_id, since=0, interval=0, max_polls=1
postgrest_base_url, user_id, session_id, since=0, interval=0, max_polls=1
) == 0
assert capsys.readouterr().out.splitlines() == [
"$ echo integration",
Expand Down
Loading