Load the test schema once and truncate data between files.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3c0213ae74
commit
79e4fd0d4b
|
|
@ -59,7 +59,7 @@ jobs:
|
||||||
export KANSHO_PROVIDER_KEY=
|
export KANSHO_PROVIDER_KEY=
|
||||||
export KANSHO_DETECT_PROVIDER_KEY=
|
export KANSHO_DETECT_PROVIDER_KEY=
|
||||||
pip install -q -r requirements-dev.txt
|
pip install -q -r requirements-dev.txt
|
||||||
python -m pytest tests -m "not slow" -ra -vv --tb=short
|
python -m pytest tests -m "not slow" -ra --tb=short
|
||||||
'
|
'
|
||||||
|
|
||||||
smoke-dev:
|
smoke-dev:
|
||||||
|
|
|
||||||
|
|
@ -555,16 +555,21 @@ def _seed_runtime(conn: Any) -> None:
|
||||||
seed_generation_instructions(conn)
|
seed_generation_instructions(conn)
|
||||||
|
|
||||||
|
|
||||||
|
def refresh_runtime_seed() -> None:
|
||||||
|
"""Re-seed catalog rows after a data truncate. Schema must already exist."""
|
||||||
|
with get_db() as conn:
|
||||||
|
_seed_runtime(conn)
|
||||||
|
from writing_profile_store import bootstrap_from_existing
|
||||||
|
|
||||||
|
bootstrap_from_existing()
|
||||||
|
|
||||||
|
|
||||||
def init_db() -> None:
|
def init_db() -> None:
|
||||||
if use_postgres():
|
if use_postgres():
|
||||||
from db_init import ensure_postgres_ready
|
from db_init import ensure_postgres_ready
|
||||||
|
|
||||||
ensure_postgres_ready()
|
ensure_postgres_ready()
|
||||||
with get_db() as conn:
|
refresh_runtime_seed()
|
||||||
_seed_runtime(conn)
|
|
||||||
from writing_profile_store import bootstrap_from_existing
|
|
||||||
|
|
||||||
bootstrap_from_existing()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
schema = SCHEMA_PATH.read_text(encoding="utf-8")
|
schema = SCHEMA_PATH.read_text(encoding="utf-8")
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,13 @@ SQLITE_HISTORY_MIGRATIONS = (
|
||||||
"021_voice_legacy_immutable",
|
"021_voice_legacy_immutable",
|
||||||
)
|
)
|
||||||
_LEADING_DIGITS = re.compile(r"^(\d{3})_.*\.sql$")
|
_LEADING_DIGITS = re.compile(r"^(\d{3})_.*\.sql$")
|
||||||
|
_schema_ready = False
|
||||||
|
|
||||||
|
|
||||||
|
def mark_schema_dirty() -> None:
|
||||||
|
"""Call after DROP SCHEMA so the next init_db reloads schema.sql."""
|
||||||
|
global _schema_ready
|
||||||
|
_schema_ready = False
|
||||||
|
|
||||||
|
|
||||||
def _connect_raw():
|
def _connect_raw():
|
||||||
|
|
@ -137,13 +144,17 @@ def apply_schema_and_migrations() -> None:
|
||||||
|
|
||||||
|
|
||||||
def ensure_postgres_ready() -> None:
|
def ensure_postgres_ready() -> None:
|
||||||
|
global _schema_ready
|
||||||
if not use_postgres():
|
if not use_postgres():
|
||||||
return
|
return
|
||||||
|
if _schema_ready:
|
||||||
|
return
|
||||||
wait_for_postgres()
|
wait_for_postgres()
|
||||||
try:
|
try:
|
||||||
apply_schema_and_migrations()
|
apply_schema_and_migrations()
|
||||||
except Exception:
|
except Exception:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
_schema_ready = True
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
"""pytest runner for the existing test_*.py scripts.
|
"""pytest runner for the existing test_*.py scripts.
|
||||||
|
|
||||||
Each file stays one case (`main()`) until it is split into native pytest
|
Each file stays one case (`main()`) until it is split into native pytest
|
||||||
functions. Integration files reset `kansho_test` only; `kansho_dev` is never
|
functions. Schema is loaded once per session; each integration file only
|
||||||
the test target. Provider keys and fake flags are restored per file so the
|
truncates data so kansho_dev is never the target and CI does not reload
|
||||||
shared pytest process matches the old one-script-per-process isolation.
|
schema.sql twenty times.
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
@ -21,6 +21,7 @@ from tests.harness import ( # noqa: E402
|
||||||
apply_module_env,
|
apply_module_env,
|
||||||
is_postgres_test_database,
|
is_postgres_test_database,
|
||||||
prepare_test_env,
|
prepare_test_env,
|
||||||
|
reset_postgres_data,
|
||||||
reset_postgres_schema,
|
reset_postgres_schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -64,6 +65,20 @@ class KanshoScriptModule(pytest.Module):
|
||||||
yield pytest.Function.from_parent(self, name="test_main", callobj=main)
|
yield pytest.Function.from_parent(self, name="test_main", callobj=main)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def _session_postgres():
|
||||||
|
if not is_postgres_test_database():
|
||||||
|
pytest.skip(
|
||||||
|
"integration requires KANSHO_DB_BACKEND=postgres and DB_NAME ending _test "
|
||||||
|
"(Gitea: kansho_test on the Dev Postgres, never kansho_dev)"
|
||||||
|
)
|
||||||
|
reset_postgres_schema()
|
||||||
|
from db import init_db
|
||||||
|
|
||||||
|
init_db()
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module", autouse=True)
|
@pytest.fixture(scope="module", autouse=True)
|
||||||
def _module_backend(request: pytest.FixtureRequest):
|
def _module_backend(request: pytest.FixtureRequest):
|
||||||
source = Path(str(request.path))
|
source = Path(str(request.path))
|
||||||
|
|
@ -74,15 +89,8 @@ def _module_backend(request: pytest.FixtureRequest):
|
||||||
if stem in UNIT_MODULES:
|
if stem in UNIT_MODULES:
|
||||||
yield
|
yield
|
||||||
return
|
return
|
||||||
if not is_postgres_test_database():
|
request.getfixturevalue("_session_postgres")
|
||||||
pytest.skip(
|
reset_postgres_data()
|
||||||
"integration requires KANSHO_DB_BACKEND=postgres and DB_NAME ending _test "
|
|
||||||
"(Gitea: kansho_test on the Dev Postgres, never kansho_dev)"
|
|
||||||
)
|
|
||||||
reset_postgres_schema()
|
|
||||||
from db import init_db
|
|
||||||
|
|
||||||
init_db()
|
|
||||||
yield
|
yield
|
||||||
finally:
|
finally:
|
||||||
os.environ.clear()
|
os.environ.clear()
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ def _require_test_database() -> None:
|
||||||
def reset_postgres_schema() -> None:
|
def reset_postgres_schema() -> None:
|
||||||
import psycopg
|
import psycopg
|
||||||
|
|
||||||
|
from db_init import mark_schema_dirty
|
||||||
from sql_compat import postgres_connect_kwargs
|
from sql_compat import postgres_connect_kwargs
|
||||||
|
|
||||||
kwargs = postgres_connect_kwargs()
|
kwargs = postgres_connect_kwargs()
|
||||||
|
|
@ -103,6 +104,36 @@ def reset_postgres_schema() -> None:
|
||||||
conn.execute("GRANT ALL ON SCHEMA public TO CURRENT_USER")
|
conn.execute("GRANT ALL ON SCHEMA public TO CURRENT_USER")
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
mark_schema_dirty()
|
||||||
|
|
||||||
|
|
||||||
|
def reset_postgres_data() -> None:
|
||||||
|
"""Clear rows on kansho_test without reloading schema.sql."""
|
||||||
|
import psycopg
|
||||||
|
|
||||||
|
from sql_compat import postgres_connect_kwargs
|
||||||
|
|
||||||
|
kwargs = postgres_connect_kwargs()
|
||||||
|
if "conninfo" in kwargs:
|
||||||
|
conn = psycopg.connect(kwargs["conninfo"], autocommit=True)
|
||||||
|
else:
|
||||||
|
conn = psycopg.connect(autocommit=True, **kwargs)
|
||||||
|
try:
|
||||||
|
rows = conn.execute(
|
||||||
|
"""
|
||||||
|
SELECT tablename FROM pg_tables
|
||||||
|
WHERE schemaname = 'public' AND tablename <> 'schema_migrations'
|
||||||
|
"""
|
||||||
|
).fetchall()
|
||||||
|
names = [row[0] for row in rows]
|
||||||
|
if names:
|
||||||
|
joined = ", ".join('"' + name.replace('"', '""') + '"' for name in names)
|
||||||
|
conn.execute(f"TRUNCATE TABLE {joined} RESTART IDENTITY CASCADE")
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
from db import refresh_runtime_seed
|
||||||
|
|
||||||
|
refresh_runtime_seed()
|
||||||
|
|
||||||
|
|
||||||
def configure_test_engine() -> None:
|
def configure_test_engine() -> None:
|
||||||
|
|
|
||||||
|
|
@ -209,10 +209,9 @@ def main() -> None:
|
||||||
test_compile_flags()
|
test_compile_flags()
|
||||||
test_budget_omission_in_effective_trace()
|
test_budget_omission_in_effective_trace()
|
||||||
|
|
||||||
from tests.harness import reset_postgres_schema
|
from tests.harness import reset_postgres_data
|
||||||
|
|
||||||
reset_postgres_schema()
|
reset_postgres_data()
|
||||||
init_db()
|
|
||||||
reset_debug()
|
reset_debug()
|
||||||
with TestClient(app) as client:
|
with TestClient(app) as client:
|
||||||
setup = client.post(
|
setup = client.post(
|
||||||
|
|
|
||||||
|
|
@ -268,10 +268,9 @@ def test_later_semantic_seed_creates_successor() -> None:
|
||||||
|
|
||||||
|
|
||||||
def test_legacy_generate_trace_and_prompt() -> None:
|
def test_legacy_generate_trace_and_prompt() -> None:
|
||||||
from tests.harness import reset_postgres_schema
|
from tests.harness import reset_postgres_data
|
||||||
|
|
||||||
reset_postgres_schema()
|
reset_postgres_data()
|
||||||
init_db()
|
|
||||||
client = TestClient(app)
|
client = TestClient(app)
|
||||||
setup = client.post(
|
setup = client.post(
|
||||||
"/api/auth/setup",
|
"/api/auth/setup",
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ Gateway-Verfahren und offener Security Layer: `privacy_gateway.md` §9.1–9.2 u
|
||||||
|
|
||||||
Tests beweisen API-Verträge und Invarianten, nicht Dialogqualität.
|
Tests beweisen API-Verträge und Invarianten, nicht Dialogqualität.
|
||||||
|
|
||||||
**Additiv 2026-09-07:** pytest ist der Backend-Runner (`backend/pytest.ini`). Gitea führt `python -m pytest tests -m "not slow"` nach erfolgreichem Dev-Deploy auf `kansho_test` aus. `scripts/test-mvp.ps1` wrappt denselben Aufruf lokal. Unit-Marker laufen ohne Postgres; Integration nie gegen `kansho_dev`.
|
**Additiv 2026-09-07:** pytest ist der Backend-Runner (`backend/pytest.ini`). Gitea führt `python -m pytest tests -m "not slow"` nach erfolgreichem Dev-Deploy auf `kansho_test` aus. `scripts/test-mvp.ps1` wrappt denselben Aufruf lokal. Unit-Marker laufen ohne Postgres; Integration nie gegen `kansho_dev`. Schema einmal pro Lauf, dazwischen nur Daten-Truncate — nicht 22× `schema.sql`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user