227 lines
7.9 KiB
Python
227 lines
7.9 KiB
Python
|
|
# retoor <retoor@molodetz.nl>
|
||
|
|
|
||
|
|
import time
|
||
|
|
import requests
|
||
|
|
from tests.conftest import BASE_URL, login_user
|
||
|
|
from devplacepy.database import (
|
||
|
|
get_table,
|
||
|
|
get_primary_admin_uid,
|
||
|
|
invalidate_admins_cache,
|
||
|
|
refresh_snapshot,
|
||
|
|
)
|
||
|
|
from devplacepy.utils import clear_user_cache
|
||
|
|
|
||
|
|
_counter = [0]
|
||
|
|
|
||
|
|
|
||
|
|
def _make_admin():
|
||
|
|
_counter[0] += 1
|
||
|
|
name = f"ecm{int(time.time() * 1000)}{_counter[0]}"
|
||
|
|
password = "secret123"
|
||
|
|
requests.post(
|
||
|
|
f"{BASE_URL}/auth/signup",
|
||
|
|
data={
|
||
|
|
"username": name,
|
||
|
|
"email": f"{name}@t.dev",
|
||
|
|
"password": password,
|
||
|
|
"confirm_password": password,
|
||
|
|
},
|
||
|
|
allow_redirects=True,
|
||
|
|
)
|
||
|
|
refresh_snapshot()
|
||
|
|
row = get_table("users").find_one(username=name)
|
||
|
|
get_table("users").update({"uid": row["uid"], "role": "Admin"}, ["uid"])
|
||
|
|
clear_user_cache(row["uid"])
|
||
|
|
invalidate_admins_cache()
|
||
|
|
return {
|
||
|
|
"email": f"{name}@t.dev",
|
||
|
|
"password": password,
|
||
|
|
"uid": row["uid"],
|
||
|
|
"api_key": row["api_key"],
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def _demote_existing_admins():
|
||
|
|
existing = [r["uid"] for r in get_table("users").find(role="Admin")]
|
||
|
|
for uid in existing:
|
||
|
|
get_table("users").update({"uid": uid, "role": "Member"}, ["uid"])
|
||
|
|
invalidate_admins_cache()
|
||
|
|
return existing
|
||
|
|
|
||
|
|
|
||
|
|
def _restore_admins(uids):
|
||
|
|
for uid in uids:
|
||
|
|
get_table("users").update({"uid": uid, "role": "Admin"}, ["uid"])
|
||
|
|
invalidate_admins_cache()
|
||
|
|
|
||
|
|
|
||
|
|
def _create_project(api_key, title, is_private=False):
|
||
|
|
data = {
|
||
|
|
"title": title,
|
||
|
|
"description": "e2e container manage isolation",
|
||
|
|
"project_type": "software",
|
||
|
|
"status": "In Development",
|
||
|
|
}
|
||
|
|
if is_private:
|
||
|
|
data["is_private"] = "on"
|
||
|
|
r = requests.post(
|
||
|
|
f"{BASE_URL}/projects/create",
|
||
|
|
headers={"Accept": "application/json", "X-API-KEY": api_key},
|
||
|
|
data=data,
|
||
|
|
)
|
||
|
|
assert r.status_code == 200, r.text
|
||
|
|
return r.json()["data"]
|
||
|
|
|
||
|
|
|
||
|
|
def _insert_instance(project_uid, created_by):
|
||
|
|
uid = f"ecm-{int(time.time() * 1000000)}"
|
||
|
|
get_table("instances").insert(
|
||
|
|
{
|
||
|
|
"uid": uid,
|
||
|
|
"slug": uid,
|
||
|
|
"name": "e2e-manage-test",
|
||
|
|
"project_uid": project_uid,
|
||
|
|
"created_by": created_by,
|
||
|
|
"owner_uid": "",
|
||
|
|
"status": "stopped",
|
||
|
|
"container_id": "",
|
||
|
|
"workspace_dir": "",
|
||
|
|
"restart_policy": "never",
|
||
|
|
"deleted_at": None,
|
||
|
|
"deleted_by": None,
|
||
|
|
}
|
||
|
|
)
|
||
|
|
refresh_snapshot()
|
||
|
|
return uid
|
||
|
|
|
||
|
|
|
||
|
|
def _cleanup(inst_uid):
|
||
|
|
get_table("instances").delete(uid=inst_uid)
|
||
|
|
refresh_snapshot()
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_list_shows_view_only_for_non_owned_public_instance(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
other = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage List Public", is_private=False)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, other)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
|
||
|
|
row = page.locator(f"tr.cm-row[data-uid='{inst_uid}']")
|
||
|
|
row.wait_for(state="visible", timeout=15000)
|
||
|
|
assert "view only" in row.inner_text().lower()
|
||
|
|
assert row.locator("[data-cm-action='delete']").count() == 0
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_list_shows_actions_for_owner(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage List Owner", is_private=False)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, owner)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
|
||
|
|
row = page.locator(f"tr.cm-row[data-uid='{inst_uid}']")
|
||
|
|
row.wait_for(state="visible", timeout=15000)
|
||
|
|
assert row.locator("[data-cm-action='delete']").count() == 1
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_list_excludes_others_private_project_instance(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
other = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage List Private", is_private=True)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, other)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
|
||
|
|
assert page.locator(f"tr.cm-row[data-uid='{inst_uid}']").count() == 0
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_detail_page_view_only_hides_manage_controls(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
other = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage Detail Public", is_private=False)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, other)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
|
||
|
|
actions = page.locator("#ci-actions")
|
||
|
|
actions.wait_for(state="visible")
|
||
|
|
assert "view only" in actions.inner_text().lower()
|
||
|
|
assert page.locator("#ci-term-toggle").count() == 0
|
||
|
|
assert page.locator("[data-modal='ci-schedule-modal']").count() == 0
|
||
|
|
assert page.locator("a:has-text('Edit configuration')").count() == 0
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_detail_page_owner_sees_manage_controls(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage Detail Owner", is_private=False)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, owner)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
|
||
|
|
page.locator("[data-modal='ci-schedule-modal']").wait_for(state="visible")
|
||
|
|
assert page.locator("a:has-text('Edit configuration')").count() == 1
|
||
|
|
assert page.locator("#ci-term-toggle").count() == 1
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_detail_page_404_for_non_viewer_on_private_project(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
other = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage Detail Private", is_private=True)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, other)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
|
||
|
|
assert page.is_visible("text=Not Found") or page.is_visible("text=404")
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_admin_edit_page_redirects_non_owner_to_detail(page, app_server):
|
||
|
|
owner = _make_admin()
|
||
|
|
other = _make_admin()
|
||
|
|
project = _create_project(owner["api_key"], "E2E Manage Edit Redirect", is_private=False)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, other)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers/{inst_uid}/edit", wait_until="domcontentloaded")
|
||
|
|
page.wait_for_url(f"**/admin/containers/{inst_uid}", wait_until="domcontentloaded")
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
|
||
|
|
|
||
|
|
def test_primary_admin_sees_and_manages_others_private_instance(page, app_server):
|
||
|
|
restore = _demote_existing_admins()
|
||
|
|
try:
|
||
|
|
primary = _make_admin()
|
||
|
|
owner = _make_admin()
|
||
|
|
assert get_primary_admin_uid() == primary["uid"]
|
||
|
|
project = _create_project(
|
||
|
|
owner["api_key"], "E2E Manage Primary Private", is_private=True
|
||
|
|
)
|
||
|
|
inst_uid = _insert_instance(project["uid"], owner["uid"])
|
||
|
|
try:
|
||
|
|
login_user(page, primary)
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers", wait_until="domcontentloaded")
|
||
|
|
row = page.locator(f"tr.cm-row[data-uid='{inst_uid}']")
|
||
|
|
row.wait_for(state="visible", timeout=15000)
|
||
|
|
assert row.locator("[data-cm-action='delete']").count() == 1
|
||
|
|
|
||
|
|
page.goto(f"{BASE_URL}/admin/containers/{inst_uid}", wait_until="domcontentloaded")
|
||
|
|
page.locator("a:has-text('Edit configuration')").wait_for(state="visible")
|
||
|
|
finally:
|
||
|
|
_cleanup(inst_uid)
|
||
|
|
finally:
|
||
|
|
_restore_admins(restore)
|