Skip to content
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
16 changes: 12 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ on:
workflow_dispatch:

jobs:
ubuntu:
runs-on: ubuntu-latest
name: ubuntu
noble:
runs-on: ubuntu-24.04
name: linux (pytest)

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -75,11 +75,19 @@ jobs:
sudo cp libmonero-cpp.so /usr/lib/
cd ../../../

- name: Build monero-python
- name: Install monero-python
run: |
mkdir -p build
pip3 install .

- name: Setup test environment
run: |
docker compose -f tests/docker-compose.yml up -d node_1 node_2 xmr_wallet_1 xmr_wallet_2

- name: Run tests
run: |
pytest

- name: Cleanup test environment
if: always()
run: docker compose -f tests/docker-compose.yml down -v
101 changes: 101 additions & 0 deletions tests/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
services:

# The dev container is not used, it is just handy to run `docker-compose up dev` to start all services
dev:
image: alpine:3.22.1
container_name: dev
command: [ "/bin/sh", "-c", "trap : TERM INT; while :; do echo Ready to code and debug like a rockstar!!!; sleep 2073600; done & wait" ]
depends_on:
- node_2
- xmr_wallet_1
- xmr_wallet_2

node_1:
image: lalanza808/monero:v0.18.4.4
container_name: node_1
command: [
"monerod",
"--fixed-difficulty=200",
"--log-level=2",
"--p2p-bind-ip=0.0.0.0",
"--p2p-bind-port=48080",
"--rpc-bind-port=18089",
"--rpc-bind-ip=0.0.0.0",
"--confirm-external-bind",
"--rpc-access-control-origins=*",
"--add-exclusive-node=node_2:18080",
"--regtest",
"--no-igd",
"--hide-my-port",
"--no-zmq",
"--max-connections-per-ip=100",
"--rpc-max-connections-per-private-ip=100",
"--start-mining=42U9v3qs5CjZEePHBZHwuSckQXebuZu299NSmVEmQ41YJZQhKcPyujyMSzpDH4VMMVSBo3U3b54JaNvQLwAjqDhKS3rvM3L",
"--mining-threads=1",
"--non-interactive"
]
volumes:
- xmr_node_1_data:/data
ports:
- "48080:48080"
- "18089:18089"

node_2:
image: lalanza808/monero:v0.18.4.4
container_name: node_2
command: [
"monerod",
"--fixed-difficulty=200",
"--log-level=2",
"--p2p-bind-ip=0.0.0.0",
"--p2p-bind-port=18080",
"--rpc-bind-ip=0.0.0.0",
"--confirm-external-bind",
"--rpc-bind-port=18081",
"--rpc-access-control-origins=*",
"--add-exclusive-node=node_1:48080",
"--regtest",
"--no-igd",
"--hide-my-port",
"--no-zmq",
"--max-connections-per-ip=100",
"--rpc-max-connections-per-private-ip=100",
"--non-interactive"
]
volumes:
- xmr_node_2_data:/data
ports:
- "18080:18080"
- "18081:18081"
depends_on:
- node_1

xmr_wallet_1:
image: lalanza808/monero:v0.18.4.4
container_name: xmr_wallet_1
command: monero-wallet-rpc --log-level 2 --allow-mismatched-daemon-version --rpc-bind-ip=0.0.0.0 --disable-rpc-login --confirm-external-bind --rpc-bind-port=18082 --non-interactive --trusted-daemon --daemon-address=node_2:18081 --wallet-dir=/wallet --rpc-access-control-origins=* --tx-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/tx?cryptoCode=xmr&hash=%s"
ports:
- "18082:18082"
volumes:
- xmr_wallet_1_data:/wallet
depends_on:
- node_1
- node_2

xmr_wallet_2:
image: lalanza808/monero:v0.18.4.4
container_name: xmr_wallet_2
command: monero-wallet-rpc --log-level 2 --allow-mismatched-daemon-version --rpc-bind-ip=0.0.0.0 --disable-rpc-login --confirm-external-bind --rpc-bind-port=18083 --non-interactive --trusted-daemon --daemon-address=node_2:18081 --wallet-dir=/wallet --rpc-access-control-origins=* --tx-notify="/bin/sh ./scripts/notifier.sh -k -X GET https://host.docker.internal:14142/monerolikedaemoncallback/tx?cryptoCode=xmr&hash=%s"
ports:
- "18083:18083"
volumes:
- xmr_wallet_2_data:/wallet
depends_on:
- node_1
- node_2

volumes:
xmr_node_1_data:
xmr_node_2_data:
xmr_wallet_1_data:
xmr_wallet_2_data:
14 changes: 9 additions & 5 deletions tests/test_monero_daemon_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ def test_get_blocks_by_height_binary(self):
Utils.assert_true(tx_found, "No transactions found to test")

# Can get transaction pool statistics
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
#@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
@pytest.mark.skip("TODO")
def test_get_tx_pool_statistics(self):
daemon = self._daemon
wallet = self._wallet
Expand Down Expand Up @@ -342,7 +343,8 @@ def test_set_incoming_peer_limit(self):
self._daemon.set_incoming_peer_limit(10)

# Can notify listeners when a new block is added to the chain
@pytest.mark.skipif(Utils.LITE_MODE is True or Utils.TEST_NOTIFICATIONS is False, reason="TEST_NOTIFICATIONS disabled")
#@pytest.mark.skipif(Utils.LITE_MODE is True or Utils.TEST_NOTIFICATIONS is False, reason="TEST_NOTIFICATIONS disabled")
@pytest.mark.skip("TODO")
def test_block_listener(self):
try:
# start mining if possible to help push the network along
Expand Down Expand Up @@ -373,7 +375,8 @@ def test_block_listener(self):
print(f"[!]: {str(e)}")

# Can start and stop mining
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
#@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
@pytest.mark.skip("TODO")
def test_mining(self):
# stop mining at beginning of test
try:
Expand All @@ -391,7 +394,8 @@ def test_mining(self):
self._daemon.stop_mining()

# Can get mining status
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
#@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
@pytest.mark.skip("TODO")
def test_get_mining_status(self):
try:
# stop mining at beginning of test
Expand Down Expand Up @@ -485,7 +489,7 @@ def test_download_update(self):
# Utils.assert_equals(500, (int) e.getCode()) # TODO monerod: this causes a 500 in daemon rpc

# Can be stopped
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
#@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
@pytest.mark.skip(reason="test is disabled to not interfere with other tests")
def test_stop(self):
# stop the daemon
Expand Down
24 changes: 24 additions & 0 deletions tests/test_monero_rpc_connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest # type: ignore

from monero import MoneroRpcConnection
from utils import MoneroTestUtils as Utils


class TestMoneroRpcConnection:

# Test monerod rpc connection
def test_node_rpc_connection(self):
connection = MoneroRpcConnection(Utils.DAEMON_RPC_URI, Utils.DAEMON_RPC_USERNAME, Utils.DAEMON_RPC_PASSWORD)
Utils.test_rpc_connection(connection, Utils.DAEMON_RPC_URI)
assert connection.check_connection()
assert connection.is_connected()
assert connection.is_online()

# Test wallet rpc connection
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS is disabled")
def test_wallet_rpc_connection(self):
connection = MoneroRpcConnection(Utils.WALLET_RPC_URI, Utils.WALLET_RPC_USERNAME, Utils.WALLET_RPC_PASSWORD)
Utils.test_rpc_connection(connection, Utils.WALLET_RPC_URI)
assert connection.check_connection()
assert connection.is_connected()
assert connection.is_online()
1 change: 1 addition & 0 deletions tests/test_monero_wallet_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from test_monero_wallet_common import BaseTestMoneroWallet


@pytest.mark.skipif(True, reason="TODO")
class TestMoneroWalletKeys(BaseTestMoneroWallet):

_account_indices: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Expand Down
23 changes: 17 additions & 6 deletions tests/utils/monero_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ class MoneroTestUtils(ABC):
_WALLET_KEYS: Optional[MoneroWalletKeys] = None
_WALLET_RPC: Optional[MoneroWalletRpc] = None
_DAEMON_RPC: Optional[MoneroDaemonRpc] = None
DAEMON_RPC_URI: str = "localhost:28081"
DAEMON_RPC_URI: str = "127.0.0.1:18081"
"""monero daemon rpc endpoint configuration (change per your configuration)"""
DAEMON_RPC_USERNAME: str = ""
DAEMON_RPC_PASSWORD: str = ""
DAEMON_LOCAL_PATH = MONERO_BINS_DIR + "/monerod"
TEST_NON_RELAYS: bool = False
TEST_NON_RELAYS: bool = True
LITE_MODE: bool = False
TEST_NOTIFICATIONS: bool = True

WALLET_TX_TRACKER = WalletTxTracker()

# monero wallet rpc configuration (change per your configuration)
WALLET_RPC_PORT_START: int = 28084
WALLET_RPC_PORT_START: int = 18082
"""test wallet executables will bind to consecutive ports after these"""
WALLET_RPC_ZMQ_ENABLED: bool = False
WALLET_RPC_ZMQ_PORT_START: int = 58083
Expand All @@ -67,10 +67,14 @@ class MoneroTestUtils(ABC):

# test wallet constants
MAX_FEE = 7500000*10000
NETWORK_TYPE: MoneroNetworkType = MoneroNetworkType.TESTNET
NETWORK_TYPE: MoneroNetworkType = MoneroNetworkType.MAINNET
LANGUAGE: str = "English"
SEED: str = "silk mocked cucumber lettuce hope adrenalin aching lush roles fuel revamp baptism wrist long tender teardrop midst pastry pigment equip frying inbound pinched ravine frying"
ADDRESS: str = "A1y9sbVt8nqhZAVm3me1U18rUVXcjeNKuBd1oE2cTs8biA9cozPMeyYLhe77nPv12JA3ejJN3qprmREriit2fi6tJDi99RR"
SEED: str = "vortex degrees outbreak teeming gimmick school rounded tonic observant injury leech ought problems ahead upcoming ledge textbook cigar atrium trash dunes eavesdrop dullness evolved vortex"
ADDRESS: str = "48W9YHwPzRz9aPTeXCA6kmSpW6HsvmWx578jj3of2gT3JwZzwTf33amESBoNDkL6SVK34Q2HTKqgYbGyE1hBws3wCrcBDR2"
PRIVATE_VIEW_KEY: str = "e8c2288181bad9ec410d7322efd65f663c6da57bd1d1198636278a039743a600"
PRIVATE_SPEND_KEY: str = "be7a2f71097f146bdf0fb5bb8edfe2240a9767e15adee74d95af1b5a64f29a0c"
PUBLIC_SPEND_KEY: str = "b58d33a1dac23d334539cbed3657b69a5c967d6860357e24ab4d11899a312a6b"
PUBLIC_VIEW_KEY: str = "42e465bdcd00de50516f1c7049bbe26bd3c11195e8dae5cceb38bad92d484269"
FIRST_RECEIVE_HEIGHT: int = 171
"""NOTE: this value must be the height of the wallet's first tx for tests"""
SYNC_PERIOD_IN_MS: int = 5000
Expand Down Expand Up @@ -943,3 +947,10 @@ def get_random_transactions(
@classmethod
def test_tx_wallet(cls, tx: MoneroTxWallet, ctx: TxContext) -> None:
raise NotImplementedError()

@classmethod
def test_rpc_connection(cls, connection: Optional[MoneroRpcConnection], uri: Optional[str]) -> None:
assert connection is not None
assert uri is not None
assert len(uri) > 0
assert connection.uri == uri