chore: reorganize test files into domain-specific subdirectories under tests/
Split the monolithic test directory into three tiers (unit, api, e2e) with a path-mirroring directory structure. Added corresponding Makefile targets (test-unit, test-api, test-e2e) and updated all documentation references (CLAUDE.md, README.md, testing-cicd.html, testing-framework.html, testing-make.html) to reflect the new layout and naming conventions.
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import io
|
||||
import uuid
|
||||
import requests
|
||||
from PIL import Image
|
||||
from tests.conftest import BASE_URL
|
||||
from devplacepy.database import get_table
|
||||
JSON_media = {"Accept": "application/json"}
|
||||
def _png_bytes_media(color=(200, 30, 30)):
|
||||
buf = io.BytesIO()
|
||||
Image.new("RGB", (8, 8), color).save(buf, "PNG")
|
||||
return buf.getvalue()
|
||||
def _signup_media(prefix="media"):
|
||||
s = requests.Session()
|
||||
name = f"{prefix}_{uuid.uuid4().hex[:10]}"
|
||||
s.post(
|
||||
f"{BASE_URL}/auth/signup",
|
||||
data={
|
||||
"username": name,
|
||||
"email": f"{name}@test.devplace",
|
||||
"password": "secret123",
|
||||
"confirm_password": "secret123",
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
return s, name
|
||||
def _login_media(seeded_db, who):
|
||||
s = requests.Session()
|
||||
creds = seeded_db[who]
|
||||
s.post(
|
||||
f"{BASE_URL}/auth/login",
|
||||
data={"email": creds["email"], "password": creds["password"]},
|
||||
allow_redirects=True,
|
||||
)
|
||||
return s
|
||||
def _upload_media(s, name="pic.png", content=None, mime="image/png"):
|
||||
files = {"file": (name, content if content is not None else _png_bytes_media(), mime)}
|
||||
r = s.post(f"{BASE_URL}/uploads/upload", files=files)
|
||||
assert r.status_code == 201, r.text
|
||||
return r.json()["uid"]
|
||||
def _create_post_media(s, attachment_uids, title="media post"):
|
||||
r = s.post(
|
||||
f"{BASE_URL}/posts/create",
|
||||
data={
|
||||
"content": "A post that carries media for the gallery tests.",
|
||||
"title": title,
|
||||
"topic": "random",
|
||||
"attachment_uids": attachment_uids,
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
assert r.status_code == 200, r.text[:300]
|
||||
assert "/posts/" in r.url, r.url
|
||||
return r.url
|
||||
def _create_project_media(s, attachment_uids, title="Media Project"):
|
||||
r = s.post(
|
||||
f"{BASE_URL}/projects/create",
|
||||
data={
|
||||
"title": title,
|
||||
"description": "Project with media for gallery tests.",
|
||||
"project_type": "software",
|
||||
"platforms": "linux",
|
||||
"status": "In Development",
|
||||
"attachment_uids": attachment_uids,
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
assert r.status_code == 200, r.text[:300]
|
||||
assert "/projects/" in r.url, r.url
|
||||
return r.url
|
||||
def _media_json(session, username):
|
||||
r = session.get(f"{BASE_URL}/profile/{username}?tab=media", headers=JSON_media)
|
||||
assert r.status_code == 200, r.text[:300]
|
||||
return r.json()
|
||||
def _media_uids(session, username):
|
||||
return [m["uid"] for m in _media_json(session, username)["media"]]
|
||||
def _seed_media_via_browser(page, title="ui media"):
|
||||
up = page.request.post(
|
||||
f"{BASE_URL}/uploads/upload",
|
||||
multipart={
|
||||
"file": {
|
||||
"name": "pic.png",
|
||||
"mimeType": "image/png",
|
||||
"buffer": _png_bytes_media(),
|
||||
}
|
||||
},
|
||||
)
|
||||
assert up.ok, up.text()
|
||||
uid = up.json()["uid"]
|
||||
post = page.request.post(
|
||||
f"{BASE_URL}/posts/create",
|
||||
form={
|
||||
"content": "media for the ui gallery test",
|
||||
"title": title,
|
||||
"topic": "random",
|
||||
"attachment_uids": uid,
|
||||
},
|
||||
)
|
||||
assert post.ok, post.text()
|
||||
return uid
|
||||
def _media_uids_via_page(page, username):
|
||||
resp = page.request.get(f"{BASE_URL}/profile/{username}?tab=media", headers=JSON_media)
|
||||
return [m["uid"] for m in resp.json()["media"]]
|
||||
|
||||
|
||||
def test_admin_trash_requires_admin(seeded_db):
|
||||
member = _login_media(seeded_db, "bob")
|
||||
r = member.get(f"{BASE_URL}/admin/media", allow_redirects=False)
|
||||
assert r.status_code in (302, 303)
|
||||
anon = requests.Session()
|
||||
assert anon.get(f"{BASE_URL}/admin/media", allow_redirects=False).status_code in (
|
||||
302,
|
||||
303,
|
||||
)
|
||||
@@ -0,0 +1,131 @@
|
||||
# retoor <retoor@molodetz.nl>
|
||||
|
||||
import io
|
||||
import uuid
|
||||
import requests
|
||||
from PIL import Image
|
||||
from tests.conftest import BASE_URL
|
||||
from devplacepy.database import get_table
|
||||
JSON_media = {"Accept": "application/json"}
|
||||
def _png_bytes_media(color=(200, 30, 30)):
|
||||
buf = io.BytesIO()
|
||||
Image.new("RGB", (8, 8), color).save(buf, "PNG")
|
||||
return buf.getvalue()
|
||||
def _signup_media(prefix="media"):
|
||||
s = requests.Session()
|
||||
name = f"{prefix}_{uuid.uuid4().hex[:10]}"
|
||||
s.post(
|
||||
f"{BASE_URL}/auth/signup",
|
||||
data={
|
||||
"username": name,
|
||||
"email": f"{name}@test.devplace",
|
||||
"password": "secret123",
|
||||
"confirm_password": "secret123",
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
return s, name
|
||||
def _login_media(seeded_db, who):
|
||||
s = requests.Session()
|
||||
creds = seeded_db[who]
|
||||
s.post(
|
||||
f"{BASE_URL}/auth/login",
|
||||
data={"email": creds["email"], "password": creds["password"]},
|
||||
allow_redirects=True,
|
||||
)
|
||||
return s
|
||||
def _upload_media(s, name="pic.png", content=None, mime="image/png"):
|
||||
files = {"file": (name, content if content is not None else _png_bytes_media(), mime)}
|
||||
r = s.post(f"{BASE_URL}/uploads/upload", files=files)
|
||||
assert r.status_code == 201, r.text
|
||||
return r.json()["uid"]
|
||||
def _create_post_media(s, attachment_uids, title="media post"):
|
||||
r = s.post(
|
||||
f"{BASE_URL}/posts/create",
|
||||
data={
|
||||
"content": "A post that carries media for the gallery tests.",
|
||||
"title": title,
|
||||
"topic": "random",
|
||||
"attachment_uids": attachment_uids,
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
assert r.status_code == 200, r.text[:300]
|
||||
assert "/posts/" in r.url, r.url
|
||||
return r.url
|
||||
def _create_project_media(s, attachment_uids, title="Media Project"):
|
||||
r = s.post(
|
||||
f"{BASE_URL}/projects/create",
|
||||
data={
|
||||
"title": title,
|
||||
"description": "Project with media for gallery tests.",
|
||||
"project_type": "software",
|
||||
"platforms": "linux",
|
||||
"status": "In Development",
|
||||
"attachment_uids": attachment_uids,
|
||||
},
|
||||
allow_redirects=True,
|
||||
)
|
||||
assert r.status_code == 200, r.text[:300]
|
||||
assert "/projects/" in r.url, r.url
|
||||
return r.url
|
||||
def _media_json(session, username):
|
||||
r = session.get(f"{BASE_URL}/profile/{username}?tab=media", headers=JSON_media)
|
||||
assert r.status_code == 200, r.text[:300]
|
||||
return r.json()
|
||||
def _media_uids(session, username):
|
||||
return [m["uid"] for m in _media_json(session, username)["media"]]
|
||||
def _seed_media_via_browser(page, title="ui media"):
|
||||
up = page.request.post(
|
||||
f"{BASE_URL}/uploads/upload",
|
||||
multipart={
|
||||
"file": {
|
||||
"name": "pic.png",
|
||||
"mimeType": "image/png",
|
||||
"buffer": _png_bytes_media(),
|
||||
}
|
||||
},
|
||||
)
|
||||
assert up.ok, up.text()
|
||||
uid = up.json()["uid"]
|
||||
post = page.request.post(
|
||||
f"{BASE_URL}/posts/create",
|
||||
form={
|
||||
"content": "media for the ui gallery test",
|
||||
"title": title,
|
||||
"topic": "random",
|
||||
"attachment_uids": uid,
|
||||
},
|
||||
)
|
||||
assert post.ok, post.text()
|
||||
return uid
|
||||
def _media_uids_via_page(page, username):
|
||||
resp = page.request.get(f"{BASE_URL}/profile/{username}?tab=media", headers=JSON_media)
|
||||
return [m["uid"] for m in resp.json()["media"]]
|
||||
|
||||
|
||||
def test_purge_requires_admin(seeded_db):
|
||||
owner, name = _signup_media()
|
||||
uid = _upload_media(owner)
|
||||
_create_post_media(owner, uid)
|
||||
owner.post(f"{BASE_URL}/media/{uid}/delete", headers=JSON_media)
|
||||
member = _login_media(seeded_db, "bob")
|
||||
r = member.post(f"{BASE_URL}/admin/media/{uid}/purge", allow_redirects=False)
|
||||
assert r.status_code in (302, 303)
|
||||
|
||||
|
||||
def test_admin_purge_hard_deletes(seeded_db):
|
||||
owner, name = _signup_media()
|
||||
uid = _upload_media(owner)
|
||||
_create_post_media(owner, uid)
|
||||
file_url = next(m["url"] for m in _media_json(owner, name)["media"] if m["uid"] == uid)
|
||||
owner.post(f"{BASE_URL}/media/{uid}/delete", headers=JSON_media)
|
||||
|
||||
admin = _login_media(seeded_db, "alice")
|
||||
assert owner.get(f"{BASE_URL}{file_url}").status_code == 200
|
||||
r = admin.post(f"{BASE_URL}/admin/media/{uid}/purge", headers=JSON_media)
|
||||
assert r.status_code == 200
|
||||
# row gone (not in trash, cannot restore) and file removed from disk
|
||||
trash = admin.get(f"{BASE_URL}/admin/media", headers=JSON_media).json()
|
||||
assert all(m["uid"] != uid for m in trash["media"])
|
||||
assert owner.get(f"{BASE_URL}{file_url}").status_code == 404
|
||||
Reference in New Issue
Block a user