Skip to content
Open
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
85 changes: 85 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: 'Tests'

on:
push:
branches:
- main
pull_request:
branches:
- main

workflow_dispatch:

jobs:
ubuntu:
runs-on: ubuntu-latest
name: ubuntu

steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: |
sudo apt update
sudo apt install -y build-essential cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache doxygen graphviz git curl autoconf libtool gperf nettle-dev libevent-dev debhelper python3-all python3-pip python3-pybind11 python3-pytest
pip3 install pybind11-stubgen pytest --break-system-packages

- name: Install expat
run: |
wget https://github.com/libexpat/libexpat/releases/download/R_2_4_8/expat-2.4.8.tar.bz2
tar -xf expat-2.4.8.tar.bz2
sudo rm expat-2.4.8.tar.bz2
cd expat-2.4.8
./configure --enable-static --disable-shared
make
sudo make install
cd ../

- name: Install unbound
run: |
wget https://www.nlnetlabs.nl/downloads/unbound/unbound-1.22.0.tar.gz
tar xzf unbound-1.22.0.tar.gz
sudo apt install -y build-essential
sudo apt install -y libssl-dev
sudo apt install -y libexpat1-dev
sudo apt-get install -y bison
sudo apt-get install -y flex
cd unbound-1.22.0
./configure --with-libexpat=/usr --with-ssl=/usr --enable-static-exe
make
sudo make install
cd ../

- name: Update submodules
run: |
git submodule update --init --recursive

- name: Build monero
run: |
mkdir build
cd external/monero-cpp/external/monero-project
mkdir -p build/release
cd build/release
cmake -DSTATIC=ON -DBUILD_64=ON -DCMAKE_BUILD_TYPE=Release ../../
make -j3 wallet cryptonote_protocol
cd ../../../../../../

- name: Build monero-cpp
run: |
cd external/monero-cpp
mkdir -p build
cd build
cmake ..
cmake --build .
make -j3
sudo cp libmonero-cpp.so /usr/lib/
cd ../../../

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

- name: Run tests
run: |
pytest
3 changes: 2 additions & 1 deletion tests/test_monero_connection_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from utils import ConnectionChangeCollector, MoneroTestUtils as Utils


@pytest.mark.monero_connection_manager
# TODO enable connection manager tests
@pytest.mark.skipif(True, reason="TODO")
class TestMoneroConnectionManager:

def test_connection_manager(self):
Expand Down
71 changes: 36 additions & 35 deletions tests/test_monero_daemon_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,34 @@
from utils import MoneroTestUtils as Utils, TestContext, BinaryBlockContext


@pytest.mark.monero_daemon_rpc
# TODO enable rpc daemon tests
@pytest.mark.skipif(True, reason="TODO")
class TestMoneroDaemonRpc:
_daemon: MoneroDaemonRpc = Utils.get_daemon_rpc()
_wallet: MoneroWalletRpc = Utils.get_wallet_rpc()
_wallet: MoneroWalletRpc #= Utils.get_wallet_rpc()
BINARY_BLOCK_CTX: BinaryBlockContext = BinaryBlockContext()

# Can get the daemon's version
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_version(self):
version: MoneroVersion = self._daemon.get_version()
assert version.number is not None
Utils.assert_true(version.number > 0)
Utils.assert_not_none(version.is_release)

# Can indicate if it's trusted
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_is_trusted(self):
self._daemon.is_trusted()

# Can get the blockchain height
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_height(self):
height = self._daemon.get_height()
Utils.assert_true(height > 0, "Height must be greater than 0")

# Can get a block hash by height
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_id_by_height(self):
last_header: MoneroBlockHeader = self._daemon.get_last_block_header()
assert last_header.height is not None
Expand All @@ -48,19 +49,19 @@ def test_get_block_id_by_height(self):
Utils.assert_equals(64, len(hash_str))

# Can get a block template
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_template(self):
template: MoneroBlockTemplate = self._daemon.get_block_template(Utils.ADDRESS, 2)
Utils.test_block_template(template)

# Can get the last block's header
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_last_block_header(self):
last_header: MoneroBlockHeader = self._daemon.get_last_block_header()
Utils.test_block_header(last_header, True)

# Can get a block header by hash
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_header_by_hash(self):
# retrieve by hash of last block
last_header: MoneroBlockHeader = self._daemon.get_last_block_header()
Expand All @@ -77,7 +78,7 @@ def test_get_block_header_by_hash(self):
Utils.assert_equals(last_header.height - 1, header.height)

# Can get a block header by height
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_header_by_height(self):
# retrieve by height of last block
last_header: MoneroBlockHeader = self._daemon.get_last_block_header()
Expand All @@ -93,7 +94,7 @@ def test_get_block_header_by_height(self):

# Can get block headers by range
# TODO: test start with no end, vice versa, inclusivity
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_headers_by_range(self):
# determine start and end height based on number of blocks and how many blocks ago
num_blocks = 100
Expand All @@ -115,7 +116,7 @@ def test_get_block_headers_by_range(self):
i += 1

# Can get a block by hash
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_by_hash(self):
# test config
ctx = TestContext()
Expand All @@ -141,12 +142,12 @@ def test_get_block_by_hash(self):
Utils.assert_equals(None, block.txs)

# Can get blocks by hash which includes transactions (binary)
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_blocks_by_hash_binary(self) -> None:
raise NotImplementedError("Not implemented")

# Can get a block by height
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_block_by_height(self):
# config for testing blocks
ctx = TestContext()
Expand All @@ -168,7 +169,7 @@ def test_get_block_by_height(self):
Utils.assert_equals(last_header.height - 1, block.height)

# Can get blocks by height which includes transactions (binary)
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_blocks_by_height_binary(self):
# set number of blocks to test
num_blocks = 100
Expand Down Expand Up @@ -207,7 +208,7 @@ 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, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_tx_pool_statistics(self):
daemon = self._daemon
wallet = self._wallet
Expand Down Expand Up @@ -238,40 +239,40 @@ def test_get_tx_pool_statistics(self):
raise e

# Can get general information
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_general_information(self):
info: MoneroDaemonInfo = self._daemon.get_info()
Utils.test_info(info)

# Can get sync information
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_sync_information(self):
sync_info: MoneroDaemonSyncInfo = self._daemon.get_sync_info()
Utils.test_sync_info(sync_info)

# Can get hard fork information
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_hard_fork_information(self):
hard_fork_info: MoneroHardForkInfo = self._daemon.get_hard_fork_info()
Utils.test_hard_fork_info(hard_fork_info)

# Can get alternative chains
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_alternative_chains(self):
alt_chains: list[MoneroAltChain] = self._daemon.get_alt_chains()
for altChain in alt_chains:
Utils.test_alt_chain(altChain)

# Can get alternative block hashes
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_alternative_block_ids(self):
alt_block_ids: list[str] = self._daemon.get_alt_block_hashes()
for altBlockId in alt_block_ids:
Utils.assert_not_none(altBlockId)
Utils.assert_equals(64, len(altBlockId)) # TODO: common validation

# Can get, set, and reset a download bandwidth limit
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_set_download_bandwidth(self):
init_val: int = self._daemon.get_download_limit()
Utils.assert_true(init_val > 0)
Expand All @@ -291,7 +292,7 @@ def test_set_download_bandwidth(self):
Utils.assert_equals(self._daemon.get_download_limit(), init_val)

# Can get, set, and reset an upload bandwidth limit
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_set_upload_bandwidth(self):
init_val: int = self._daemon.get_upload_limit()
Utils.assert_true(init_val > 0)
Expand All @@ -311,37 +312,37 @@ def test_set_upload_bandwidth(self):
Utils.assert_equals(init_val, self._daemon.get_upload_limit())

# Can get peers with active incoming or outgoing connections
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_peers(self):
peers: list[MoneroPeer] = self._daemon.get_peers()
Utils.assert_false(len(peers) == 0, "Daemon has no incoming or outgoing peers to test")
for peer in peers:
Utils.test_peer(peer)

# Can get all known peers which may be online or offline
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_known_peers(self):
peers: list[MoneroPeer] = self._daemon.get_known_peers()
Utils.assert_false(len(peers) == 0, "Daemon has no known peers to test")
for peer in peers:
Utils.test_known_peer(peer, False)

# Can limit the number of outgoing peers
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_set_outgoing_peer_limit(self):
self._daemon.set_outgoing_peer_limit(0)
self._daemon.set_outgoing_peer_limit(8)
self._daemon.set_outgoing_peer_limit(10)

# Can limit the number of incoming peers
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_set_incoming_peer_limit(self):
self._daemon.set_incoming_peer_limit(0)
self._daemon.set_incoming_peer_limit(8)
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)
@pytest.mark.skipif(Utils.LITE_MODE is True or Utils.TEST_NOTIFICATIONS is False, reason="TEST_NOTIFICATIONS disabled")
def test_block_listener(self):
try:
# start mining if possible to help push the network along
Expand Down Expand Up @@ -372,7 +373,7 @@ def test_block_listener(self):
print(f"[!]: {str(e)}")

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

# Can get mining status
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_get_mining_status(self):
try:
# stop mining at beginning of test
Expand Down Expand Up @@ -429,7 +430,7 @@ def test_get_mining_status(self):
print(f"[!]: {str(e)}")

# Can submit a mined block to the network
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_submit_mined_block(self):
# get template to mine on
template: MoneroBlockTemplate = self._daemon.get_block_template(Utils.ADDRESS)
Expand All @@ -446,7 +447,7 @@ def test_submit_mined_block(self):
Utils.assert_equals("Block not accepted", str(e))

# Can prune the blockchain
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_prune_blockchain(self):
result: MoneroPruneResult = self._daemon.prune_blockchain(True)

Expand All @@ -457,13 +458,13 @@ def test_prune_blockchain(self):
Utils.assert_equals(0, result.pruning_seed)

# Can check for an update
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_check_for_update(self):
result: MoneroDaemonUpdateCheckResult = self._daemon.check_for_update()
Utils.test_update_check_result(result)

# Can download an update
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, "TEST_NON_RELAYS disabled")
@pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled")
def test_download_update(self):
# download to default path
result: MoneroDaemonUpdateDownloadResult = self._daemon.download_update()
Expand All @@ -484,7 +485,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, "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
Loading
Loading