Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
801c348
Bump monero-cpp to v0.9.3
everoddandeven Aug 28, 2026
88e2c98
types: move opaque STL containers to header's top
everoddandeven Aug 28, 2026
fd65092
bindings: add new data model and interface methods
everoddandeven Aug 28, 2026
e8952a3
pyi: add new data model and interfaces
everoddandeven Aug 28, 2026
e69140f
unit tests: remove xfail after monero-cpp fixes
everoddandeven Aug 28, 2026
30aaadb
unit tests: implement close tests for wallet keys
everoddandeven Aug 28, 2026
6337c0d
unit tests: use pytest.raises
everoddandeven Aug 28, 2026
9788340
tests: update rules for not_supported and not_implemeneted markers
everoddandeven Aug 29, 2026
ca350a6
tests: update BUSY error
everoddandeven Aug 29, 2026
e534605
integration tests: use pytest.raises
everoddandeven Aug 29, 2026
2a4331b
pyi: fix MoneroWallet.get_new_key_images_from_last_import return type
everoddandeven Aug 29, 2026
eb9be51
tests: align sync testers with reference
everoddandeven Aug 29, 2026
73d500b
integration tests: minor fixes
everoddandeven Aug 29, 2026
7a10e79
pyi: fix monero_mineri_data difficulty docstrings
everoddandeven Aug 29, 2026
6c0ec8a
integration tests: add tests for new daemon methods
everoddandeven Aug 29, 2026
9bfed7c
unit tests: add tests for new daemon data model
everoddandeven Aug 29, 2026
3642dd2
unit tests: minor refactory offline full wallet tests
everoddandeven Aug 29, 2026
b69edc9
tests: minor fixes
everoddandeven Aug 29, 2026
51d4ffa
wallet full: fix get file buffer bindings
everoddandeven Aug 29, 2026
2bb6d52
unit tests: add full wallet move test
everoddandeven Aug 29, 2026
f6bfa52
integration tests: restore original log level after tests
everoddandeven Aug 29, 2026
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
84 changes: 41 additions & 43 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,69 +1,67 @@
from __future__ import annotations

import logging
import pytest

from os.path import splitext
from typing import TYPE_CHECKING, Generator, Optional, cast

import pytest

from tests.utils.gen_utils import GenUtils

if TYPE_CHECKING:
from pluggy import Result # runtime-optional (pluggy < 1.2), only needed for typing

logger: logging.Logger = logging.getLogger("conftest")

_NOT_SUPPORTED_HINTS: tuple[str, ...] = ("not supported", "does not support", "doesn't support")

def pytest_runtest_logreport(report: pytest.TestReport) -> None:
if report.outcome != "rerun": # type: ignore - pytest-rerunfailures sets this outcome
return

message: str
def _crash_message(report: pytest.TestReport) -> str:
reprcrash: object = getattr(report.longrepr, "reprcrash", None)
message: Optional[str] = getattr(reprcrash, "message", None)
return str(message) if message else (report.longreprtext or "unknown")

try:
crash_msg = report.longrepr.reprcrash.message # type: ignore
message = str(crash_msg) if crash_msg is not None else "" # type: ignore
except AttributeError:
message = report.longreprtext
except Exception as e:
message = str(e)

if len(message) == 0:
message = "Unknwon"

logger.error(f"EXPECTED FAILURE: {message}")
def pytest_runtest_logreport(report: pytest.TestReport) -> None:
if report.outcome != "rerun": # type: ignore # set by pytest-rerunfailures
return
logger.error(f"EXPECTED FAILURE: {_crash_message(report)}")
logger.warning(f"RERUN {report.nodeid}")


def pytest_configure(config: pytest.Config) -> None:
# inject current date/time into the configured log file name
log_file: str = config.getini("log_file") # type: ignore

# timestamp the log file so each run keeps its own
log_file: str = cast(str, config.getini("log_file"))
if not log_file:
return

name, ext = splitext(log_file)
config.option.log_file = f"{name}_{GenUtils.current_date_time_str()}{ext}"


def pytest_runtest_call(item: pytest.Item):
# get not_supported marker
marker: pytest.Mark | None = item.get_closest_marker("not_supported")
not_implemented: bool = False
def pytest_collection_modifyitems(items: list[pytest.Item]) -> None:
# `not_implemented` == non-strict xfail: xfails while it raises, xpasses once done
for item in items:
if item.get_closest_marker("not_implemented") is not None:
item.add_marker(pytest.mark.xfail(reason="not implemented", strict=False))

if marker is None:
# get not_implemented marker
marker = item.get_closest_marker("not_implemented")
not_implemented = True

if marker is None:
# marker not found
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item: pytest.Item) -> Generator[None, Result[None], None]:
# `not_supported`: the inherited test must raise a "not supported" error;
# that's a pass, anything else (or no error) is a failure.
if item.get_closest_marker("not_supported") is None:
yield
return

outcome: Result[None] = yield

try:
# run test
item.runtest()
except Exception as e:
e_str = str(e).lower()
if "not supported" in e_str or "does not support" in e_str or "doesn't support" in e_str:
# Ok
pytest.xfail(str(e))
if not_implemented and "not implemented" in e_str:
pytest.xfail(str(e))
raise
else:
# fail test
pytest.fail("Expected test to fail")
outcome.get_result()
except Exception as error:
if any(hint in str(error).lower() for hint in _NOT_SUPPORTED_HINTS):
logger.debug(f"NOT SUPPORTED (as expected): {error}")
outcome.force_result(None)
return

outcome.force_exception(pytest.fail.Exception("Expected a 'not supported' error"))
2 changes: 1 addition & 1 deletion external/monero-cpp
Submodule monero-cpp updated 341 files
6 changes: 3 additions & 3 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[pytest]
minversion = 6.0
required_plugins = pytest-rerunfailures pytest-timeout pytest-cov
addopts = -s -v --reruns 5 --reruns-delay 10 --only-rerun "BUSY"
addopts = -s -v --reruns 5 --reruns-delay 10 --only-rerun "Daemon is busy"
log_level = INFO
log_cli = True
log_cli_level = INFO
Expand All @@ -15,5 +15,5 @@ testpaths =
markers =
unit: fast unit tests, no external dependencies
integration: slow integration tests, requires external services
not_supported: expects not supported error
not_implemented: expects not implemented error
not_supported: inherited test whose operation is permanently unsupported for this type; passes when it raises a "not supported" error, fails otherwise
not_implemented: inherited test whose operation is not implemented yet; applied as a non-strict xfail (xfails while it raises, xpasses once the feature lands)
64 changes: 60 additions & 4 deletions src/cpp/daemon/py_monero_daemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::shared_ptr<monero_block_template>, monero_daemon, get_block_template, wallet_address, reserve_size);
}

std::shared_ptr<monero_miner_data> get_miner_data() override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_miner_data>, monero_daemon, get_miner_data);
}

std::string calculate_pow(uint32_t major_version, uint64_t height, const std::string& block_blob, const std::string& seed_hash) override {
PYBIND11_OVERRIDE(std::string, monero_daemon, calculate_pow, major_version, height, block_blob, seed_hash);
}

std::shared_ptr<monero_add_auxiliary_pow_result> add_auxiliary_pow(const std::string& block_template_blob, const std::vector<std::shared_ptr<monero_auxiliary_pow>>& aux_pow) override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_add_auxiliary_pow_result>, monero_daemon, add_auxiliary_pow, block_template_blob, aux_pow);
}

std::shared_ptr<monero_block_header> get_last_block_header() override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_block_header>, monero_daemon, get_last_block_header);
}
Expand All @@ -129,8 +141,8 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::shared_ptr<monero_block>, monero_daemon, get_block_by_hash, hash);
}

std::vector<std::shared_ptr<monero_block>> get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune) override {
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<monero_block>>, monero_daemon, get_blocks_by_hash, block_hashes, start_height, prune);
std::shared_ptr<monero_get_blocks_by_hash_result> get_blocks_by_hash(const std::vector<std::string>& block_hashes, uint64_t start_height, bool prune, uint64_t max_block_count = 0) override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_get_blocks_by_hash_result>, monero_daemon, get_blocks_by_hash, block_hashes, start_height, prune, max_block_count);
}

std::shared_ptr<monero_block> get_block_by_height(uint64_t height) override {
Expand All @@ -149,8 +161,8 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<monero_block>>, monero_daemon, get_blocks_by_range_chunked, start_height, end_height, max_chunk_size);
}

std::vector<std::string> get_block_hashes(const std::vector<std::string>& block_hashes, uint64_t start_height) override {
PYBIND11_OVERRIDE(std::vector<std::string>, monero_daemon, get_block_hashes, block_hashes, start_height);
std::shared_ptr<monero_get_block_hashes_result> get_block_hashes(const std::vector<std::string>& block_hashes) override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_get_block_hashes_result>, monero_daemon, get_block_hashes, block_hashes);
}

std::shared_ptr<monero_tx> get_tx(const std::string& tx_hash, bool prune = false) override {
Expand Down Expand Up @@ -225,6 +237,10 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::vector<monero_key_image_spent_status>, monero_daemon, get_key_image_spent_statuses, key_images);
}

std::vector<uint64_t> get_output_indices(const std::string& tx_hash) override {
PYBIND11_OVERRIDE(std::vector<uint64_t>, monero_daemon, get_output_indices, tx_hash);
}

std::vector<std::shared_ptr<monero_output>> get_outputs(const std::vector<monero_output>& outputs) override {
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<monero_output>>, monero_daemon, get_outputs, outputs);
}
Expand All @@ -245,6 +261,10 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::shared_ptr<monero_daemon_sync_info>, monero_daemon, get_sync_info);
}

std::shared_ptr<monero_daemon_network_stats> get_network_stats() override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_daemon_network_stats>, monero_daemon, get_network_stats);
}

std::shared_ptr<monero_hard_fork_info> get_hard_fork_info() override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_hard_fork_info>, monero_daemon, get_hard_fork_info);
}
Expand Down Expand Up @@ -289,6 +309,10 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<monero_peer>>, monero_daemon, get_known_peers);
}

std::vector<std::shared_ptr<monero_peer>> get_public_peers(bool include_offline = false) override {
PYBIND11_OVERRIDE(std::vector<std::shared_ptr<monero_peer>>, monero_daemon, get_public_peers, include_offline);
}

void set_outgoing_peer_limit(int limit) override {
PYBIND11_OVERRIDE(void, monero_daemon, set_outgoing_peer_limit, limit);
}
Expand All @@ -309,6 +333,10 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(void, monero_daemon, set_peer_ban, ban);
}

std::shared_ptr<monero_ban> get_peer_ban(const std::string& address) override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_ban>, monero_daemon, get_peer_ban, address);
}

void start_mining(const std::string &address, boost::optional<uint64_t> num_threads, boost::optional<bool> is_background, boost::optional<bool> ignore_battery) override {
PYBIND11_OVERRIDE(void, monero_daemon, start_mining, address, num_threads, is_background, ignore_battery);
}
Expand Down Expand Up @@ -337,6 +365,34 @@ class PyMoneroDaemon : public monero_daemon {
PYBIND11_OVERRIDE(std::shared_ptr<monero_prune_result>, monero_daemon, prune_blockchain, check);
}

void save_blockchain() override {
PYBIND11_OVERRIDE(void, monero_daemon, save_blockchain);
}

uint64_t pop_blocks(uint64_t num_blocks) override {
PYBIND11_OVERRIDE(uint64_t, monero_daemon, pop_blocks, num_blocks);
}

void flush_cache(bool bad_blocks = false) override {
PYBIND11_OVERRIDE(void, monero_daemon, flush_cache, bad_blocks);
}

void set_bootstrap_daemon(const std::string& address, const std::string& username = "", const std::string& password = "", const std::string& proxy = "") override {
PYBIND11_OVERRIDE(void, monero_daemon, set_bootstrap_daemon, address, username, password, proxy);
}

void set_log_hash_rate(bool is_visible) override {
PYBIND11_OVERRIDE(void, monero_daemon, set_log_hash_rate, is_visible);
}

void set_log_level(int level) override {
PYBIND11_OVERRIDE(void, monero_daemon, set_log_level, level);
}

std::string set_log_categories(const std::string& categories = "") override {
PYBIND11_OVERRIDE(std::string, monero_daemon, set_log_categories, categories);
}

std::shared_ptr<monero_daemon_update_check_result> check_for_update() override {
PYBIND11_OVERRIDE(std::shared_ptr<monero_daemon_update_check_result>, monero_daemon, check_for_update);
}
Expand Down
Loading
Loading