Release: dev → main (first public release) #258
@@ -70,11 +70,21 @@ _CAPS = (
|
|||||||
|
|
||||||
|
|
||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
# The constraint goes first: it names `slots`, so dropping the column out
|
# The constraints go first: they name `slots`, so dropping the column out
|
||||||
# from under it fails on Postgres.
|
# from under them fails on Postgres.
|
||||||
op.drop_constraint("ck_worker_lane_slots_within_cap", "worker_lane", type_="check")
|
#
|
||||||
|
# `op.f()` around each name, and it is load-bearing. Without it alembic
|
||||||
|
# runs the name through Base.metadata's naming convention, which prepends
|
||||||
|
# `ck_worker_lane_` to a string that already carries it — and the DROP
|
||||||
|
# goes looking for `ck_worker_lane_ck_worker_lane_slots_within_cap`, which
|
||||||
|
# no database has. That is #3275 exactly, from the other direction:
|
||||||
|
# alembic 0088 had to RENAME four constraints created with the same
|
||||||
|
# doubling. Caught here by the integration lane, run 7365.
|
||||||
op.drop_constraint(
|
op.drop_constraint(
|
||||||
"ck_worker_lane_slots_non_negative", "worker_lane", type_="check",
|
op.f("ck_worker_lane_slots_within_cap"), "worker_lane", type_="check",
|
||||||
|
)
|
||||||
|
op.drop_constraint(
|
||||||
|
op.f("ck_worker_lane_slots_non_negative"), "worker_lane", type_="check",
|
||||||
)
|
)
|
||||||
op.drop_column("worker_lane", "slots")
|
op.drop_column("worker_lane", "slots")
|
||||||
op.drop_column("worker_lane", "enabled")
|
op.drop_column("worker_lane", "enabled")
|
||||||
|
|||||||
+17
-27
@@ -246,22 +246,16 @@ def test_an_unrecognised_queue_set_still_gets_a_true_label():
|
|||||||
# --- the model's invariant ---------------------------------------------------
|
# --- the model's invariant ---------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
def test_the_row_carries_exactly_one_constraint_now():
|
||||||
"slots,cap,ok",
|
"""`slots >= 0` and `slots <= slots_cap` went with the `slots` column on
|
||||||
[
|
2026-09-23 — there is one number left, and the only thing that can be
|
||||||
(0, 0, True),
|
wrong with it is being negative.
|
||||||
(1, 1, True),
|
|
||||||
(1, 4, True),
|
Asserted as the WHOLE set rather than as a membership check: a constraint
|
||||||
(5, 4, False), # slots above its own cap
|
left behind naming a dropped column is not a harmless leftover, it is a
|
||||||
(-1, 1, False), # negative slots
|
table the migration cannot have produced, and the model would then
|
||||||
(1, -1, False), # negative cap
|
describe a schema no database has.
|
||||||
],
|
"""
|
||||||
)
|
|
||||||
def test_worker_lane_check_constraints(slots, cap, ok):
|
|
||||||
"""The constraints live in the database, not only in the service, because
|
|
||||||
a row violating `slots <= slots_cap` is not a rejected request — it is a
|
|
||||||
lane the reconcile (step 3) will drive UP to a number the operator
|
|
||||||
capped."""
|
|
||||||
from backend.app.models import WorkerLane
|
from backend.app.models import WorkerLane
|
||||||
|
|
||||||
constraints = {
|
constraints = {
|
||||||
@@ -269,17 +263,13 @@ def test_worker_lane_check_constraints(slots, cap, ok):
|
|||||||
if hasattr(c, "sqltext")
|
if hasattr(c, "sqltext")
|
||||||
}
|
}
|
||||||
# The names carry the convention's `ck_worker_lane_` prefix ALREADY — the
|
# The names carry the convention's `ck_worker_lane_` prefix ALREADY — the
|
||||||
# model declares them bare and Base.metadata's naming_convention applies it.
|
# model declares them bare and Base.metadata's naming_convention applies
|
||||||
# Asserting the prefixed form is what pins the thing that actually went
|
# it. Asserting the prefixed form is what pins the thing that actually
|
||||||
# wrong once: alembic 0088 had to rename four constraints that shipped as
|
# went wrong once: alembic 0088 had to rename four constraints that
|
||||||
# `ck_x_ck_x_name`, because the migration pre-prefixed a name the
|
# shipped as `ck_x_ck_x_name`, because the migration pre-prefixed a name
|
||||||
# convention then prefixed again (#3275). A bare-name assertion here would
|
# the convention then prefixed again (#3275). A bare-name assertion here
|
||||||
# pass just as happily against a doubled one.
|
# would pass just as happily against a doubled one.
|
||||||
assert constraints == {
|
assert constraints == {"ck_worker_lane_cap_non_negative": "slots_cap >= 0"}
|
||||||
"ck_worker_lane_slots_non_negative": "slots >= 0",
|
|
||||||
"ck_worker_lane_cap_non_negative": "slots_cap >= 0",
|
|
||||||
"ck_worker_lane_slots_within_cap": "slots <= slots_cap",
|
|
||||||
}
|
|
||||||
for name in constraints:
|
for name in constraints:
|
||||||
assert not name.startswith("ck_worker_lane_ck_"), f"doubled prefix: {name}"
|
assert not name.startswith("ck_worker_lane_ck_"), f"doubled prefix: {name}"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user