reapply fee migration

This commit is contained in:
9qeklajc
2026-07-25 23:42:50 +02:00
parent 1d4b8d7cb2
commit 344c3c5f21
2 changed files with 111 additions and 0 deletions
@@ -0,0 +1,47 @@
"""repair missing fee payout checkpoint columns
Revision ID: 9c4d8e2f1a6b
Revises: 7f2843d3f4e4
Create Date: 2026-07-25 00:00:00.000000
"""
from __future__ import annotations
import sqlalchemy as sa
from alembic import op
revision = "9c4d8e2f1a6b"
down_revision = "7f2843d3f4e4"
branch_labels = None
depends_on = None
def upgrade() -> None:
"""Repair databases stamped past the original checkpoint migration."""
conn = op.get_bind()
columns = {
column["name"] for column in sa.inspect(conn).get_columns("routstr_fees")
}
if "payout_in_progress_msats" not in columns:
op.add_column(
"routstr_fees",
sa.Column(
"payout_in_progress_msats",
sa.Integer(),
nullable=False,
server_default="0",
),
)
if "payout_started_at" not in columns:
op.add_column(
"routstr_fees",
sa.Column("payout_started_at", sa.Integer(), nullable=True),
)
def downgrade() -> None:
# The preceding revision already expects both columns. This migration only
# repairs schema drift, so downgrading it must preserve the expected schema.
pass
+64
View File
@@ -18,6 +18,37 @@ def _run_alembic(root: Path, database_url: str, revision: str) -> None:
)
def test_fresh_node_migrates_fee_payout_schema_to_head(tmp_path: Path) -> None:
root = Path(__file__).resolve().parents[2]
database_path = tmp_path / "fresh-node.db"
database_url = f"sqlite+aiosqlite:///{database_path}"
_run_alembic(root, database_url, "head")
with sqlite3.connect(database_path) as connection:
version = connection.execute(
"SELECT version_num FROM alembic_version"
).fetchone()
columns = {
row[1] for row in connection.execute("PRAGMA table_info(routstr_fees)")
}
fee = connection.execute(
"SELECT id, accumulated_msats, total_paid_msats, last_paid_at, "
"payout_in_progress_msats, payout_started_at FROM routstr_fees"
).fetchone()
assert version == ("9c4d8e2f1a6b",)
assert {
"id",
"accumulated_msats",
"total_paid_msats",
"last_paid_at",
"payout_in_progress_msats",
"payout_started_at",
} <= columns
assert fee == (1, 0, 0, None, 0, None)
def test_fee_payout_checkpoint_migration_preserves_existing_row(
tmp_path: Path,
) -> None:
@@ -44,3 +75,36 @@ def test_fee_payout_checkpoint_migration_preserves_existing_row(
).fetchone()
assert row == (5000, 1000, 123, 0, None)
def test_fee_payout_checkpoint_repair_restores_columns_missing_at_old_head(
tmp_path: Path,
) -> None:
root = Path(__file__).resolve().parents[2]
database_path = tmp_path / "migration.db"
database_url = f"sqlite+aiosqlite:///{database_path}"
old_head = "7f2843d3f4e4"
_run_alembic(root, database_url, old_head)
# Reproduce a database that was stamped to head after a duplicate-column or
# unknown-revision recovery skipped part of the migration chain.
with sqlite3.connect(database_path) as connection:
connection.execute("ALTER TABLE routstr_fees DROP COLUMN payout_started_at")
connection.execute(
"ALTER TABLE routstr_fees DROP COLUMN payout_in_progress_msats"
)
connection.commit()
_run_alembic(root, database_url, "head")
with sqlite3.connect(database_path) as connection:
columns = {
row[1] for row in connection.execute("PRAGMA table_info(routstr_fees)")
}
row = connection.execute(
"SELECT payout_in_progress_msats, payout_started_at "
"FROM routstr_fees WHERE id = 1"
).fetchone()
assert {"payout_in_progress_msats", "payout_started_at"} <= columns
assert row == (0, None)