2025-11-30 14:45:55 +01:00
|
|
|
"""Integration tests for the articles C server API."""
|
|
|
|
|
|
2025-11-30 15:01:14 +01:00
|
|
|
from http import HTTPStatus
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
import http.client
|
2025-09-07 21:26:55 +02:00
|
|
|
import json
|
|
|
|
|
import os
|
2025-11-30 13:42:16 +01:00
|
|
|
from pathlib import Path
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
import shutil
|
2025-11-30 13:42:16 +01:00
|
|
|
import socket
|
|
|
|
|
import subprocess
|
2025-09-07 21:26:55 +02:00
|
|
|
import time
|
2025-11-30 15:49:40 +01:00
|
|
|
from typing import Any
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
import urllib.parse
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-11-30 15:11:39 +01:00
|
|
|
import pytest
|
|
|
|
|
|
2025-09-07 21:26:55 +02:00
|
|
|
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
class _HTTPError(Exception):
|
|
|
|
|
"""HTTP error with status code."""
|
|
|
|
|
|
|
|
|
|
def __init__(self, code: int) -> None:
|
|
|
|
|
super().__init__(f"HTTP {code}")
|
|
|
|
|
self.code = code
|
|
|
|
|
|
|
|
|
|
|
2025-11-30 15:49:40 +01:00
|
|
|
def _req(
|
|
|
|
|
url: str, method: str = "GET", data: dict[str, Any] | bytes | None = None
|
|
|
|
|
) -> tuple[int, bytes]:
|
2025-11-30 14:45:55 +01:00
|
|
|
"""Send an HTTP request and return status code and body."""
|
|
|
|
|
if data is not None and not isinstance(data, bytes | bytearray):
|
2025-09-07 21:26:55 +02:00
|
|
|
data = json.dumps(data).encode("utf-8")
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
parsed = urllib.parse.urlparse(url)
|
|
|
|
|
conn = http.client.HTTPConnection(parsed.hostname, parsed.port, timeout=5)
|
|
|
|
|
try:
|
|
|
|
|
headers = {"Content-Type": "application/json"}
|
|
|
|
|
conn.request(method, parsed.path or "/", body=data, headers=headers)
|
|
|
|
|
resp = conn.getresponse()
|
2025-09-07 21:26:55 +02:00
|
|
|
body = resp.read()
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
status = resp.status
|
|
|
|
|
finally:
|
|
|
|
|
conn.close()
|
|
|
|
|
if status >= 400:
|
|
|
|
|
raise _HTTPError(status)
|
|
|
|
|
return status, body
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _probe_server(host: str, port: int) -> bool:
|
|
|
|
|
"""Try a single GET to the server. Return True if it responded."""
|
|
|
|
|
try:
|
|
|
|
|
conn = http.client.HTTPConnection(host, port, timeout=0.2)
|
|
|
|
|
try:
|
|
|
|
|
conn.request("GET", "/api/articles")
|
|
|
|
|
conn.getresponse().read()
|
|
|
|
|
return True
|
|
|
|
|
finally:
|
|
|
|
|
conn.close()
|
|
|
|
|
except OSError:
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _wait_for_server(host: str, port: int, attempts: int = 30) -> None:
|
|
|
|
|
"""Poll the server until it responds or attempts are exhausted."""
|
|
|
|
|
for _ in range(attempts):
|
|
|
|
|
if _probe_server(host, port):
|
|
|
|
|
return
|
|
|
|
|
time.sleep(0.05)
|
2025-09-07 21:26:55 +02:00
|
|
|
|
|
|
|
|
|
2025-11-30 15:49:40 +01:00
|
|
|
def test_crud_roundtrip(tmp_path: Path) -> None:
|
2025-11-30 14:45:55 +01:00
|
|
|
"""Test full CRUD lifecycle for articles API."""
|
2025-09-07 21:46:47 +02:00
|
|
|
# Build C server
|
2026-03-21 17:51:36 +01:00
|
|
|
here = Path(__file__).resolve().parent.parent
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
make_path = shutil.which("make")
|
|
|
|
|
assert make_path is not None, "make not found in PATH"
|
|
|
|
|
subprocess.run([make_path, "-s", "server_c"], check=True, cwd=str(here))
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# Find a free port
|
|
|
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
|
|
|
s.bind(("127.0.0.1", 0))
|
|
|
|
|
_, port = s.getsockname()
|
|
|
|
|
host = "127.0.0.1"
|
2025-09-07 21:26:55 +02:00
|
|
|
base = f"http://{host}:{port}"
|
|
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# Isolate storage and start server
|
|
|
|
|
env = os.environ.copy()
|
|
|
|
|
env["ARTICLES_DATA_DIR"] = str(tmp_path)
|
|
|
|
|
env["HOST"] = host
|
|
|
|
|
env["PORT"] = str(port)
|
|
|
|
|
srv = subprocess.Popen(["./server_c"], cwd=str(here), env=env)
|
|
|
|
|
try:
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
_wait_for_server(host, port)
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# Create
|
2025-11-30 13:42:16 +01:00
|
|
|
code, body = _req(
|
|
|
|
|
base + "/api/articles",
|
|
|
|
|
method="POST",
|
|
|
|
|
data={
|
|
|
|
|
"title": "T1",
|
|
|
|
|
"body": "<p>Hello</p>",
|
|
|
|
|
"thumb": "data:image/png;base64,xyz",
|
|
|
|
|
},
|
|
|
|
|
)
|
2025-11-30 15:01:14 +01:00
|
|
|
assert code == HTTPStatus.CREATED
|
2025-09-07 21:46:47 +02:00
|
|
|
created = json.loads(body)
|
|
|
|
|
art_id = created["id"]
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# List
|
2025-11-30 13:42:16 +01:00
|
|
|
code, body = _req(base + "/api/articles")
|
2025-11-30 15:01:14 +01:00
|
|
|
assert code == HTTPStatus.OK
|
2025-09-07 21:46:47 +02:00
|
|
|
items = json.loads(body)
|
|
|
|
|
assert any(a["id"] == art_id for a in items)
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# Get one
|
2025-11-30 13:42:16 +01:00
|
|
|
code, body = _req(base + f"/api/articles/{art_id}")
|
2025-11-30 15:01:14 +01:00
|
|
|
assert code == HTTPStatus.OK
|
2025-09-07 21:46:47 +02:00
|
|
|
got = json.loads(body)
|
|
|
|
|
assert got["title"] == "T1"
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# Update
|
2025-11-30 14:25:35 +01:00
|
|
|
code, body = _req(
|
|
|
|
|
base + f"/api/articles/{art_id}", method="PUT", data={"title": "T2"}
|
|
|
|
|
)
|
2025-11-30 15:01:14 +01:00
|
|
|
assert code == HTTPStatus.OK
|
2025-09-07 21:46:47 +02:00
|
|
|
updated = json.loads(body)
|
|
|
|
|
assert updated["title"] == "T2"
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
# Delete
|
2025-11-30 13:42:16 +01:00
|
|
|
code, _ = _req(base + f"/api/articles/{art_id}", method="DELETE")
|
2025-11-30 15:01:14 +01:00
|
|
|
assert code == HTTPStatus.NO_CONTENT
|
2025-09-07 21:46:47 +02:00
|
|
|
|
|
|
|
|
# Ensure gone
|
Reduce per-file-ignores by fixing lint violations across codebase
Fix ruff violations in ~15 source files and ~60+ test files to minimize
per-file-ignores in pyproject.toml. Remaining ignores are justified with
comments explaining why each suppression is necessary.
Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001
(private access), T201 (print→logging), C901 (complexity), E501 (line
length), E402 (import order).
Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in
loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108
(tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type
annotations), RUF059 (unused unpacked vars), PT019 (fixture naming).
Remaining per-file-ignores (with justifications):
- Tests: ARG, D, PLC0415, PLR2004, S101, SLF001
- music_gen sources: PLC0415 (heavy ML lazy imports)
- moviepy_showcase: PLC0415 (circular dependency)
- generate_images: PLR0913 (matplotlib helpers need many params)
- praca_magisterska_video: E501, E402 (long paths, mpl.use)
2026-03-25 18:58:05 +01:00
|
|
|
with pytest.raises(_HTTPError) as exc_info:
|
2025-11-30 13:42:16 +01:00
|
|
|
_req(base + f"/api/articles/{art_id}")
|
2025-11-30 15:11:39 +01:00
|
|
|
assert exc_info.value.code == HTTPStatus.NOT_FOUND
|
2025-09-07 21:26:55 +02:00
|
|
|
|
2025-09-07 21:46:47 +02:00
|
|
|
finally:
|
|
|
|
|
srv.terminate()
|
|
|
|
|
try:
|
|
|
|
|
srv.wait(timeout=2)
|
2025-11-30 21:37:47 +01:00
|
|
|
except subprocess.TimeoutExpired:
|
2025-09-07 21:46:47 +02:00
|
|
|
srv.kill()
|