add blocker presets
This commit is contained in:
12 files changed
+426
-83
No files matched your search
@@ -0,0 +1,85 @@
|
||||
"""Regression test for a schema-drift bug: a database created by an older
|
||||
build of the app still had a `completed_here NOT NULL` column on `tasks`
|
||||
that a later refactor dropped from the model. `create_all` never alters an
|
||||
existing table, so every task insert on such a database failed with
|
||||
|
||||
IntegrityError: null value in column "completed_here" ... violates
|
||||
not-null constraint
|
||||
|
||||
which, since task refresh runs from both the scheduler and `/api/tasks`
|
||||
endpoints, looked like "everything 500s". `app.db.init_db` now reconciles
|
||||
known-dead columns after `create_all`; this pins that behaviour down.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from app.db import SessionLocal, engine, init_db
|
||||
from app.models import TaskRecord
|
||||
|
||||
|
||||
def _simulate_pre_refactor_database() -> None:
|
||||
"""Recreate the exact drift: today's `tasks` table, plus the long-gone
|
||||
`completed_here` column, `NOT NULL` and with no database-side default —
|
||||
just like a database that has been running since before the column was
|
||||
removed from the model.
|
||||
"""
|
||||
with engine.begin() as conn:
|
||||
conn.execute(text("DROP TABLE IF EXISTS tasks"))
|
||||
conn.execute(
|
||||
text(
|
||||
"""
|
||||
CREATE TABLE tasks (
|
||||
id INTEGER PRIMARY KEY,
|
||||
source VARCHAR(32) NOT NULL,
|
||||
external_id VARCHAR(128) NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
url TEXT,
|
||||
project TEXT,
|
||||
status VARCHAR(64),
|
||||
priority VARCHAR(32),
|
||||
due_date DATE,
|
||||
start_date DATE,
|
||||
labels JSON,
|
||||
raw JSON,
|
||||
is_done BOOLEAN NOT NULL DEFAULT 0,
|
||||
completed_at DATETIME,
|
||||
completed_date DATE,
|
||||
completed_here BOOLEAN NOT NULL,
|
||||
estimated_pomodoros INTEGER,
|
||||
pinned BOOLEAN NOT NULL DEFAULT 0,
|
||||
first_seen_at DATETIME NOT NULL,
|
||||
last_seen_at DATETIME NOT NULL,
|
||||
stale BOOLEAN NOT NULL DEFAULT 0
|
||||
)
|
||||
"""
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_init_db_drops_the_dead_not_null_column(session):
|
||||
_simulate_pre_refactor_database()
|
||||
|
||||
init_db()
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
# This is exactly what `tasks_service._upsert` + `refresh_tasks` do on
|
||||
# a newly-seen task: insert a row without ever mentioning the column
|
||||
# the model no longer has.
|
||||
db.add(TaskRecord(source="jira", external_id="VPN-48", title="Renew VPN"))
|
||||
db.commit() # pre-fix: IntegrityError (null value in "completed_here")
|
||||
|
||||
stored = db.query(TaskRecord).filter_by(external_id="VPN-48").one()
|
||||
assert stored.title == "Renew VPN"
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_init_db_is_a_no_op_once_the_column_is_already_gone(session):
|
||||
"""Running it twice (every boot does) must not blow up when there is
|
||||
nothing left to drop."""
|
||||
init_db()
|
||||
init_db()
|
||||
Reference in new issue
Block a user