From 71c98c50324016a22cda8850bba00f2e6ac92b9f Mon Sep 17 00:00:00 2001 From: savsis Date: Mon, 14 Sep 2026 00:57:56 +0500 Subject: [PATCH] test: verify backup/restore actually undoes branding, live settings and held subscriptions together MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not a new feature — a checkpoint after three commits in a row (plan pricing/HWID live-settings, branding + client site, subscription hold) that all touched adjacent ground, none of which had been exercised against backup/restore since. backup.py itself needed zero changes — it already does a full sqlite-level snapshot plus a raw .env copy, so by design any new column or .env key is automatically covered without per-feature updates. That's exactly the kind of claim worth actually proving instead of assuming, especially for a "restore my database" feature — if it silently missed something, the admin would only find out when they needed it most. Verified end to end against a real isolated sqlite db (not mocked): set a custom brand name, a price override, HWID settings, and held one of two subscriptions — snapshot — mutated all of that further (new brand name, new price, HWID back off, resumed the held subscription, granted a third one) — restored from the snapshot — confirmed every single value reverted to exactly what it was at snapshot time, including held_at surviving the round-trip (the held subscription comes back held, not silently resumed) and the newer third subscription being gone. 23 checks, all passing on the first run — backup/restore's "it's a full snapshot, not a selective export" design held up exactly as intended. Added this as a permanent CI step (not just a local script) so future changes to any of these three features get caught if they ever break this interaction — ran the step's exact extracted content locally before committing, same as every other CI addition tonight. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/ci.yml | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0af3c41..5d2446e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -288,3 +288,67 @@ jobs: print("live settings: prices/HWID/credential-rotation all apply with zero reimport OK") PYEOF + + - name: Smoke test backup/restore round-trip covers branding + live settings + held subscriptions + env: + BOT_TOKEN: "123456789:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + BOT_USERNAME: "x" + ADMIN_IDS: "1" + ADMIN_PANEL_PASSWORD: "ci-test-password-not-real" + PANEL_DOMAIN: "panel.test" + SUB_DOMAIN: "sub.test" + SITE_DOMAIN: "test" + XRAY_PUBLIC_KEY: "x" + XRAY_SHORT_ID_TCP: "x" + XRAY_SHORT_ID_GRPC: "x" + XRAY_SHORT_ID_XHTTP: "x" + run: | + python - << 'PYEOF' + import backup + import db + import legal + import settings + + db.init_db() + db.create_node("n1", "Node One", "managed", "1.1.1.1", 443, "pub1", "sid1", "sni1", "xtls-rprx-vision") + + sub_a = db.create_subscription(111, "n1", 30, "1m", source="bot") + sub_b = db.create_subscription(222, "n1", 30, "1m", source="bot") + + legal.update_env_var("BRAND_NAME", "SnapshotBrand") + settings.set_plan_prices({"1m": 555}) + legal.update_env_var("HWID_LIMIT_ENABLED", "true") + legal.update_env_var("HWID_FALLBACK_LIMIT", "4") + assert db.hold_subscription(sub_a["uuid"]) + + assert settings.get_brand_name() == "SnapshotBrand" + assert settings.get_plans_by_code()["1m"]["price"] == 555 + assert settings.get_hwid_settings() == {"enabled": True, "fallback_limit": 4} + assert len(db.list_active_subscriptions(tg_id=111)) == 0, "held sub excluded pre-backup" + assert len(db.list_active_subscriptions(tg_id=222)) == 1 + + snapshot = backup.create_backup() + + legal.update_env_var("BRAND_NAME", "MutatedAfterBackup") + settings.set_plan_prices({"1m": 999}) + legal.update_env_var("HWID_LIMIT_ENABLED", "false") + assert db.resume_subscription(sub_a["uuid"])["held_at"] is None + sub_c = db.create_subscription(333, "n1", 30, "1m", source="bot") + assert settings.get_brand_name() == "MutatedAfterBackup" + assert len(db.list_active_subscriptions(tg_id=111)) == 1 + + result = backup.restore_backup(snapshot) + assert result["restored_env"] is True + + assert settings.get_brand_name() == "SnapshotBrand", "brand must revert to snapshot value" + assert settings.get_plans_by_code()["1m"]["price"] == 555, "price override must revert" + assert settings.get_hwid_settings() == {"enabled": True, "fallback_limit": 4}, "hwid settings must revert" + + restored_sub_a = db.get_subscription(sub_a["uuid"]) + assert restored_sub_a["held_at"] is not None, "held_at must round-trip through backup/restore" + assert len(db.list_active_subscriptions(tg_id=111)) == 0, "sub_a held again after restore" + assert len(db.list_active_subscriptions(tg_id=222)) == 1, "sub_b untouched" + assert db.get_subscription(sub_c["uuid"]) is None, "sub_c created after backup point must be gone" + + print("backup/restore correctly round-trips branding, live settings and held_at together OK") + PYEOF