diff --git a/src/cpp/py_monero.cpp b/src/cpp/py_monero.cpp index 9380205..d136e89 100644 --- a/src/cpp/py_monero.cpp +++ b/src/cpp/py_monero.cpp @@ -1446,14 +1446,14 @@ PYBIND11_MODULE(monero, m) { assert_wallet_is_not_closed(&self); MONERO_CATCH_AND_RETHROW(self.get_connection_manager()); }) - .def("set_daemon_connection", [](PyMoneroWallet& self, const monero::monero_rpc_connection& connection) { + .def("set_daemon_connection", [](PyMoneroWallet& self, const boost::optional& connection) { assert_wallet_is_not_closed(&self); MONERO_CATCH_AND_RETHROW(self.set_daemon_connection(connection)); }, py::arg("connection")) .def("set_daemon_connection", [](PyMoneroWallet& self, const std::string& uri, const std::string& username, const std::string& password, const std::string& proxy) { assert_wallet_is_not_closed(&self); MONERO_CATCH_AND_RETHROW(self.set_daemon_connection(uri, username, password, proxy)); - }, py::arg("uri") = "", py::arg("username") = "", py::arg("password") = "", py::arg("proxy") = "") + }, py::arg("uri"), py::arg("username") = "", py::arg("password") = "", py::arg("proxy") = "") .def("get_daemon_connection", [](PyMoneroWallet& self) { assert_wallet_is_not_closed(&self); MONERO_CATCH_AND_RETHROW(self.get_daemon_connection()); @@ -2012,7 +2012,7 @@ PYBIND11_MODULE(monero, m) { MONERO_CATCH_AND_RETHROW(monero::monero_wallet_full::open_wallet_data(password, nettype, keys_data, cache_data, daemon_connection)); }, py::arg("password"), py::arg("nettype"), py::arg("keys_data"), py::arg("cache_data"), py::arg("daemon_connection")) .def_static("create_wallet", [](const PyMoneroWalletConfig& config) { - MONERO_CATCH_AND_RETHROW(monero::monero_wallet_full::create_wallet(config)); + MONERO_CATCH_AND_RETHROW(PyMoneroWalletFull::create_wallet(config)); }, py::arg("config")) .def_static("get_seed_languages", []() { MONERO_CATCH_AND_RETHROW(monero::monero_wallet_full::get_seed_languages()); diff --git a/src/cpp/wallet/py_monero_wallet_full.cpp b/src/cpp/wallet/py_monero_wallet_full.cpp index b67f01e..e42993f 100644 --- a/src/cpp/wallet/py_monero_wallet_full.cpp +++ b/src/cpp/wallet/py_monero_wallet_full.cpp @@ -9,3 +9,14 @@ void PyMoneroWalletFull::close(bool save) { void PyMoneroWalletFull::set_account_label(uint32_t account_idx, const std::string& label) { set_subaddress_label(account_idx, 0, label); } + +monero_wallet_full* PyMoneroWalletFull::create_wallet(const monero_wallet_config& config, std::unique_ptr http_client_factory) { + try { + return monero_wallet_full::create_wallet(config, std::move(http_client_factory)); + } catch(const std::exception& ex) { + std::string msg = ex.what(); + if (msg.find("file already exists") != std::string::npos && config.m_path != boost::none) + msg = std::string("Wallet already exists: ") + config.m_path.get(); + throw PyMoneroError(msg); + } +} diff --git a/src/cpp/wallet/py_monero_wallet_full.h b/src/cpp/wallet/py_monero_wallet_full.h index c5e5b7c..f409800 100644 --- a/src/cpp/wallet/py_monero_wallet_full.h +++ b/src/cpp/wallet/py_monero_wallet_full.h @@ -6,6 +6,8 @@ class PyMoneroWalletFull : public monero::monero_wallet_full { public: + static monero_wallet_full* create_wallet(const monero_wallet_config& config, std::unique_ptr http_client_factory = nullptr); + bool is_closed() const { return m_is_closed; } void close(bool save = false) override; void set_account_label(uint32_t account_idx, const std::string& label); diff --git a/src/python/monero_wallet.pyi b/src/python/monero_wallet.pyi index 0e94c63..08ff205 100644 --- a/src/python/monero_wallet.pyi +++ b/src/python/monero_wallet.pyi @@ -928,7 +928,7 @@ class MoneroWallet: """ ... @typing.overload - def set_daemon_connection(self, uri: str = '', username: str = '', password: str = '', proxy_uri: str = '') -> None: + def set_daemon_connection(self, uri: str, username: str = '', password: str = '', proxy_uri: str = '') -> None: """ Set the wallet's daemon connection. diff --git a/tests/test_monero_connection_manager.py b/tests/test_monero_connection_manager.py index 6a199ec..14329ce 100644 --- a/tests/test_monero_connection_manager.py +++ b/tests/test_monero_connection_manager.py @@ -1,4 +1,5 @@ import pytest +import logging from typing import Optional from monero import ( @@ -6,11 +7,18 @@ ) from utils import ConnectionChangeCollector, TestUtils as Utils +logger: logging.Logger = logging.getLogger("TestMoneroConnectionManager") # TODO enable connection manager tests @pytest.mark.skipif(True, reason="TODO") class TestMoneroConnectionManager: + @pytest.fixture(autouse=True) + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before {request.node.name}") # type: ignore + yield + logger.info(f"After {request.node.name}") # type: ignore + def test_connection_manager(self): wallet_rpcs: list[MoneroWallet] = Utils.get_wallets("rpc") connection_manager: Optional[MoneroConnectionManager] = None diff --git a/tests/test_monero_daemon_rpc.py b/tests/test_monero_daemon_rpc.py index 951d534..e320968 100644 --- a/tests/test_monero_daemon_rpc.py +++ b/tests/test_monero_daemon_rpc.py @@ -13,7 +13,7 @@ ) from utils import TestUtils as Utils, TestContext, BinaryBlockContext, MiningUtils -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("TestMoneroDaemonRpc") class TestMoneroDaemonRpc: @@ -30,9 +30,9 @@ def before_all(self): @pytest.fixture(autouse=True) def before_each(self, request: pytest.FixtureRequest): - logger.info(f"Before test {request.node.name}") # type: ignore + logger.info(f"Before {request.node.name}") # type: ignore yield - logger.info(f"After test {request.node.name}") # type: ignore + logger.info(f"After {request.node.name}") # type: ignore #endregion @@ -654,6 +654,7 @@ def test_get_mining_status(self): # Can submit a mined block to the network @pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled") + @pytest.mark.flaky(reruns=5, reruns_delay=5) def test_submit_mined_block(self): # get template to mine on template: MoneroBlockTemplate = self._daemon.get_block_template(Utils.ADDRESS) @@ -682,14 +683,14 @@ def test_prune_blockchain(self): # Can check for an update @pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled") - @pytest.mark.flaky(reruns=5, reruns_delay=2) + @pytest.mark.flaky(reruns=5, reruns_delay=5) 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, reason="TEST_NON_RELAYS disabled") - @pytest.mark.flaky(reruns=5, reruns_delay=2) + @pytest.mark.flaky(reruns=5, reruns_delay=5) def test_download_update(self): # download to default path result: MoneroDaemonUpdateDownloadResult = self._daemon.download_update() diff --git a/tests/test_monero_rpc_connection.py b/tests/test_monero_rpc_connection.py index 0f6f521..d95fa32 100644 --- a/tests/test_monero_rpc_connection.py +++ b/tests/test_monero_rpc_connection.py @@ -1,11 +1,20 @@ import pytest +import logging from monero import MoneroRpcConnection from utils import TestUtils as Utils +logger: logging.Logger = logging.getLogger("TestMoneroRpcConnection") + class TestMoneroRpcConnection: + @pytest.fixture(autouse=True) + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before {request.node.name}") # type: ignore + yield + logger.info(f"After {request.node.name}") # type: ignore + # Test monerod rpc connection def test_node_rpc_connection(self): connection = MoneroRpcConnection(Utils.DAEMON_RPC_URI, Utils.DAEMON_RPC_USERNAME, Utils.DAEMON_RPC_PASSWORD) diff --git a/tests/test_monero_utils.py b/tests/test_monero_utils.py index 6db00e7..c0f512c 100644 --- a/tests/test_monero_utils.py +++ b/tests/test_monero_utils.py @@ -1,5 +1,8 @@ from __future__ import annotations + import pytest +import logging + from typing import Any from configparser import ConfigParser from monero import ( @@ -7,6 +10,8 @@ ) from utils import TestUtils, AddressBook, KeysBook +logger: logging.Logger = logging.getLogger("TestMoneroUtils") + class TestMoneroUtils: @@ -35,6 +40,14 @@ def config(self) -> TestMoneroUtils.Config: parser.read('tests/config/test_monero_utils.ini') return TestMoneroUtils.Config.parse(parser) + @pytest.fixture(autouse=True) + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before {request.node.name}") # type: ignore + yield + logger.info(f"After {request.node.name}") # type: ignore + + #region Tests + # Can get integrated addresses def test_get_integrated_address(self, config: TestMoneroUtils.Config): primary_address: str = config.stagenet.primary_address_4 @@ -270,3 +283,5 @@ def test_get_payment_uri(self, config: TestMoneroUtils.Config): payment_uri = MoneroUtils.get_payment_uri(tx_config) query = "tx_amount=0.250000000000&recipient_name=John%20Doe&tx_description=My%20transfer%20to%20wallet" assert payment_uri == f"monero:{address}?{query}" + + #endregion diff --git a/tests/test_monero_wallet_common.py b/tests/test_monero_wallet_common.py index a5b134b..0379576 100644 --- a/tests/test_monero_wallet_common.py +++ b/tests/test_monero_wallet_common.py @@ -13,7 +13,7 @@ ) from utils import TestUtils, WalletEqualityUtils -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("TestMoneroWalletCommon") class BaseTestMoneroWallet(ABC): @@ -83,9 +83,9 @@ def test_config(self) -> BaseTestMoneroWallet.Config: @pytest.fixture(autouse=True) def before_each(self, request: pytest.FixtureRequest): - logger.info(f"Before test {request.node.name}") # type: ignore + logger.info(f"Before {request.node.name}") # type: ignore yield - logger.info(f"After test {request.node.name}") # type: ignore + logger.info(f"After {request.node.name}") # type: ignore #endregion @@ -130,6 +130,7 @@ def test_create_wallet_random(self) -> None: try: config = MoneroWalletConfig() config.language = "english" + self._create_wallet(config) raise Exception("Should have thrown error") except Exception as e: TestUtils.assert_equals("Unknown language: english", str(e)) diff --git a/tests/test_monero_wallet_full.py b/tests/test_monero_wallet_full.py index 2bc430a..90662f3 100644 --- a/tests/test_monero_wallet_full.py +++ b/tests/test_monero_wallet_full.py @@ -1,4 +1,5 @@ import pytest +import logging from typing import Optional from typing_extensions import override @@ -10,6 +11,8 @@ from utils import TestUtils as Utils from test_monero_wallet_common import BaseTestMoneroWallet +logger: logging.Logger = logging.getLogger("TestMoneroWalletFull") + class TestMoneroWalletFull(BaseTestMoneroWallet): @@ -79,6 +82,13 @@ def _get_seed_languages(self) -> list[str]: def get_test_wallet(self) -> MoneroWallet: return Utils.get_wallet_full() + @pytest.fixture(autouse=True) + @override + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before test {request.node.name}") # type: ignore + yield + logger.info(f"After test {request.node.name}") # type: ignore + #endregion #region Tests @@ -127,26 +137,6 @@ def test_create_subaddress(self): def test_get_height_by_date(self): return super().test_get_height_by_date() - @pytest.mark.skip(reason="TODO") - @override - def test_create_wallet_random(self) -> None: - return super().test_create_wallet_random() - - @pytest.mark.skip(reason="TODO") - @override - def test_create_wallet_from_seed(self, test_config: BaseTestMoneroWallet.Config) -> None: - return super().test_create_wallet_from_seed(test_config) - - @pytest.mark.skip(reason="TODO") - @override - def test_create_wallet_from_keys(self) -> None: - return super().test_create_wallet_from_keys() - - @pytest.mark.skip(reason="TODO") - @override - def test_create_wallet_from_seed_with_offset(self) -> None: - return super().test_create_wallet_from_seed_with_offset() - @pytest.mark.skip(reason="TODO") @override def test_wallet_equality_ground_truth(self): @@ -167,16 +157,6 @@ def test_set_tx_note(self) -> None: def test_set_tx_notes(self): return super().test_set_tx_notes() - @pytest.mark.skip(reason="TODO") - @override - def test_set_daemon_connection(self): - return super().test_set_daemon_connection() - - @pytest.mark.skip(reason="TODO") - @override - def test_mining(self): - return super().test_mining() - @pytest.mark.skip(reason="TODO") @override def test_export_key_images(self): diff --git a/tests/test_monero_wallet_keys.py b/tests/test_monero_wallet_keys.py index 22bc849..dd39b4a 100644 --- a/tests/test_monero_wallet_keys.py +++ b/tests/test_monero_wallet_keys.py @@ -11,7 +11,7 @@ from test_monero_wallet_common import BaseTestMoneroWallet -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("TestMoneroWalletKeys") class TestMoneroWalletKeys(BaseTestMoneroWallet): @@ -21,6 +21,7 @@ class TestMoneroWalletKeys(BaseTestMoneroWallet): _wallet: MoneroWalletKeys = Utils.get_wallet_keys() # type: ignore @pytest.fixture(autouse=True) + @override def before_each(self, request: pytest.FixtureRequest): logger.info(f"Before test {request.node.name}") # type: ignore yield @@ -196,6 +197,8 @@ def test_mining(self): #endregion + #region Tests + @pytest.mark.skipif(Utils.TEST_NON_RELAYS is False, reason="TEST_NON_RELAYS disabled") @override def test_create_wallet_random(self) -> None: @@ -458,6 +461,8 @@ def test_get_subaddress_by_index(self): subaddress, self._wallet.get_subaddresses(account.index, [subaddress.index])[0] ) + #endregion + #region Utils def _get_subaddress(self, account_idx: int, subaddress_idx: int) -> Optional[MoneroSubaddress]: diff --git a/tests/test_monero_wallet_rpc.py b/tests/test_monero_wallet_rpc.py index 89cd3d8..c2ea326 100644 --- a/tests/test_monero_wallet_rpc.py +++ b/tests/test_monero_wallet_rpc.py @@ -1,10 +1,14 @@ import pytest +import logging + from monero import MoneroWallet, MoneroWalletConfig, MoneroDaemonRpc, MoneroWalletRpc from typing_extensions import override from utils import TestUtils as Utils from test_monero_wallet_common import BaseTestMoneroWallet +logger: logging.Logger = logging.getLogger("TestMoneroWalletRpc") + class TestMoneroWalletRpc(BaseTestMoneroWallet): @@ -33,6 +37,13 @@ def _close_wallet(self, wallet: MoneroWallet, save: bool = False) -> None: def _get_seed_languages(self) -> list[str]: return self._wallet.get_seed_languages() # type: ignore + @pytest.fixture(autouse=True) + @override + def before_each(self, request: pytest.FixtureRequest): + logger.info(f"Before test {request.node.name}") # type: ignore + yield + logger.info(f"After test {request.node.name}") # type: ignore + #endregion #region Tests @@ -118,16 +129,11 @@ def test_set_tx_note(self) -> None: def test_set_tx_notes(self): return super().test_set_tx_notes() - @pytest.mark.skip(reason="TODO") + @pytest.mark.skip(reason="TODO implement TestUtils.create_wallet_rpc()") @override def test_set_daemon_connection(self): return super().test_set_daemon_connection() - @pytest.mark.skip(reason="TODO") - @override - def test_mining(self): - return super().test_mining() - @pytest.mark.skip(reason="TODO") @override def test_export_key_images(self): diff --git a/tests/utils/mining_utils.py b/tests/utils/mining_utils.py index 3a42758..8d92253 100644 --- a/tests/utils/mining_utils.py +++ b/tests/utils/mining_utils.py @@ -6,7 +6,7 @@ from .test_utils import TestUtils as Utils from .string_utils import StringUtils -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("MiningUtils") class MiningUtils: diff --git a/tests/utils/print_height.py b/tests/utils/print_height.py index 8d37c7b..b80e403 100644 --- a/tests/utils/print_height.py +++ b/tests/utils/print_height.py @@ -3,7 +3,7 @@ from .test_utils import TestUtils -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("PrintHeight") class PrintHeight(ABC): diff --git a/tests/utils/sample_connection_listener.py b/tests/utils/sample_connection_listener.py index 56507a9..6183652 100644 --- a/tests/utils/sample_connection_listener.py +++ b/tests/utils/sample_connection_listener.py @@ -4,7 +4,7 @@ from typing_extensions import override from monero import MoneroConnectionManagerListener, MoneroRpcConnection -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("SampleConnectionListener") class SampleConnectionListener(MoneroConnectionManagerListener): diff --git a/tests/utils/string_utils.py b/tests/utils/string_utils.py index fdf0830..08067ae 100644 --- a/tests/utils/string_utils.py +++ b/tests/utils/string_utils.py @@ -6,4 +6,8 @@ class StringUtils(ABC): @classmethod def get_percentage(cls, n: int, m: int, precision: int = 2) -> str: r: float = (n / m)*100 - return f"{round(r, precision)}%" + return cls.get_percentage_float(r, precision) + + @classmethod + def get_percentage_float(cls, n: float, precision: int = 2) -> str: + return f"{round(n, precision)}%" diff --git a/tests/utils/test_utils.py b/tests/utils/test_utils.py index 68592a4..8b92a40 100644 --- a/tests/utils/test_utils.py +++ b/tests/utils/test_utils.py @@ -24,7 +24,7 @@ from .tx_context import TxContext from .binary_block_context import BinaryBlockContext -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("TestUtils") class TestUtils(ABC): @@ -230,6 +230,8 @@ def assert_equals(cls, expr1: Any, expr2: Any, message: str = "assertion failed" str1 = expr1.serialize() str2 = expr2.serialize() assert str1 == str2, f"{message}: {str1} == {str2}" + elif isinstance(expr1, MoneroRpcConnection) and isinstance(expr2, MoneroRpcConnection): + cls.assert_connection_equals(expr1, expr2) else: assert expr1 == expr2, f"{message}: {expr1} == {expr2}" @@ -1053,5 +1055,16 @@ def test_get_blocks_range( cls.assert_equals(real_start_height + i, block.height) cls.test_block(block, block_ctx) + @classmethod + def assert_connection_equals(cls, c1: Optional[MoneroRpcConnection], c2: Optional[MoneroRpcConnection]) -> None: + if c1 is None and c2 is None: + return + + assert c1 is not None + assert c2 is not None + assert c1.uri == c2.uri + assert c1.username == c2.username + assert c1.password == c2.password + TestUtils.load_config() diff --git a/tests/utils/wallet_sync_printer.py b/tests/utils/wallet_sync_printer.py index 24d74ae..66b3510 100644 --- a/tests/utils/wallet_sync_printer.py +++ b/tests/utils/wallet_sync_printer.py @@ -3,7 +3,7 @@ from typing_extensions import override from monero import MoneroWalletListener -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("WalletSyncPrinter") class WalletSyncPrinter(MoneroWalletListener): diff --git a/tests/utils/wallet_tx_tracker.py b/tests/utils/wallet_tx_tracker.py index 54d74fc..ef73a22 100644 --- a/tests/utils/wallet_tx_tracker.py +++ b/tests/utils/wallet_tx_tracker.py @@ -2,7 +2,7 @@ from time import sleep from monero import MoneroDaemon, MoneroWallet -logger: logging.Logger = logging.getLogger(__name__) +logger: logging.Logger = logging.getLogger("WalletTxTracker") class WalletTxTracker: