v0.5.4
This commit is contained in:
119
tests/test_group_i_basic_checkalive.py
Normal file
119
tests/test_group_i_basic_checkalive.py
Normal file
@@ -0,0 +1,119 @@
|
||||
"""
|
||||
Tests for the "BASIC mode dynamic Check Alive" fix (Group I).
|
||||
|
||||
Background (reported by the owner): with the plugin left in BASIC mode (the
|
||||
default), the "Check Alive" (threshold) field is hidden from the user and
|
||||
stays stuck at its old/default value (roughly "today + 11 months", i.e. one
|
||||
year minus the default 30-day margin). If the user then anticipates the
|
||||
delivery time (locktime) to something earlier than that stale threshold - e.g.
|
||||
"in 1 month" - two different checks that compare locktime against
|
||||
``date_to_check`` (the resolved threshold) would incorrectly treat the will as
|
||||
"expired"/"invalid", even though the whole Check Alive concept is supposed to
|
||||
be inert in BASIC mode.
|
||||
|
||||
The fix (``BalWindow.compute_date_to_check``) makes ``date_to_check`` track
|
||||
the delivery time LIVE in BASIC mode, placed a fixed 2-hour margin before it,
|
||||
so it is always < locktime by construction. In ADVANCED mode nothing changes:
|
||||
the stored threshold is used as-is.
|
||||
|
||||
These tests call the real production method directly (no GUI/Electrum wallet
|
||||
needed - it is a plain ``@staticmethod``), so they exercise the exact code
|
||||
used at runtime rather than a re-implementation.
|
||||
|
||||
Run:
|
||||
PYTHONPATH=electrum-src python3 -m pytest tests/test_group_i_basic_checkalive.py -q
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir))
|
||||
|
||||
from bal.gui.qt.window import BalWindow # noqa: E402 (path insert above)
|
||||
|
||||
|
||||
OFFSET = BalWindow.BASIC_MODE_CHECK_ALIVE_OFFSET_SECONDS
|
||||
|
||||
|
||||
def test_offset_is_two_hours():
|
||||
"""Owner-approved margin: exactly 2 hours."""
|
||||
assert OFFSET == 2 * 60 * 60
|
||||
|
||||
|
||||
def _relative_days_to_midnight_timestamp(days):
|
||||
"""Reproduce Util.parse_locktime_string's own normalisation: "now + N
|
||||
days", truncated to midnight. Used to compute the expected value in
|
||||
tests without duplicating the parsing logic itself."""
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
now = datetime.now()
|
||||
return (
|
||||
(now + timedelta(days=days))
|
||||
.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
.timestamp()
|
||||
)
|
||||
|
||||
|
||||
def test_basic_mode_relative_locktime_one_year():
|
||||
"""BASIC + default "1y" delivery: date_to_check tracks it, 2h earlier."""
|
||||
result = BalWindow.compute_date_to_check(True, "1y", "30d")
|
||||
expected_locktime = _relative_days_to_midnight_timestamp(365)
|
||||
assert abs(result - (expected_locktime - OFFSET)) < 5
|
||||
|
||||
|
||||
def test_basic_mode_anticipated_delivery_stays_consistent():
|
||||
"""BASIC + delivery anticipated to 1 month: date_to_check follows it,
|
||||
NOT the old ~11-month threshold - this is the exact bug scenario
|
||||
reported by the owner."""
|
||||
stale_threshold = "30d" # would resolve close to the OLD 1-year locktime
|
||||
anticipated_locktime = "30d" # user moved delivery to ~1 month from now
|
||||
result = BalWindow.compute_date_to_check(
|
||||
True, anticipated_locktime, stale_threshold
|
||||
)
|
||||
locktime_ts = _relative_days_to_midnight_timestamp(30)
|
||||
# date_to_check must be (delivery - 2h), always strictly before delivery.
|
||||
assert result < locktime_ts
|
||||
assert abs((locktime_ts - OFFSET) - result) < 5
|
||||
|
||||
|
||||
def test_basic_mode_date_to_check_always_before_locktime():
|
||||
"""Regression guard for the reported bug: whatever the delivery date is
|
||||
(even very close to "now"), date_to_check must stay before it."""
|
||||
for relative_locktime in ("1d", "7d", "30d", "90d", "365d"):
|
||||
result = BalWindow.compute_date_to_check(True, relative_locktime, "30d")
|
||||
parsed_locktime = _relative_days_to_midnight_timestamp(
|
||||
int(relative_locktime[:-1])
|
||||
)
|
||||
assert result < parsed_locktime, (
|
||||
f"date_to_check ({result}) should be before locktime "
|
||||
f"({parsed_locktime}) for locktime={relative_locktime}"
|
||||
)
|
||||
|
||||
|
||||
def test_advanced_mode_uses_stored_threshold_unchanged():
|
||||
"""ADVANCED mode: behaviour must stay exactly as before this fix - the
|
||||
stored threshold is used as-is, regardless of the locktime value."""
|
||||
absolute_threshold = time.time() + 5 * 86400 # arbitrary user-chosen value
|
||||
result = BalWindow.compute_date_to_check(False, "30d", absolute_threshold)
|
||||
assert abs(result - absolute_threshold) < 1
|
||||
|
||||
|
||||
def test_basic_mode_falls_back_on_unparsable_locktime():
|
||||
"""If the locktime can't be parsed for any reason, BASIC mode must not
|
||||
crash: it falls back to the stored threshold, same as ADVANCED."""
|
||||
absolute_threshold = time.time() + 5 * 86400
|
||||
result = BalWindow.compute_date_to_check(
|
||||
True, {"not": "a valid locktime"}, absolute_threshold
|
||||
)
|
||||
assert abs(result - absolute_threshold) < 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_offset_is_two_hours()
|
||||
test_basic_mode_relative_locktime_one_year()
|
||||
test_basic_mode_anticipated_delivery_stays_consistent()
|
||||
test_basic_mode_date_to_check_always_before_locktime()
|
||||
test_advanced_mode_uses_stored_threshold_unchanged()
|
||||
test_basic_mode_falls_back_on_unparsable_locktime()
|
||||
print("All test_group_i_basic_checkalive tests passed.")
|
||||
Reference in New Issue
Block a user