Split ledger tests into multiple test files/groups

This commit is contained in:
Jason Rhinelander 2023-05-01 20:58:43 -03:00
parent 9cd7756d51
commit 67e1e6b364
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
5 changed files with 217 additions and 207 deletions

View File

@ -15,6 +15,13 @@ def pytest_addoption(parser):
parser.addoption("--ledger-api", default="http://127.0.0.1:5000", action="store")
def pytest_collection_modifyitems(session, config, items):
"""Reorders the tests more logically than the default alphabetical order"""
pos = {"test_basic.py": 1, "test_transfers.py": 2, "test_sn.py": 3, "test_ons.py": 4, "": 5}
items.sort(key=lambda i: pos.get(i.parent.name, pos[""]))
@pytest.fixture(scope="session")
def binary_dir(request):
binpath = request.config.getoption("--binary-dir")
@ -36,7 +43,6 @@ def ledger(request):
@pytest.fixture
def net(pytestconfig, tmp_path, binary_dir):
import vprint
return service_node_network.basic_net(pytestconfig, tmp_path, binary_dir)

View File

@ -0,0 +1,36 @@
from expected import *
def test_init(net, mike, hal, ledger):
"""
Tests that the node fakenet got initialized properly, and that the wallet starts up and shows
the right address.
"""
# All nodes should be at the same height:
heights = [x.rpc("/get_height").json()["height"] for x in net.all_nodes]
height = max(heights)
assert heights == [height] * len(net.all_nodes)
assert mike.height(refresh=True) == height
assert mike.balances() > (0, 0)
assert hal.height(refresh=True) == height
assert hal.balances() == (0, 0)
address = hal.address()
def check_addr(_, m):
assert address.startswith(m[1][1]) and address.endswith(m[1][2])
check_interactions(
ledger,
MatchScreen([r"^OXEN wallet$", r"^(\w+)\.\.(\w+)$"], check_addr),
Do.both, # Hitting both on the main screen shows us the full address details
ExactScreen(["Regular address", "(fakenet)"]),
Do.right,
MatchMulti("Address", address),
Do.right,
ExactScreen(["Back"]),
Do.both,
MatchScreen([r"^OXEN wallet$", r"^(\w+)\.\.(\w+)$"], check_addr),
)

159
tests/ledger/test_sn.py Normal file
View File

@ -0,0 +1,159 @@
import pytest
from functools import partial
from utils import *
from expected import *
def check_sn_rewards(net, hal, sn, starting_bal, reward):
net.mine(5) # 5 blocks until it starts earning rewards (testnet/fakenet)
hal_bal = hal.balances(refresh=True)
batch_offset = None
assert hal_bal == coins(starting_bal, 0)
# We don't know where our batch payment occurs yet, but let's look for it:
for i in range(20):
net.mine(1)
if hal.balances(refresh=True)[0] > coins(starting_bal):
batch_offset = sn.height() % 20
break
assert batch_offset is not None
hal_bal = hal.balances()
net.mine(19)
assert hal.balances(refresh=True)[0] == hal_bal[0]
net.mine(1) # Should be our batch height
assert hal.balances(refresh=True)[0] == hal_bal[0] + coins(20 * reward)
def test_sn_register(net, mike, hal, ledger, sn):
mike.transfer(hal, coins(101))
net.mine()
assert hal.balances(refresh=True) == coins(101, 101)
store_fee = StoreFee()
run_with_interactions(
ledger,
partial(hal.register_sn, sn),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Confirm Stake", "100.0"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
ExactScreen(["Processing Stake"]),
)
# We are half the SN network, so get half of the block reward per block:
reward = 0.5 * 16.5
check_sn_rewards(net, hal, sn, 101 - store_fee.fee, reward)
def test_sn_stake(net, mike, alice, hal, ledger, sn):
mike.multi_transfer([hal, alice], coins(13.02, 87.02))
net.mine()
assert hal.balances(refresh=True) == coins(13.02, 13.02)
assert alice.balances(refresh=True) == coins(87.02, 87.02)
alice.register_sn(sn, stake=coins(87))
net.mine(1)
store_fee = StoreFee()
run_with_interactions(
ledger,
partial(hal.stake_sn, sn, coins(13)),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Confirm Stake", "13.0"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
ExactScreen(["Processing Stake"]),
)
# Our SN is 1 or 2 registered, so we get 50% of the 16.5 reward, 10% is removed for operator
# fee, then hal gets 13/100 of the rest:
reward = 0.5 * 16.5 * 0.9 * 0.13
check_sn_rewards(net, hal, sn, 13 - store_fee.fee, reward)
def test_sn_reject(net, mike, hal, ledger, sn):
mike.transfer(hal, coins(101))
net.mine()
assert hal.balances(refresh=True) == coins(101, 101)
store_fee = StoreFee()
with pytest.raises(RuntimeError, match=r"Fee denied on device\.$"):
run_with_interactions(
ledger,
partial(hal.register_sn, sn),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
Do.right,
ExactScreen(["Reject"]),
Do.both,
)
with pytest.raises(RuntimeError, match=r"Transaction denied on device\.$"):
run_with_interactions(
ledger,
partial(hal.register_sn, sn),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Confirm Stake", "100.0"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.both,
)
def test_sn_unstake(net, mike, hal, ledger, sn):
# Do the full registration:
test_sn_register(net, mike, hal, ledger, sn)
run_with_interactions(
ledger,
partial(hal.unstake_sn, sn),
ExactScreen(["Confirm Service", "Node Unlock"]),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
)
# A fakechain unlock takes 30 blocks, plus add another 20 just so we are sure we've received the
# last batch reward:
net.mine(30 + 20)
hal_bal = hal.balances(refresh=True)
net.mine(20)
assert hal.balances(refresh=True) == hal_bal

View File

@ -1,54 +1,11 @@
import pytest
import time
import re
from functools import partial
from service_node_network import coins, vprint
from ledgerapi import LedgerAPI
from utils import *
from expected import *
import daemons
def balance(c):
"""Shortcut for coins(c,c), particularly useful when c is complex"""
return coins(c, c)
def test_init(net, mike, hal, ledger):
"""
Tests that the node fakenet got initialized properly, and that the wallet starts up and shows
the right address.
"""
# All nodes should be at the same height:
heights = [x.rpc("/get_height").json()["height"] for x in net.all_nodes]
height = max(heights)
assert heights == [height] * len(net.all_nodes)
assert mike.height(refresh=True) == height
assert mike.balances() > (0, 0)
assert hal.height(refresh=True) == height
assert hal.balances() == (0, 0)
address = hal.address()
def check_addr(_, m):
assert address.startswith(m[1][1]) and address.endswith(m[1][2])
check_interactions(
ledger,
MatchScreen([r"^OXEN wallet$", r"^(\w+)\.\.(\w+)$"], check_addr),
Do.both, # Hitting both on the main screen shows us the full address details
ExactScreen(["Regular address", "(fakenet)"]),
Do.right,
MatchMulti("Address", address),
Do.right,
ExactScreen(["Back"]),
Do.both,
MatchScreen([r"^OXEN wallet$", r"^(\w+)\.\.(\w+)$"], check_addr),
)
def test_receive(net, mike, hal):
mike.transfer(hal, coins(100))
net.mine(blocks=2)
@ -59,14 +16,6 @@ def test_receive(net, mike, hal):
assert hal.balances(refresh=True) == coins(100, 100)
class StoreFee:
def __init__(self):
self.fee = None
def __call__(self, _, m):
self.fee = float(m[1][1])
def test_send(net, mike, alice, hal, ledger):
mike.transfer(hal, coins(100))
net.mine()
@ -386,157 +335,3 @@ def test_subaddr_send(net, mike, alice, bob, hal, ledger):
assert alice.balances(refresh=True) == coins(6, 6)
assert bob.balances(refresh=True) == coins(15, 15)
assert hal.balances(refresh=True) == balance(100 - sum(amounts) - store_fee.fee)
def check_sn_rewards(net, hal, sn, starting_bal, reward):
net.mine(5) # 5 blocks until it starts earning rewards (testnet/fakenet)
hal_bal = hal.balances(refresh=True)
batch_offset = None
assert hal_bal == coins(starting_bal, 0)
# We don't know where our batch payment occurs yet, but let's look for it:
for i in range(20):
net.mine(1)
if hal.balances(refresh=True)[0] > coins(starting_bal):
batch_offset = sn.height() % 20
break
assert batch_offset is not None
hal_bal = hal.balances()
net.mine(19)
assert hal.balances(refresh=True)[0] == hal_bal[0]
net.mine(1) # Should be our batch height
assert hal.balances(refresh=True)[0] == hal_bal[0] + coins(20 * reward)
def test_sn_register(net, mike, hal, ledger, sn):
mike.transfer(hal, coins(101))
net.mine()
assert hal.balances(refresh=True) == coins(101, 101)
store_fee = StoreFee()
run_with_interactions(
ledger,
partial(hal.register_sn, sn),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Confirm Stake", "100.0"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
ExactScreen(["Processing Stake"]),
)
# We are half the SN network, so get half of the block reward per block:
reward = 0.5 * 16.5
check_sn_rewards(net, hal, sn, 101 - store_fee.fee, reward)
def test_sn_stake(net, mike, alice, hal, ledger, sn):
mike.multi_transfer([hal, alice], coins(13.02, 87.02))
net.mine()
assert hal.balances(refresh=True) == coins(13.02, 13.02)
assert alice.balances(refresh=True) == coins(87.02, 87.02)
alice.register_sn(sn, stake=coins(87))
net.mine(1)
store_fee = StoreFee()
run_with_interactions(
ledger,
partial(hal.stake_sn, sn, coins(13)),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Confirm Stake", "13.0"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
ExactScreen(["Processing Stake"]),
)
# Our SN is 1 or 2 registered, so we get 50% of the 16.5 reward, 10% is removed for operator
# fee, then hal gets 13/100 of the rest:
reward = 0.5 * 16.5 * 0.9 * 0.13
check_sn_rewards(net, hal, sn, 13 - store_fee.fee, reward)
def test_sn_reject(net, mike, hal, ledger, sn):
mike.transfer(hal, coins(101))
net.mine()
assert hal.balances(refresh=True) == coins(101, 101)
store_fee = StoreFee()
with pytest.raises(RuntimeError, match=r"Fee denied on device\.$"):
run_with_interactions(
ledger,
partial(hal.register_sn, sn),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
Do.right,
ExactScreen(["Reject"]),
Do.both,
)
with pytest.raises(RuntimeError, match=r"Transaction denied on device\.$"):
run_with_interactions(
ledger,
partial(hal.register_sn, sn),
ExactScreen(["Processing Stake"]),
MatchScreen([r"^Confirm Fee$", r"^(0\.01\d{1,7})$"], store_fee, fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.both,
ExactScreen(["Confirm Stake", "100.0"], fail_index=1),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.both,
)
def test_sn_unstake(net, mike, hal, ledger, sn):
# Do the full registration:
test_sn_register(net, mike, hal, ledger, sn)
run_with_interactions(
ledger,
partial(hal.unstake_sn, sn),
ExactScreen(["Confirm Service", "Node Unlock"]),
Do.right,
ExactScreen(["Accept"]),
Do.right,
ExactScreen(["Reject"]),
Do.left,
Do.both,
)
# A fakechain unlock takes 30 blocks, plus add another 20 just so we are sure we've received the
# last batch reward:
net.mine(30 + 20)
hal_bal = hal.balances(refresh=True)
net.mine(20)
assert hal.balances(refresh=True) == hal_bal

14
tests/ledger/utils.py Normal file
View File

@ -0,0 +1,14 @@
from service_node_network import coins, vprint
def balance(c):
"""Shortcut for coins(c,c), particularly useful when c is complex"""
return coins(c, c)
class StoreFee:
def __init__(self):
self.fee = None
def __call__(self, _, m):
self.fee = float(m[1][1])