umbau 1.0
This commit is contained in:
@ -36,6 +36,9 @@ Drei voneinander unabhaengige Bugs/Features, gemeldet in derselben Session:
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
import io # Bug-Fix Punkt 1: UploadFile(file, *, filename=...) braucht ein
|
||||
# dateiaehnliches Objekt als erstes Argument, keine rohen bytes
|
||||
# (siehe UploadFile-Konstruktionen unten).
|
||||
|
||||
import asyncssh
|
||||
import pytest
|
||||
@ -53,6 +56,17 @@ class _FakeUser:
|
||||
self.username = username
|
||||
|
||||
|
||||
def _fake_request() -> "sftp_module.Request":
|
||||
"""Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): starlette.Request
|
||||
verlangt seit jeher ein `scope`-Dict als Pflichtargument (KEIN API-Drift
|
||||
der Anwendung -- die Tests riefen schlicht Request() ohne Argumente auf).
|
||||
Minimaler, aber vollstaendiger ASGI-HTTP-Scope: `client` wird von
|
||||
sftp.py's _client_ip()-Helfer gelesen (request.client.host), `headers`
|
||||
muss als Liste vorhanden sein (Starlette baut Request.headers direkt
|
||||
daraus, KeyError bei fehlendem Key)."""
|
||||
return sftp_module.Request({"type": "http", "client": ("127.0.0.1", 12345), "headers": []})
|
||||
|
||||
|
||||
class _FakeConn:
|
||||
"""Minimaler aiosqlite-Ersatz fuer diese Tests -- genug fuer die
|
||||
INSERT/UPDATE/SELECT-Aufrufe aus sftp.py/terminal_ws.py, ohne echte
|
||||
@ -118,13 +132,17 @@ async def test_upload_erfolgreicher_transfer_wirft_keine_typeerror(monkeypatch):
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
async def fake_connect_to_host(conn, host_id):
|
||||
async def fake_connect_to_host(conn, host_id, *, user_id=None):
|
||||
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): connect_to_host()
|
||||
# verlangt inzwischen user_id als Keyword-Argument (echte Signatur-
|
||||
# erweiterung, app/ssh_proxy/proxy.py) -- dieser Fake muss es zumindest
|
||||
# entgegennehmen koennen, auch wenn er es hier nicht auswertet.
|
||||
return _OkSshConn()
|
||||
|
||||
monkeypatch.setattr(sftp_module, "connect_to_host", fake_connect_to_host)
|
||||
|
||||
request = sftp_module.Request()
|
||||
upload = sftp_module.UploadFile("test.txt", b"hallo welt")
|
||||
request = _fake_request()
|
||||
upload = sftp_module.UploadFile(io.BytesIO(b"hallo welt"), filename="test.txt")
|
||||
|
||||
result = await sftp_module.upload_file(
|
||||
host_id=1, request=request, remote_path="/tmp/test.txt", file=upload,
|
||||
@ -144,13 +162,29 @@ async def test_upload_asyncssh_error_wird_zu_http_exception_400(monkeypatch):
|
||||
fake_conn = _FakeConn()
|
||||
monkeypatch.setattr(sftp_module, "get_db", lambda: fake_conn)
|
||||
|
||||
async def fake_connect_to_host(conn, host_id):
|
||||
raise asyncssh.Error(reason="Connection refused")
|
||||
async def fake_connect_to_host(conn, host_id, *, user_id=None):
|
||||
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): connect_to_host()
|
||||
# verlangt inzwischen user_id als Keyword-Argument (echte Signatur-
|
||||
# erweiterung, app/ssh_proxy/proxy.py) -- dieser Fake muss es zumindest
|
||||
# entgegennehmen koennen, auch wenn er es hier nicht auswertet.
|
||||
# Weiterer Drift (echte asyncssh-Signatur via inspect.signature
|
||||
# bestaetigt): asyncssh.Error.__init__(self, code: int, reason: str,
|
||||
# lang: str = 'en-US') verlangt `code` als PFLICHT-Positionsargument,
|
||||
# nicht nur `reason`. Der alte Fake-Aufruf asyncssh.Error(reason=...)
|
||||
# loeste selbst einen TypeError aus, BEVOR die eigentlich zu testende
|
||||
# except asyncssh.Error-Behandlung in sftp.py ueberhaupt erreicht wurde
|
||||
# -- der TypeError fiel unter das allgemeine except Exception-
|
||||
# Auffangnetz und ergab faelschlich 500 statt 400. Der konkrete
|
||||
# code-Wert ist fuer den Test irrelevant (nur die Klasse asyncssh.Error
|
||||
# zaehlt fuer den except-Zweig in sftp.py); DISC_CONNECTION_LOST
|
||||
# ist eine echte asyncssh-Konstante (asyncssh.DISC_CONNECTION_LOST) und
|
||||
# passt inhaltlich.
|
||||
raise asyncssh.Error(asyncssh.DISC_CONNECTION_LOST, "Connection refused")
|
||||
|
||||
monkeypatch.setattr(sftp_module, "connect_to_host", fake_connect_to_host)
|
||||
|
||||
request = sftp_module.Request()
|
||||
upload = sftp_module.UploadFile("test.txt", b"hallo welt")
|
||||
request = _fake_request()
|
||||
upload = sftp_module.UploadFile(io.BytesIO(b"hallo welt"), filename="test.txt")
|
||||
|
||||
with pytest.raises(HTTPException) as excinfo:
|
||||
await sftp_module.upload_file(
|
||||
@ -184,13 +218,17 @@ async def test_upload_sftp_permission_denied_wird_zu_http_exception_400(monkeypa
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
async def fake_connect_to_host(conn, host_id):
|
||||
async def fake_connect_to_host(conn, host_id, *, user_id=None):
|
||||
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): connect_to_host()
|
||||
# verlangt inzwischen user_id als Keyword-Argument (echte Signatur-
|
||||
# erweiterung, app/ssh_proxy/proxy.py) -- dieser Fake muss es zumindest
|
||||
# entgegennehmen koennen, auch wenn er es hier nicht auswertet.
|
||||
return _SshConn()
|
||||
|
||||
monkeypatch.setattr(sftp_module, "connect_to_host", fake_connect_to_host)
|
||||
|
||||
request = sftp_module.Request()
|
||||
upload = sftp_module.UploadFile("test.txt", b"hallo welt")
|
||||
request = _fake_request()
|
||||
upload = sftp_module.UploadFile(io.BytesIO(b"hallo welt"), filename="test.txt")
|
||||
|
||||
with pytest.raises(HTTPException) as excinfo:
|
||||
await sftp_module.upload_file(
|
||||
@ -207,13 +245,17 @@ async def test_upload_unerwarteter_fehler_wird_zu_http_exception_500_nicht_unbeh
|
||||
fake_conn = _FakeConn()
|
||||
monkeypatch.setattr(sftp_module, "get_db", lambda: fake_conn)
|
||||
|
||||
async def fake_connect_to_host(conn, host_id):
|
||||
async def fake_connect_to_host(conn, host_id, *, user_id=None):
|
||||
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): connect_to_host()
|
||||
# verlangt inzwischen user_id als Keyword-Argument (echte Signatur-
|
||||
# erweiterung, app/ssh_proxy/proxy.py) -- dieser Fake muss es zumindest
|
||||
# entgegennehmen koennen, auch wenn er es hier nicht auswertet.
|
||||
raise AttributeError("simuliert einen unverwandten kuenftigen Bug")
|
||||
|
||||
monkeypatch.setattr(sftp_module, "connect_to_host", fake_connect_to_host)
|
||||
|
||||
request = sftp_module.Request()
|
||||
upload = sftp_module.UploadFile("test.txt", b"hallo welt")
|
||||
request = _fake_request()
|
||||
upload = sftp_module.UploadFile(io.BytesIO(b"hallo welt"), filename="test.txt")
|
||||
|
||||
with pytest.raises(HTTPException) as excinfo:
|
||||
await sftp_module.upload_file(
|
||||
@ -234,28 +276,37 @@ async def test_download_datei_zu_gross_bleibt_413_und_wird_nicht_zu_500(monkeypa
|
||||
size = sftp_module.MAX_UPLOAD_BYTES + 1
|
||||
|
||||
class _HugeSftp:
|
||||
async def __aenter__(self):
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *a):
|
||||
return False
|
||||
"""Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): download_file()
|
||||
nutzt `sftp = await ssh_conn.start_sftp_client()` (KEIN `async with`,
|
||||
anders als upload_file() -- reales asyncssh erlaubt beides ueber
|
||||
seinen @async_context_manager-Dekorator) und ruft im Fehlerfall
|
||||
`sftp.exit()` SYNCHRON auf (kein await, echte asyncssh-API). Der
|
||||
vorherige Fake hatte weder ein passendes async start_sftp_client()
|
||||
noch ueberhaupt eine exit()-Methode."""
|
||||
|
||||
async def stat(self, path):
|
||||
return _Stat()
|
||||
|
||||
def exit(self):
|
||||
pass
|
||||
|
||||
class _SshConn:
|
||||
def start_sftp_client(self):
|
||||
async def start_sftp_client(self):
|
||||
return _HugeSftp()
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
async def fake_connect_to_host(conn, host_id):
|
||||
async def fake_connect_to_host(conn, host_id, *, user_id=None):
|
||||
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): connect_to_host()
|
||||
# verlangt inzwischen user_id als Keyword-Argument (echte Signatur-
|
||||
# erweiterung, app/ssh_proxy/proxy.py) -- dieser Fake muss es zumindest
|
||||
# entgegennehmen koennen, auch wenn er es hier nicht auswertet.
|
||||
return _SshConn()
|
||||
|
||||
monkeypatch.setattr(sftp_module, "connect_to_host", fake_connect_to_host)
|
||||
|
||||
request = sftp_module.Request()
|
||||
request = _fake_request()
|
||||
with pytest.raises(HTTPException) as excinfo:
|
||||
await sftp_module.download_file(
|
||||
host_id=1, request=request, remote_path="/tmp/huge.bin",
|
||||
@ -272,7 +323,12 @@ async def test_active_sessions_broadcast_erreicht_alle_beobachter(event_loop=Non
|
||||
import asyncio
|
||||
|
||||
task = asyncio.current_task()
|
||||
active_sessions.register(session_id=4242, task=task)
|
||||
# Bug-Fix (FORTSETZUNG_Teil_C.md Abschnitt 3 Punkt 1): register()
|
||||
# verlangt seit E.4/Teil F user_id als drittes Pflichtargument (echte
|
||||
# Signaturerweiterung der Anwendung, kein Test-Freibleiber -- die
|
||||
# konkrete ID ist fuer diesen Test irrelevant, es geht nur um die
|
||||
# Beobachter-/Broadcast-Mechanik).
|
||||
active_sessions.register(session_id=4242, task=task, user_id=1)
|
||||
try:
|
||||
q1 = active_sessions.add_watcher(4242)
|
||||
q2 = active_sessions.add_watcher(4242)
|
||||
@ -377,7 +433,7 @@ async def test_watch_ssh_session_leitet_frames_weiter_und_raeumt_beobachter_auf(
|
||||
|
||||
monkeypatch.setattr(terminal_ws_module, "write_audit_event", fake_write_audit_event)
|
||||
|
||||
active_sessions.register(session_id=1, task=asyncio.current_task())
|
||||
active_sessions.register(session_id=1, task=asyncio.current_task(), user_id=1)
|
||||
try:
|
||||
class _WsThenDisconnect(_FakeWebSocket):
|
||||
def __init__(self):
|
||||
|
||||
Reference in New Issue
Block a user