feat: add user_id index to profiles table for faster lookups
The profiles table previously lacked an index on the user_id column, causing full table scans during user lookups. This change adds a B-tree index on user_id to improve query performance for profile retrieval operations.
This commit is contained in:
@@ -1,18 +1,8 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from playwright.sync_api import expect
|
||||
|
||||
_CROSS_PROCESS_CACHE_SKIP = (
|
||||
"Cross-process customization propagation has a 10s cache-version staleness "
|
||||
"window (database._cache_version_cache TTL). This test seeds an override "
|
||||
"in-process and asserts the separate uvicorn server process renders it "
|
||||
"immediately, which races that window and is flaky on any multi-process "
|
||||
"runner (local, server, and CI). The toggle UI/DB-state assertions are "
|
||||
"covered by the other tests in this module."
|
||||
)
|
||||
|
||||
from tests.conftest import BASE_URL
|
||||
from devplacepy.database import (
|
||||
CUSTOMIZATION_GLOBAL_SCOPE,
|
||||
@@ -59,7 +49,6 @@ def test_owner_sees_toggles_and_initial_state(bob):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason=_CROSS_PROCESS_CACHE_SKIP)
|
||||
def test_global_toggle_suppresses_rendering_and_persists(bob):
|
||||
page, user = bob
|
||||
uid = _user(user["username"])["uid"]
|
||||
@@ -89,7 +78,6 @@ def test_global_toggle_suppresses_rendering_and_persists(bob):
|
||||
assert sentinel in page.content()
|
||||
|
||||
|
||||
@pytest.mark.skip(reason=_CROSS_PROCESS_CACHE_SKIP)
|
||||
def test_pagetype_toggle_is_independent(bob):
|
||||
page, user = bob
|
||||
uid = _user(user["username"])["uid"]
|
||||
|
||||
@@ -88,6 +88,34 @@ def test_append_without_trailing_adds_newline_between():
|
||||
assert pf.read_file(pid, "g.txt")["content"] == "one\ntwo"
|
||||
|
||||
|
||||
def test_append_honors_content_trailing_newline():
|
||||
pid, u = _project()
|
||||
pf.write_text_file(pid, u, "g.txt", "a\nb")
|
||||
pf.append_lines(pid, "g.txt", "c\nd\n")
|
||||
assert pf.read_file(pid, "g.txt")["content"] == "a\nb\nc\nd\n"
|
||||
|
||||
|
||||
def test_replace_last_line_honors_content_trailing_newline():
|
||||
pid, u = _project()
|
||||
pf.write_text_file(pid, u, "f.txt", "a\nb\nc")
|
||||
pf.replace_lines(pid, "f.txt", 3, 3, "C\n")
|
||||
assert pf.read_file(pid, "f.txt")["content"] == "a\nb\nC\n"
|
||||
|
||||
|
||||
def test_insert_at_end_honors_content_trailing_newline():
|
||||
pid, u = _project()
|
||||
pf.write_text_file(pid, u, "f.txt", "a\nb")
|
||||
pf.insert_lines(pid, "f.txt", 3, "c\n")
|
||||
assert pf.read_file(pid, "f.txt")["content"] == "a\nb\nc\n"
|
||||
|
||||
|
||||
def test_interior_replace_does_not_add_trailing_newline():
|
||||
pid, u = _project()
|
||||
pf.write_text_file(pid, u, "f.txt", "a\nb\nc\nd")
|
||||
pf.replace_lines(pid, "f.txt", 2, 2, "X\n")
|
||||
assert pf.read_file(pid, "f.txt")["content"] == "a\nX\nc\nd"
|
||||
|
||||
|
||||
def test_line_ops_reject_missing_dir_and_binary():
|
||||
pid, u = _project()
|
||||
pf.make_dir(pid, u, "adir")
|
||||
|
||||
@@ -306,6 +306,43 @@ def test_delete_project_works_when_readonly(app_server):
|
||||
)
|
||||
|
||||
|
||||
def test_owner_can_edit_project(app_server):
|
||||
_, _, key = _signup()
|
||||
slug = _create_project(key, "Editable Via Api")["slug"]
|
||||
r = requests.post(
|
||||
f"{BASE_URL}/projects/edit/{slug}",
|
||||
headers=_h(key),
|
||||
data={
|
||||
"title": "Edited Via Api",
|
||||
"description": "updated description body",
|
||||
"project_type": "website",
|
||||
"status": "Released",
|
||||
"platforms": "Linux,Web",
|
||||
},
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert r.status_code == 200 and r.json()["ok"] is True
|
||||
row = get_table("projects").find_one(slug=slug)
|
||||
assert row["title"] == "Edited Via Api"
|
||||
assert row["status"] == "Released"
|
||||
assert row["project_type"] == "website"
|
||||
assert row["platforms"] == "Linux,Web"
|
||||
|
||||
|
||||
def test_non_owner_cannot_edit_project(app_server):
|
||||
_, _, owner_key = _signup()
|
||||
slug = _create_project(owner_key, "Owner Edit Guard")["slug"]
|
||||
_, _, other_key = _signup()
|
||||
r = requests.post(
|
||||
f"{BASE_URL}/projects/edit/{slug}",
|
||||
headers=_h(other_key),
|
||||
data={"title": "Hijacked", "description": "should not persist"},
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert r.status_code == 403
|
||||
assert get_table("projects").find_one(slug=slug)["title"] == "Owner Edit Guard"
|
||||
|
||||
|
||||
# ---------- read-only: service layer enforcement ----------
|
||||
|
||||
|
||||
@@ -354,3 +391,33 @@ def test_is_confirmed_accepts_common_truthy():
|
||||
assert _is_confirmed({"confirm": "yes"})
|
||||
assert not _is_confirmed({"confirm": ""})
|
||||
assert not _is_confirmed({})
|
||||
|
||||
|
||||
def test_delete_actions_require_confirmation():
|
||||
assert confirmation_error("project_delete_file", {"path": "a.py"}) is not None
|
||||
assert confirmation_error("project_delete_file", {"path": "a.py", "confirm": "true"}) is None
|
||||
assert confirmation_error("delete_project", {"project_slug": "p"}) is not None
|
||||
assert confirmation_error("delete_project", {"project_slug": "p", "confirm": "true"}) is None
|
||||
|
||||
|
||||
def test_container_delete_requires_confirmation_but_not_other_actions():
|
||||
assert confirmation_error("container_instance_action", {"action": "delete"}) is not None
|
||||
assert confirmation_error("container_instance_action", {"action": "restart"}) is None
|
||||
assert confirmation_error("container_instance_action", {"action": "start"}) is None
|
||||
|
||||
|
||||
def test_destructive_container_exec_requires_confirmation():
|
||||
assert confirmation_error("container_exec", {"command": "rm -f /app/cms/cms.db"}) is not None
|
||||
assert confirmation_error("container_exec", {"command": "sudo rm -rf /app"}) is not None
|
||||
assert confirmation_error("container_exec", {"command": "find . -delete"}) is not None
|
||||
assert confirmation_error("container_exec", {"command": "echo x > /etc/hosts"}) is not None
|
||||
assert (
|
||||
confirmation_error("container_exec", {"command": "rm -rf /app", "confirm": "true"})
|
||||
is None
|
||||
)
|
||||
|
||||
|
||||
def test_benign_container_exec_runs_without_confirmation():
|
||||
assert confirmation_error("container_exec", {"command": "pip install requests"}) is None
|
||||
assert confirmation_error("container_exec", {"command": "ls -la /app"}) is None
|
||||
assert confirmation_error("container_exec", {"command": "grep -rm 5 foo ."}) is None
|
||||
|
||||
+57
-1
@@ -82,13 +82,69 @@ def test_delete_own_project(alice):
|
||||
page, _ = alice
|
||||
_create_project(page, "Deletable Project XYZ")
|
||||
proj_url = page.url
|
||||
page.locator("form[action*='/projects/delete/'] button").click()
|
||||
page.locator(".project-actions-more").click()
|
||||
page.locator(".context-menu-item:has-text('Delete')").click()
|
||||
page.locator(".dialog-overlay.visible .dialog-confirm").click()
|
||||
page.wait_for_url(f"{BASE_URL}/projects", wait_until="domcontentloaded")
|
||||
resp = page.goto(proj_url, wait_until="domcontentloaded")
|
||||
assert resp.status == 404
|
||||
|
||||
|
||||
def test_project_edit_button(alice):
|
||||
page, _ = alice
|
||||
_create_project(page, "Editable Project ABC")
|
||||
page.locator(".project-actions-more").click()
|
||||
expect(page.locator(".context-menu-item:has-text('Edit')")).to_be_visible()
|
||||
|
||||
|
||||
def test_project_edit_modal_prefills(alice):
|
||||
page, _ = alice
|
||||
_create_project(page, "Edit Modal Project")
|
||||
page.locator(".project-actions-more").click()
|
||||
page.locator(".context-menu-item:has-text('Edit')").click()
|
||||
assert page.is_visible("h3:has-text('Edit Project')")
|
||||
expect(page.locator("#edit-project-title")).to_have_value("Edit Modal Project")
|
||||
expect(page.locator("#platforms-tags .platform-tag:has-text('PC')")).to_be_visible()
|
||||
|
||||
|
||||
def test_project_edit_submit(alice):
|
||||
page, _ = alice
|
||||
_create_project(page, "Original Project Title")
|
||||
proj_url = page.url
|
||||
page.locator(".project-actions-more").click()
|
||||
page.locator(".context-menu-item:has-text('Edit')").click()
|
||||
page.fill("#edit-project-title", "Edited Project Title")
|
||||
page.fill("#edit-project-description", "Edited project description body")
|
||||
page.click("button:has-text('Save Changes')")
|
||||
expect(
|
||||
page.locator(".project-detail-title:has-text('Edited Project Title')")
|
||||
).to_be_visible()
|
||||
assert page.url.rstrip("/") == proj_url.rstrip("/")
|
||||
|
||||
|
||||
def test_project_edit_status_change(alice):
|
||||
page, _ = alice
|
||||
_create_project(page, "Status Change Project")
|
||||
page.locator(".project-actions-more").click()
|
||||
page.locator(".context-menu-item:has-text('Edit')").click()
|
||||
page.check("#edit-project-modal input[value='Released']")
|
||||
page.click("button:has-text('Save Changes')")
|
||||
expect(page.locator(".project-status:has-text('Released')")).to_be_visible()
|
||||
|
||||
|
||||
def test_project_edit_hidden_for_non_owner(alice, bob):
|
||||
page, _ = alice
|
||||
_create_project(page, "Owner Only Edit Project")
|
||||
proj_url = page.url
|
||||
bob_page, _ = bob
|
||||
bob_page.goto(proj_url, wait_until="domcontentloaded")
|
||||
bob_page.locator(".project-actions-more").click()
|
||||
expect(
|
||||
bob_page.locator(".context-menu-item:has-text('Download zip')")
|
||||
).to_be_visible()
|
||||
expect(bob_page.locator(".context-menu-item:has-text('Edit')")).to_have_count(0)
|
||||
|
||||
|
||||
def test_project_detail_share_button(alice):
|
||||
page, _ = alice
|
||||
page.goto(f"{BASE_URL}/projects", wait_until="domcontentloaded")
|
||||
|
||||
@@ -34,7 +34,7 @@ def test_oversized_post_content_rejected(app_server):
|
||||
s = _session()
|
||||
r = s.post(
|
||||
f"{BASE_URL}/posts/create",
|
||||
data={"content": "x" * 2001, "topic": "random"},
|
||||
data={"content": "x" * 125001, "topic": "random"},
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert r.status_code in (302, 303, 400)
|
||||
|
||||
Reference in New Issue
Block a user