Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] Improve tests #296

Merged
merged 18 commits into from
Aug 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ TOR=TRUE

# NOSTR
# nostr private key to which to receive tokens to
NOSTR_PRIVATE_KEY=nostr_privatekey_here_hex_or_bech32_nsec
# NOSTR_PRIVATE_KEY=nostr_privatekey_here_hex_or_bech32_nsec
# nostr relays (comma separated list)
NOSTR_RELAYS=["wss://nostr-pub.wellorder.net"]

Expand All @@ -38,7 +38,6 @@ MINT_INFO_CONTACT=[["email","[email protected]"], ["twitter","@me"], ["nostr", "np
MINT_INFO_MOTD="Message to users"

MINT_PRIVATE_KEY=supersecretprivatekey
MINT_DATABASE=data/mint
# increment derivation path to rotate to a new keyset
MINT_DERIVATION_PATH="0/0/0/0"

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ tor.pid

# Default data directory
/data
/test_data

# MacOS
.DS_Store
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ package:
python setup.py sdist bdist_wheel

test:
LIGHTNING=false \
TOR=false \
poetry run pytest tests --cov-report xml --cov cashu

install:
Expand Down
50 changes: 27 additions & 23 deletions cashu/wallet/api/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,35 @@
router: APIRouter = APIRouter()


def create_wallet(
url=settings.mint_url, dir=settings.cashu_dir, name=settings.wallet_name
):
return Wallet(
url=url,
db=os.path.join(dir, name),
name=name,
async def mint_wallet(mint_url: Optional[str] = None):
wallet: Wallet = await Wallet.with_db(
mint_url or settings.mint_url,
db=os.path.join(settings.cashu_dir, settings.wallet_name),
name=settings.wallet_name,
)


async def load_mint(wallet: Wallet, mint: Optional[str] = None):
if mint:
wallet = create_wallet(mint)
await init_wallet(wallet)
await wallet.load_mint()
return wallet


wallet = create_wallet()
wallet: Wallet = Wallet(
settings.mint_url,
db=os.path.join(settings.cashu_dir, settings.wallet_name),
name=settings.wallet_name,
)


@router.on_event("startup")
async def start_wallet():
global wallet
wallet = await Wallet.with_db(
settings.mint_url,
db=os.path.join(settings.cashu_dir, settings.wallet_name),
name=settings.wallet_name,
)

if settings.tor and not TorProxy().check_platform():
raise Exception("tor not working.")
await init_wallet(wallet)
await wallet.load_mint()


@router.post("/pay", name="Pay lightning invoice", response_model=PayResponse)
Expand All @@ -78,7 +81,7 @@ async def pay(
raise Exception("lightning not enabled.")

global wallet
wallet = await load_mint(wallet, mint)
wallet = await mint_wallet(mint)

total_amount, fee_reserve_sat = await wallet.get_pay_amount_with_fees(invoice)
assert total_amount > 0, "amount has to be larger than zero."
Expand Down Expand Up @@ -116,7 +119,7 @@ async def invoice(
print(f"Requesting split with {n_splits}*{split} sat tokens.")

global wallet
wallet = await load_mint(wallet, mint)
wallet = await mint_wallet(mint)
if not settings.lightning:
await wallet.mint(amount, split=optional_split)
return InvoiceResponse(
Expand Down Expand Up @@ -150,16 +153,16 @@ async def swap(
):
if not settings.lightning:
raise Exception("lightning not supported")
incoming_wallet = await load_mint(wallet, mint=incoming_mint)
outgoing_wallet = await load_mint(wallet, mint=outgoing_mint)
incoming_wallet = await mint_wallet(incoming_mint)
outgoing_wallet = await mint_wallet(outgoing_mint)
if incoming_wallet.url == outgoing_wallet.url:
raise Exception("mints for swap have to be different")

# request invoice from incoming mint
invoice = await incoming_wallet.request_mint(amount)

# pay invoice from outgoing mint
await outgoing_wallet.load_proofs()
await outgoing_wallet.load_proofs(reload=True)
total_amount, fee_reserve_sat = await outgoing_wallet.get_pay_amount_with_fees(
invoice.pr
)
Expand All @@ -174,7 +177,7 @@ async def swap(

# mint token in incoming mint
await incoming_wallet.mint(amount, hash=invoice.hash)
await incoming_wallet.load_proofs()
await incoming_wallet.load_proofs(reload=True)
mint_balances = await incoming_wallet.balance_per_minturl()
return SwapResponse(
outgoing_mint=outgoing_mint,
Expand All @@ -191,7 +194,7 @@ async def swap(
response_model=BalanceResponse,
)
async def balance():
await wallet.load_proofs()
await wallet.load_proofs(reload=True)
keyset_balances = wallet.balance_per_keyset()
mint_balances = await wallet.balance_per_minturl()
return BalanceResponse(
Expand Down Expand Up @@ -229,6 +232,7 @@ async def receive_command(
nostr: bool = Query(default=False, description="Receive tokens via nostr"),
all: bool = Query(default=False, description="Receive all pending tokens"),
):
wallet = await mint_wallet()
initial_balance = wallet.available_balance
if token:
tokenObj: TokenV3 = deserialize_token_from_string(token)
Expand Down Expand Up @@ -269,7 +273,7 @@ async def burn(
):
global wallet
if not delete:
wallet = await load_mint(wallet, mint)
wallet = await mint_wallet(mint)
if not (all or token or force or delete) or (token and all):
raise Exception(
"enter a token or use --all to burn all pending tokens, --force to check all tokens"
Expand Down
56 changes: 24 additions & 32 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,36 @@
from cashu.mint import migrations as migrations_mint
from cashu.mint.ledger import Ledger

SERVER_ENDPOINT = "http://localhost:3337"
SERVER_PORT = 3337
SERVER_ENDPOINT = f"http://localhost:{SERVER_PORT}"

settings.cashu_dir = "./test_data/"
settings.mint_host = "localhost"
settings.mint_port = SERVER_PORT
settings.mint_host = "0.0.0.0"
settings.mint_listen_port = SERVER_PORT
settings.mint_url = SERVER_ENDPOINT
settings.lightning = False
settings.tor = False
settings.mint_lightning_backend = "FakeWallet"
settings.mint_database = "./test_data/test_mint"
settings.mint_derivation_path = "0/0/0/0"
settings.mint_private_key = "TEST_PRIVATE_KEY"
Comment on lines +22 to +33
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hrm, overwriting the settings like this strikes me as a bad idea -- to me intuitively settings should be immutable, avoids having value A at some time, then a bit of code runs, then it's now value B, things break or are confusing. Or potentially if you just import this file, it'll mangle the settings because the mutation doesn't happen in a function. Also as they're currently configured, they'll be type-checked on load (and will error if a setting is wrong), but they won't be when you re-assign them like this.

Instead it'd be 'better' to use a separate .env for the tests (docs)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its a hard override on settings for conftest. i think its fine, mixing up different .env is error prone too. i could just prefix the poetry run command inside Makefile but then running it with poetry run pytest does not work.


shutil.rmtree(settings.cashu_dir, ignore_errors=True)
Path(settings.cashu_dir).mkdir(parents=True, exist_ok=True)


class UvicornServer(multiprocessing.Process):
def __init__(self, config: Config, private_key: str = "TEST_PRIVATE_KEY"):
def __init__(self, config: Config):
super().__init__()
self.server = Server(config=config)
self.config = config
self.private_key = private_key

def stop(self):
self.terminate()

def run(self, *args, **kwargs):
settings.lightning = False
settings.mint_lightning_backend = "FakeWallet"
settings.mint_database = "data/test_mint"
settings.mint_private_key = self.private_key
settings.mint_derivation_path = "0/0/0/0"

dirpath = Path(settings.mint_database)
if dirpath.exists() and dirpath.is_dir():
shutil.rmtree(dirpath)

dirpath = Path("data/wallet1")
if dirpath.exists() and dirpath.is_dir():
shutil.rmtree(dirpath)

dirpath = Path("data/wallet2")
if dirpath.exists() and dirpath.is_dir():
shutil.rmtree(dirpath)

dirpath = Path("data/wallet3")
if dirpath.exists() and dirpath.is_dir():
shutil.rmtree(dirpath)

self.server.run()


Expand All @@ -62,13 +56,13 @@ async def start_mint_init(ledger: Ledger):
await ledger.load_used_proofs()
await ledger.init_keysets()

db_file = "data/mint/test.sqlite3"
db_file = "test_data/mint/test.sqlite3"
if os.path.exists(db_file):
os.remove(db_file)
ledger = Ledger(
db=Database("test", "data/mint"),
seed="TEST_PRIVATE_KEY",
derivation_path="0/0/0/0",
db=Database("test", "test_data/mint"),
seed=settings.mint_private_key,
derivation_path=settings.mint_derivation_path,
lightning=FakeWallet(),
)
await start_mint_init(ledger)
Expand All @@ -77,12 +71,10 @@ async def start_mint_init(ledger: Ledger):

@pytest.fixture(autouse=True, scope="session")
def mint():
settings.mint_listen_port = 3337
settings.mint_url = "http://localhost:3337"
config = uvicorn.Config(
"cashu.mint.app:app",
port=settings.mint_listen_port,
host="127.0.0.1",
host=settings.mint_listen_host,
)

server = UvicornServer(config=config)
Expand Down
22 changes: 4 additions & 18 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@ def cli_prefix():
async def init_wallet():
wallet = await Wallet.with_db(
url=settings.mint_host,
db="data/test_cli_wallet",
db="test_data/test_cli_wallet",
name="wallet",
)
await wallet.load_proofs()
return wallet


@pytest.mark.asyncio
def test_info(cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -37,7 +36,6 @@ def test_info(cli_prefix):
assert result.exit_code == 0


@pytest.mark.asyncio
def test_info_with_mint(cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -51,7 +49,6 @@ def test_info_with_mint(cli_prefix):
assert result.exit_code == 0


@pytest.mark.asyncio
def test_info_with_mnemonic(cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -65,7 +62,6 @@ def test_info_with_mnemonic(cli_prefix):
assert result.exit_code == 0


@pytest.mark.asyncio
def test_balance(cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -80,7 +76,6 @@ def test_balance(cli_prefix):
assert result.exit_code == 0


@pytest.mark.asyncio
def test_invoice(mint, cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -96,7 +91,6 @@ def test_invoice(mint, cli_prefix):
assert result.exit_code == 0


@pytest.mark.asyncio
def test_invoice_with_split(mint, cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -108,7 +102,6 @@ def test_invoice_with_split(mint, cli_prefix):
# assert wallet.proof_amounts.count(1) >= 10


@pytest.mark.asyncio
def test_wallets(cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -123,7 +116,6 @@ def test_wallets(cli_prefix):
assert result.exit_code == 0


@pytest.mark.asyncio
def test_send(mint, cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -136,7 +128,6 @@ def test_send(mint, cli_prefix):
assert "cashuA" in result.output, "output does not have a token"


@pytest.mark.asyncio
def test_send_without_split(mint, cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -149,7 +140,6 @@ def test_send_without_split(mint, cli_prefix):
assert "cashuA" in result.output, "output does not have a token"


@pytest.mark.asyncio
def test_send_without_split_but_wrong_amount(mint, cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand All @@ -159,7 +149,6 @@ def test_send_without_split_but_wrong_amount(mint, cli_prefix):
assert "No proof with this amount found" in str(result.exception)


@pytest.mark.asyncio
def test_receive_tokenv3(mint, cli_prefix):
runner = CliRunner()
token = (
Expand All @@ -181,10 +170,10 @@ def test_receive_tokenv3(mint, cli_prefix):
print(result.output)


@pytest.mark.asyncio
def test_receive_tokenv3_no_mint(mint, cli_prefix):
# this test works only if the previous test succeeds because we simulate the case where the mint URL is not in the token
# therefore, we need to know the mint keyset already and have the mint URL in the db
# this test works only if the previous test succeeds because we simulate the case
# where the mint URL is not in the token therefore, we need to know the mint keyset
# already and have the mint URL in the db
runner = CliRunner()
token = (
"cashuAeyJ0b2tlbiI6IFt7InByb29mcyI6IFt7ImlkIjogIjFjQ05JQVoyWC93MSIsICJhbW91bnQiOiAyLCAic2VjcmV0IjogIi1oM0ZXMFFoX1FYLW9ac1V2c0RuNlEiLC"
Expand All @@ -205,7 +194,6 @@ def test_receive_tokenv3_no_mint(mint, cli_prefix):
print(result.output)


@pytest.mark.asyncio
def test_receive_tokenv2(mint, cli_prefix):
runner = CliRunner()
token = (
Expand All @@ -223,7 +211,6 @@ def test_receive_tokenv2(mint, cli_prefix):
print(result.output)


@pytest.mark.asyncio
def test_receive_tokenv1(mint, cli_prefix):
runner = CliRunner()
token = (
Expand All @@ -240,7 +227,6 @@ def test_receive_tokenv1(mint, cli_prefix):
print(result.output)


@pytest.mark.asyncio()
def test_nostr_send(mint, cli_prefix):
runner = CliRunner()
result = runner.invoke(
Expand Down
2 changes: 0 additions & 2 deletions tests/test_mint.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
from cashu.core.settings import settings
from cashu.mint.ledger import Ledger

SERVER_ENDPOINT = "http://localhost:3338"


async def assert_err(f, msg):
"""Compute f() and expect an error message 'msg'."""
Expand Down
Loading
Loading