Merge pull request #10818

85f8bbb tests: make libwallet_api_tests work under ctest, add tests (selsta)

ACKs: plowsof, SNeedlewoods
This commit is contained in:
tobtoht
2026-07-20 09:08:09 +00:00
19 changed files with 574 additions and 322 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ on:
env:
REMOVE_BUNDLED_PACKAGES : sudo rm -rf /usr/local
# ARCH="default" (not "native") ensures, that a different execution host can execute binaries compiled elsewhere.
BUILD_DEFAULT: 'cmake -S . -B build -D ARCH="default" -D BUILD_TESTS=ON -D ENABLE_FUZZ_TEST=ON -D CMAKE_BUILD_TYPE=Release && cmake --build build --target all && cmake --build build --target wallet_api'
BUILD_DEFAULT: 'cmake -S . -B build -D ARCH="default" -D BUILD_TESTS=ON -D BUILD_GUI_DEPS=ON -D ENABLE_FUZZ_TEST=ON -D CMAKE_BUILD_TYPE=Release && cmake --build build --target all'
APT_INSTALL_LINUX: 'apt -y install build-essential cmake libboost-all-dev libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler ccache curl git'
APT_SET_CONF: |
tee -a /etc/apt/apt.conf.d/80-custom << EOF
+10
View File
@@ -975,6 +975,16 @@ bool WalletImpl::init(const std::string &daemon_address, uint64_t upper_transact
return doInit(daemon_address, proxy_address, upper_transaction_size_limit, use_ssl);
}
void WalletImpl::allowMismatchedDaemonVersion(bool allow_mismatch)
{
m_wallet->allow_mismatched_daemon_version(allow_mismatch);
}
void WalletImpl::setRingDatabase(const std::string &path)
{
m_wallet->set_ring_database(path);
}
void WalletImpl::setRefreshFromBlockHeight(uint64_t refresh_from_block_height)
{
if (checkBackgroundSync("cannot change refresh height"))
+2
View File
@@ -106,6 +106,8 @@ public:
std::string filename() const override;
std::string keysFilename() const override;
bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false, const std::string &proxy_address = "") override;
void allowMismatchedDaemonVersion(bool allow_mismatch) override;
void setRingDatabase(const std::string &path) override;
bool connectToDaemon() override;
ConnectionStatus connected() const override;
void setTrustedDaemon(bool arg) override;
+2
View File
@@ -546,6 +546,8 @@ struct Wallet
* \return - true on success
*/
virtual bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false, const std::string &proxy_address = "") = 0;
virtual void allowMismatchedDaemonVersion(bool allow_mismatch) = 0;
virtual void setRingDatabase(const std::string &path) = 0;
/*!
* \brief createWatchOnly - Creates a watch only wallet
+13 -1
View File
@@ -209,7 +209,19 @@ ctest -R hash-blake2b
# Libwallet API tests
[TODO]
The libwallet API tests are located under `tests/libwallet_api_tests/`.
They are run through `ctest` like the functional tests and do not require a
pre-existing testnet blockchain or manually created wallets. The CTest wrapper
starts a temporary fakechain daemon, creates temporary wallets and ring database
directories, mines the required blocks, and removes the process when the test
finishes.
These tests are added to CTest when the build is configured with
`BUILD_GUI_DEPS=ON`. To run only this test from such a build directory:
```bash
ctest --test-dir build -R libwallet_api_tests --output-on-failure
```
# Net Load tests
+5 -1
View File
@@ -33,6 +33,8 @@ set(libwallet_api_tests_sources
set(libwallet_api_tests_headers
)
find_package(Python3 REQUIRED)
monero_add_minimal_executable(libwallet_api_tests
${libwallet_api_tests_sources}
${libwallet_api_tests_headers})
@@ -67,4 +69,6 @@ set_property(TARGET libwallet_api_tests
add_test(
NAME libwallet_api_tests
COMMAND libwallet_api_tests)
COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/libwallet_api_tests.py" "${CMAKE_BINARY_DIR}" "$<TARGET_FILE:daemon>" "$<TARGET_FILE:libwallet_api_tests>")
set_tests_properties(libwallet_api_tests PROPERTIES TIMEOUT 240)
@@ -0,0 +1,258 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2024, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import json
import os
import shutil
import socket
import subprocess
import sys
import threading
import time
import urllib.error
import urllib.request
from signal import SIGTERM
USAGE = "usage: libwallet_api_tests.py <builddir> <monerod_exe> <libwallet_api_tests_exe>"
MINED_BLOCKS = 90
def reserve_ports(count):
sockets = []
ports = []
try:
for _ in range(count):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1", 0))
sockets.append(s)
ports.append(s.getsockname()[1])
finally:
for s in sockets:
s.close()
return ports
def wait_for_port(port, timeout=20):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.2)
if s.connect_ex(("127.0.0.1", port)) == 0:
return
time.sleep(0.1)
raise RuntimeError("timed out waiting for port {}".format(port))
def rpc_json(rpc_port, path, payload, timeout=30):
data = json.dumps(payload).encode("utf-8")
request = urllib.request.Request(
"http://127.0.0.1:{}{}".format(rpc_port, path),
data=data,
headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(request, timeout=timeout) as response:
return json.loads(response.read().decode("utf-8"))
def get_height(rpc_port):
response = rpc_json(rpc_port, "/get_height", {})
return int(response["height"])
def wait_for_height(rpc_port, height, timeout=180):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
try:
current_height = get_height(rpc_port)
if current_height >= height:
return current_height
except (urllib.error.URLError, TimeoutError, KeyError):
pass
time.sleep(0.5)
raise RuntimeError("timed out waiting for regtest height {}".format(height))
def generate_blocks(rpc_port, address, blocks):
response = rpc_json(
rpc_port,
"/json_rpc",
{
"jsonrpc": "2.0",
"id": "0",
"method": "generateblocks",
"params": {
"wallet_address": address,
"amount_of_blocks": blocks,
},
},
)
if "error" in response:
raise RuntimeError("generateblocks failed: {}".format(response["error"]))
return response
def pulse_blocks(stop_event, rpc_port, address):
while not stop_event.wait(1.0):
try:
generate_blocks(rpc_port, address, 1)
except Exception as e:
print("Failed to generate regtest block: {}".format(e))
sys.stdout.flush()
return
def stop_process(process):
if process.poll() is not None:
return
try:
process.send_signal(SIGTERM)
process.wait(timeout=20)
except subprocess.TimeoutExpired:
process.kill()
process.wait()
def main():
if len(sys.argv) != 4:
print(USAGE)
return 1
builddir = os.path.abspath(sys.argv[1])
monerod = os.path.abspath(sys.argv[2])
test_exe = os.path.abspath(sys.argv[3])
for executable in (monerod, test_exe):
if not os.path.exists(executable):
print("missing executable: {}".format(executable))
return 1
run_dir = os.path.join(builddir, "libwallet-api-tests-directory")
wallets_dir = os.path.join(run_dir, "wallets")
ringdb_dir = os.path.join(run_dir, "ringdb")
data_dir = os.path.join(run_dir, "regtest")
log_dir = os.path.join(builddir, "tests", "libwallet_api_tests")
shutil.rmtree(run_dir, ignore_errors=True)
os.makedirs(wallets_dir)
os.makedirs(ringdb_dir)
os.makedirs(data_dir)
os.makedirs(log_dir, exist_ok=True)
rpc_port, p2p_port, zmq_rpc_port, zmq_pub_port = reserve_ports(4)
daemon_log_path = os.path.join(log_dir, "monerod-regtest.log")
daemon_log = open(daemon_log_path, "ab")
daemon = None
block_pulse_stop = threading.Event()
block_pulse = None
try:
daemon = subprocess.Popen(
[
monerod,
"--regtest",
"--fixed-difficulty",
"1",
"--p2p-bind-ip",
"127.0.0.1",
"--p2p-bind-port",
str(p2p_port),
"--rpc-bind-ip",
"127.0.0.1",
"--rpc-bind-port",
str(rpc_port),
"--zmq-rpc-bind-ip",
"127.0.0.1",
"--zmq-rpc-bind-port",
str(zmq_rpc_port),
"--zmq-pub",
"tcp://127.0.0.1:{}".format(zmq_pub_port),
"--non-interactive",
"--offline",
"--disable-dns-checkpoints",
"--check-updates",
"disabled",
"--rpc-ssl",
"disabled",
"--data-dir",
data_dir,
"--log-level",
"1",
],
stdout=daemon_log,
stderr=subprocess.STDOUT,
)
wait_for_port(rpc_port)
env = os.environ.copy()
env["WALLETS_ROOT_DIR"] = wallets_dir
env["DAEMON_ADDRESS"] = "127.0.0.1:{}".format(rpc_port)
env["LIBWALLET_API_TESTS_RINGDB_DIR"] = ringdb_dir
generated = subprocess.check_output(
[test_exe, "--generate-test-wallets"],
cwd=run_dir,
env=env,
text=True,
)
generated_values = dict(
line.split("=", 1)
for line in generated.splitlines()
if line.startswith(("miner_address=", "pulse_miner_address="))
)
miner_address = generated_values["miner_address"].strip()
pulse_miner_address = generated_values["pulse_miner_address"].strip()
response = generate_blocks(rpc_port, miner_address, MINED_BLOCKS)
print("Generated regtest blocks to {}: {}".format(miner_address, response))
print("Current regtest height: {}".format(get_height(rpc_port)))
sys.stdout.flush()
wait_for_height(rpc_port, MINED_BLOCKS)
env.setdefault("GTEST_COLOR", "yes")
gtest_filter = env.get("LIBWALLET_API_TESTS_GTEST_FILTER", "*")
block_pulse = threading.Thread(target=pulse_blocks, args=(block_pulse_stop, rpc_port, pulse_miner_address))
block_pulse.start()
return subprocess.call(
[test_exe, "--gtest_filter={}".format(gtest_filter)],
cwd=run_dir,
env=env,
)
finally:
block_pulse_stop.set()
if block_pulse is not None:
block_pulse.join(timeout=10)
if daemon is not None:
stop_process(daemon)
daemon_log.close()
if __name__ == "__main__":
sys.exit(main())
+281 -209
View File
@@ -45,6 +45,8 @@
#include <boost/thread/thread.hpp>
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <atomic>
#include <functional>
@@ -59,10 +61,9 @@ namespace Consts
// TODO: get rid of hardcoded paths
const char * WALLET_NAME = "testwallet";
const char * WALLET_NAME_MAINNET = "testwallet_mainnet";
const char * WALLET_NAME_COPY = "testwallet_copy";
const char * WALLET_NAME_WITH_DIR = "walletdir/testwallet_test";
const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "/var/walletdir/testwallet_test";
const char * WALLET_NAME_WITH_DIR_NON_WRITABLE = "not_a_directory/testwallet_test";
const char * WALLET_PASS = "password";
const char * WALLET_PASS2 = "password22";
const char * WALLET_LANG = "English";
@@ -86,8 +87,9 @@ const uint64_t AMOUNT_1XMR = 1000000000000L;
const std::string PAYMENT_ID_EMPTY = "";
std::string TESTNET_DAEMON_ADDRESS = "localhost:38081";
std::string MAINNET_DAEMON_ADDRESS = "localhost:18081";
std::string DAEMON_ADDRESS;
Monero::NetworkType WALLET_NETWORK_TYPE = Monero::NetworkType::MAINNET;
std::string RING_DATABASE_DIR;
}
@@ -96,6 +98,32 @@ std::string MAINNET_DAEMON_ADDRESS = "localhost:18081";
using namespace Consts;
static void configure_wallet(Monero::Wallet *wallet)
{
if (!wallet)
return;
wallet->allowMismatchedDaemonVersion(true);
wallet->setRefreshFromBlockHeight(1);
if (!RING_DATABASE_DIR.empty())
wallet->setRingDatabase(RING_DATABASE_DIR);
}
static bool init_wallet(Monero::Wallet *wallet, const std::string &daemon_address)
{
configure_wallet(wallet);
if (!wallet || !wallet->init(daemon_address, 0))
return false;
// init() applies the new-wallet fast-sync height, so restore the fixture's
// explicit height afterwards to scan its pre-mined funding outputs.
wallet->setRefreshFromBlockHeight(1);
return true;
}
static bool init_wallet(Monero::Wallet *wallet)
{
return init_wallet(wallet, DAEMON_ADDRESS);
}
struct Utils
{
static void deleteWallet(const std::string & walletname)
@@ -129,7 +157,7 @@ struct Utils
static std::string get_wallet_address(const std::string &filename, const std::string &password)
{
Monero::WalletManager *wmgr = Monero::WalletManagerFactory::getWalletManager();
Monero::Wallet * w = wmgr->openWallet(filename, password, Monero::NetworkType::TESTNET);
Monero::Wallet * w = wmgr->openWallet(filename, password, WALLET_NETWORK_TYPE);
std::string result = w->mainAddress();
wmgr->closeWallet(w);
return result;
@@ -149,6 +177,7 @@ struct WalletManagerTest : public testing::Test
// Monero::WalletManagerFactory::setLogLevel(Monero::WalletManagerFactory::LogLevel_4);
Utils::deleteWallet(WALLET_NAME);
Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR).parent_path().string());
Utils::deleteDir(boost::filesystem::path(WALLET_NAME_WITH_DIR_NON_WRITABLE).parent_path().string());
}
@@ -160,25 +189,45 @@ struct WalletManagerTest : public testing::Test
};
struct WalletManagerMainnetTest : public testing::Test
static int generate_test_wallets()
{
Monero::WalletManager * wmgr;
boost::filesystem::create_directories(WALLETS_ROOT_DIR);
Monero::WalletManager *wmgr = Monero::WalletManagerFactory::getWalletManager();
std::string miner_address;
std::string pulse_miner_address;
WalletManagerMainnetTest()
for (int i = 1; i <= 6; ++i)
{
std::cout << __FUNCTION__ << std::endl;
wmgr = Monero::WalletManagerFactory::getWalletManager();
Utils::deleteWallet(WALLET_NAME_MAINNET);
const std::string wallet_name = WALLETS_ROOT_DIR + "/wallet_0" + std::to_string(i) + ".bin";
Utils::deleteWallet(wallet_name);
Monero::Wallet *wallet = wmgr->createWallet(wallet_name, TESTNET_WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
if (!wallet || wallet->status() != Monero::Wallet::Status_Ok)
{
std::cerr << "Failed to create wallet " << wallet_name;
if (wallet)
{
std::cerr << ": " << wallet->errorString();
wmgr->closeWallet(wallet);
}
std::cerr << std::endl;
return 1;
}
configure_wallet(wallet);
if (i == 5)
miner_address = wallet->mainAddress();
if (i == 6)
pulse_miner_address = wallet->mainAddress();
if (!wmgr->closeWallet(wallet))
{
std::cerr << "Failed to close wallet " << wallet_name << std::endl;
return 1;
}
}
~WalletManagerMainnetTest()
{
std::cout << __FUNCTION__ << std::endl;
}
};
std::cout << "miner_address=" << miner_address << std::endl;
std::cout << "pulse_miner_address=" << pulse_miner_address << std::endl;
return miner_address.empty() || pulse_miner_address.empty() ? 1 : 0;
}
struct WalletTest1 : public testing::Test
{
@@ -207,7 +256,7 @@ struct WalletTest2 : public testing::Test
TEST_F(WalletManagerTest, WalletManagerCreatesWallet)
{
Monero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(!wallet->seed().empty());
std::vector<std::string> words;
@@ -224,13 +273,14 @@ TEST_F(WalletManagerTest, WalletManagerCreatesWallet)
TEST_F(WalletManagerTest, WalletManagerOpensWallet)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet2->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
std::cout << "** seed: " << wallet2->seed() << std::endl;
ASSERT_TRUE(wmgr->closeWallet(wallet2));
}
@@ -260,9 +310,12 @@ void open_wallet_helper(Monero::WalletManager *wmgr, Monero::Wallet **wallet, co
if (mutex)
mutex->lock();
LOG_PRINT_L3("opening wallet in thread: " << boost::this_thread::get_id());
*wallet = wmgr->openWallet(WALLET_NAME, pass, Monero::NetworkType::TESTNET);
*wallet = wmgr->openWallet(WALLET_NAME, pass, WALLET_NETWORK_TYPE);
if (*wallet)
{
LOG_PRINT_L3("wallet address: " << (*wallet)->mainAddress());
LOG_PRINT_L3("wallet status: " << (*wallet)->status());
}
LOG_PRINT_L3("closing wallet in thread: " << boost::this_thread::get_id());
if (mutex)
mutex->unlock();
@@ -276,7 +329,7 @@ void open_wallet_helper(Monero::WalletManager *wmgr, Monero::Wallet **wallet, co
// // create password protected wallet
// std::string wallet_pass = "password";
// std::string wrong_wallet_pass = "1111";
// Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, wallet_pass, WALLET_LANG, Monero::NetworkType::TESTNET);
// Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, wallet_pass, WALLET_LANG, WALLET_NETWORK_TYPE);
// std::string seed1 = wallet1->seed();
// ASSERT_TRUE(wmgr->closeWallet(wallet1));
@@ -302,7 +355,7 @@ TEST_F(WalletManagerTest, WalletManagerOpensWalletWithPasswordAndReopen)
// create password protected wallet
std::string wallet_pass = "password";
std::string wrong_wallet_pass = "1111";
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, wallet_pass, WALLET_LANG, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, wallet_pass, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
ASSERT_TRUE(wmgr->closeWallet(wallet1));
@@ -325,57 +378,63 @@ TEST_F(WalletManagerTest, WalletManagerOpensWalletWithPasswordAndReopen)
TEST_F(WalletManagerTest, WalletManagerStoresWallet)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
wallet1->store("");
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet2->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wmgr->closeWallet(wallet2));
}
TEST_F(WalletManagerTest, WalletManagerMovesWallet)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
std::string WALLET_NAME_MOVED = std::string("/tmp/") + WALLET_NAME + ".moved";
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
const std::string WALLET_NAME_MOVED =
(boost::filesystem::temp_directory_path() / (std::string(WALLET_NAME) + ".moved")).string();
Utils::deleteWallet(WALLET_NAME_MOVED);
std::string seed1 = wallet1->seed();
ASSERT_TRUE(wallet1->store(WALLET_NAME_MOVED));
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_MOVED, WALLET_PASS, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_MOVED, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet2->filename() == WALLET_NAME_MOVED);
ASSERT_TRUE(wallet2->keysFilename() == WALLET_NAME_MOVED + ".keys");
ASSERT_TRUE(wallet2->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wmgr->closeWallet(wallet2));
}
TEST_F(WalletManagerTest, WalletManagerChangesPassword)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
ASSERT_TRUE(wallet1->setPassword(WALLET_PASS2));
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME, WALLET_PASS2, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet2->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wmgr->closeWallet(wallet2));
Monero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet3 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_FALSE(wallet3->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wmgr->closeWallet(wallet3));
}
TEST_F(WalletManagerTest, WalletManagerRecoversWallet)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
std::string address1 = wallet1->mainAddress();
ASSERT_FALSE(address1.empty());
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Utils::deleteWallet(WALLET_NAME);
Monero::Wallet * wallet2 = wmgr->recoveryWallet(WALLET_NAME, seed1, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet2 = wmgr->recoveryWallet(WALLET_NAME, seed1, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet2->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wallet2->mainAddress() == address1);
@@ -422,14 +481,14 @@ TEST_F(WalletManagerTest, WalletManagerStoresPasswordOfWalletRecoveredFromKeys)
TEST_F(WalletManagerTest, WalletManagerStoresWallet1)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
std::string address1 = wallet1->mainAddress();
ASSERT_TRUE(wallet1->store(""));
ASSERT_TRUE(wallet1->store(WALLET_NAME_COPY));
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_COPY, WALLET_PASS, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet2 = wmgr->openWallet(WALLET_NAME_COPY, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet2->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet2->seed() == seed1);
ASSERT_TRUE(wallet2->mainAddress() == address1);
@@ -439,14 +498,14 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet1)
TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
std::string address1 = wallet1->mainAddress();
ASSERT_TRUE(wallet1->store(WALLET_NAME_WITH_DIR));
ASSERT_TRUE(wmgr->closeWallet(wallet1));
wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR, WALLET_PASS, Monero::NetworkType::MAINNET);
wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet1->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet1->seed() == seed1);
ASSERT_TRUE(wallet1->mainAddress() == address1);
@@ -456,20 +515,23 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet2)
TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
std::string address1 = wallet1->mainAddress();
const boost::filesystem::path parent = boost::filesystem::path(WALLET_NAME_WITH_DIR_NON_WRITABLE).parent_path();
boost::filesystem::remove_all(parent);
std::ofstream(parent.string()).close();
ASSERT_FALSE(wallet1->store(WALLET_NAME_WITH_DIR_NON_WRITABLE));
ASSERT_TRUE(wmgr->closeWallet(wallet1));
ASSERT_TRUE(wmgr->closeWallet(wallet1, false));
wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR_NON_WRITABLE, WALLET_PASS, Monero::NetworkType::MAINNET);
wallet1 = wmgr->openWallet(WALLET_NAME_WITH_DIR_NON_WRITABLE, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_FALSE(wallet1->status() == Monero::Wallet::Status_Ok);
// "close" always returns true;
ASSERT_TRUE(wmgr->closeWallet(wallet1));
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, Monero::NetworkType::MAINNET);
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet1->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet1->seed() == seed1);
ASSERT_TRUE(wallet1->mainAddress() == address1);
@@ -480,7 +542,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet3)
TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
{
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, Monero::NetworkType::MAINNET);
Monero::Wallet * wallet1 = wmgr->createWallet(WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
std::string seed1 = wallet1->seed();
std::string address1 = wallet1->mainAddress();
@@ -492,7 +554,7 @@ TEST_F(WalletManagerTest, WalletManagerStoresWallet4)
ASSERT_TRUE(wmgr->closeWallet(wallet1));
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, Monero::NetworkType::MAINNET);
wallet1 = wmgr->openWallet(WALLET_NAME, WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet1->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet1->seed() == seed1);
ASSERT_TRUE(wallet1->mainAddress() == address1);
@@ -512,6 +574,56 @@ TEST_F(WalletManagerTest, WalletManagerFindsWallet)
}
}
TEST_F(WalletManagerTest, WalletSubaddresses)
{
Monero::Wallet * wallet = wmgr->createWallet(
WALLET_NAME, WALLET_PASS, WALLET_LANG, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet != nullptr);
ASSERT_TRUE(wallet->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet->numSubaddressAccounts() == 1);
ASSERT_TRUE(wallet->numSubaddresses(0) == 1);
ASSERT_TRUE(wallet->address(0, 0) == wallet->mainAddress());
wallet->addSubaddress(0, "Savings");
ASSERT_TRUE(wallet->numSubaddresses(0) == 2);
ASSERT_TRUE(wallet->getSubaddressLabel(0, 1) == "Savings");
ASSERT_TRUE(wallet->address(0, 1) != wallet->mainAddress());
ASSERT_TRUE(Monero::Wallet::addressValid(wallet->address(0, 1), WALLET_NETWORK_TYPE));
wallet->addSubaddressAccount("Account 1");
ASSERT_TRUE(wallet->numSubaddressAccounts() == 2);
ASSERT_TRUE(wallet->numSubaddresses(1) == 1);
ASSERT_TRUE(wallet->getSubaddressLabel(1, 0) == "Account 1");
ASSERT_TRUE(Monero::Wallet::addressValid(wallet->address(1, 0), WALLET_NETWORK_TYPE));
Monero::Subaddress * subaddresses = wallet->subaddress();
subaddresses->refresh(0);
ASSERT_TRUE(subaddresses->getAll().size() == 2);
ASSERT_TRUE(subaddresses->getAll()[1]->getAddress() == wallet->address(0, 1));
ASSERT_TRUE(subaddresses->getAll()[1]->getLabel() == "Savings");
subaddresses->setLabel(0, 1, "Spending");
ASSERT_TRUE(wallet->getSubaddressLabel(0, 1) == "Spending");
subaddresses->addRow(0, "Donations");
ASSERT_TRUE(wallet->numSubaddresses(0) == 3);
ASSERT_TRUE(subaddresses->getAll()[2]->getLabel() == "Donations");
Monero::SubaddressAccount * accounts = wallet->subaddressAccount();
accounts->refresh();
ASSERT_TRUE(accounts->getAll().size() == 2);
ASSERT_TRUE(accounts->getAll()[1]->getAddress() == wallet->address(1, 0));
ASSERT_TRUE(accounts->getAll()[1]->getLabel() == "Account 1");
accounts->setLabel(1, "Secondary");
ASSERT_TRUE(wallet->getSubaddressLabel(1, 0) == "Secondary");
accounts->addRow("Account 2");
ASSERT_TRUE(wallet->numSubaddressAccounts() == 3);
ASSERT_TRUE(accounts->getAll()[2]->getLabel() == "Account 2");
ASSERT_TRUE(wmgr->closeWallet(wallet));
}
TEST_F(WalletTest1, WalletGeneratesPaymentId)
{
@@ -524,22 +636,26 @@ TEST_F(WalletTest1, WalletGeneratesIntegratedAddress)
{
std::string payment_id = Monero::Wallet::genPaymentId();
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
std::string integrated_address = wallet1->integratedAddress(payment_id);
ASSERT_TRUE(integrated_address.length() == 106);
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
TEST_F(WalletTest1, WalletShowsBalance)
{
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(init_wallet(wallet1));
ASSERT_TRUE(wallet1->refresh());
ASSERT_TRUE(wallet1->balance(0) > 0);
ASSERT_TRUE(wallet1->unlockedBalance(0) > 0);
uint64_t balance1 = wallet1->balance(0);
uint64_t unlockedBalance1 = wallet1->unlockedBalance(0);
ASSERT_TRUE(wmgr->closeWallet(wallet1));
Monero::Wallet * wallet2 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet2 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
configure_wallet(wallet2);
ASSERT_TRUE(balance1 == wallet2->balance(0));
std::cout << "wallet balance: " << wallet2->balance(0) << std::endl;
@@ -550,7 +666,7 @@ TEST_F(WalletTest1, WalletShowsBalance)
TEST_F(WalletTest1, WalletReturnsCurrentBlockHeight)
{
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet1->blockChainHeight() > 0);
wmgr->closeWallet(wallet1);
}
@@ -558,16 +674,17 @@ TEST_F(WalletTest1, WalletReturnsCurrentBlockHeight)
TEST_F(WalletTest1, WalletReturnsDaemonBlockHeight)
{
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// wallet not connected to daemon
configure_wallet(wallet1);
ASSERT_TRUE(wallet1->daemonBlockChainHeight() == 0);
ASSERT_TRUE(wallet1->status() != Monero::Wallet::Status_Ok);
ASSERT_FALSE(wallet1->errorString().empty());
ASSERT_TRUE(wallet1->status() == Monero::Wallet::Status_Ok);
wmgr->closeWallet(wallet1);
wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// wallet connected to daemon
wallet1->init(TESTNET_DAEMON_ADDRESS, 0);
init_wallet(wallet1);
ASSERT_TRUE(wallet1->refresh());
ASSERT_TRUE(wallet1->daemonBlockChainHeight() > 0);
std::cout << "daemonBlockChainHeight: " << wallet1->daemonBlockChainHeight() << std::endl;
wmgr->closeWallet(wallet1);
@@ -578,10 +695,10 @@ TEST_F(WalletTest1, WalletRefresh)
{
std::cout << "Opening wallet: " << CURRENT_SRC_WALLET << std::endl;
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
std::cout << "connecting to daemon: " << TESTNET_DAEMON_ADDRESS << std::endl;
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
std::cout << "connecting to daemon: " << DAEMON_ADDRESS << std::endl;
ASSERT_TRUE(init_wallet(wallet1));
ASSERT_TRUE(wallet1->refresh());
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
@@ -602,9 +719,9 @@ TEST_F(WalletTest1, WalletConvertsToString)
TEST_F(WalletTest1, WalletTransaction)
{
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet1));
ASSERT_TRUE(wallet1->refresh());
uint64_t balance = wallet1->balance(0);
ASSERT_TRUE(wallet1->status() == Monero::PendingTransaction::Status_Ok);
@@ -644,11 +761,11 @@ TEST_F(WalletTest1, WalletTransactionWithMixin)
std::string payment_id = "";
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet1));
ASSERT_TRUE(wallet1->refresh());
uint64_t balance = wallet1->balance(0);
ASSERT_TRUE(wallet1->status() == Monero::PendingTransaction::Status_Ok);
@@ -678,10 +795,10 @@ TEST_F(WalletTest1, WalletTransactionWithPriority)
std::string payment_id = "";
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet1));
ASSERT_TRUE(wallet1->refresh());
uint64_t balance = wallet1->balance(0);
ASSERT_TRUE(wallet1->status() == Monero::PendingTransaction::Status_Ok);
@@ -718,9 +835,9 @@ TEST_F(WalletTest1, WalletTransactionWithPriority)
TEST_F(WalletTest1, WalletHistory)
{
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet1 = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet1->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet1));
ASSERT_TRUE(wallet1->refresh());
Monero::TransactionHistory * history = wallet1->history();
history->refresh();
@@ -731,14 +848,15 @@ TEST_F(WalletTest1, WalletHistory)
ASSERT_TRUE(t != nullptr);
Utils::print_transaction(t);
}
ASSERT_TRUE(wmgr->closeWallet(wallet1));
}
TEST_F(WalletTest1, WalletTransactionAndHistory)
{
return;
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->refresh());
Monero::TransactionHistory * history = wallet_src->history();
history->refresh();
@@ -775,9 +893,9 @@ TEST_F(WalletTest1, WalletTransactionAndHistory)
TEST_F(WalletTest1, WalletTransactionWithPaymentId)
{
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->refresh());
Monero::TransactionHistory * history = wallet_src->history();
history->refresh();
@@ -790,16 +908,21 @@ TEST_F(WalletTest1, WalletTransactionWithPaymentId)
Utils::print_transaction(t);
}
std::string wallet4_addr = Utils::get_wallet_address(CURRENT_DST_WALLET, TESTNET_WALLET_PASS);
std::string payment_id = Monero::Wallet::genPaymentId();
ASSERT_TRUE(payment_id.length() == 16);
Monero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet_dst != nullptr);
std::string integrated_address = wallet_dst->integratedAddress(payment_id);
ASSERT_FALSE(integrated_address.empty());
ASSERT_TRUE(wmgr->closeWallet(wallet_dst));
Monero::PendingTransaction * tx = wallet_src->createTransaction(wallet4_addr,
payment_id,
Monero::PendingTransaction * tx = wallet_src->createTransaction(integrated_address,
PAYMENT_ID_EMPTY,
AMOUNT_1XMR, 1, Monero::PendingTransaction::Priority_Medium, 0, std::set<uint32_t>{});
std::cerr << "Transaction status: " << tx->status() << std::endl;
std::cerr << "Transaction fee: " << Monero::Wallet::displayAmount(tx->fee()) << std::endl;
std::cerr << "Transaction error: " << tx->errorString() << std::endl;
ASSERT_TRUE(tx->status() == Monero::PendingTransaction::Status_Ok);
ASSERT_TRUE(tx->commit());
history = wallet_src->history();
@@ -818,6 +941,49 @@ TEST_F(WalletTest1, WalletTransactionWithPaymentId)
}
ASSERT_TRUE(payment_id_in_history);
ASSERT_TRUE(wmgr->closeWallet(wallet_src));
}
TEST_F(WalletTest1, WalletTransactionMultDestWithPaymentId)
{
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->refresh());
Monero::TransactionHistory * history = wallet_src->history();
history->refresh();
size_t count = history->count();
std::string payment_id = Monero::Wallet::genPaymentId();
ASSERT_TRUE(payment_id.length() == 16);
Monero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(wallet_dst != nullptr);
std::string integrated_address = wallet_dst->integratedAddress(payment_id);
ASSERT_FALSE(integrated_address.empty());
ASSERT_TRUE(wmgr->closeWallet(wallet_dst));
const std::vector<std::string> destinations{integrated_address, wallet_src->mainAddress()};
const std::vector<uint64_t> amounts{AMOUNT_1XMR, AMOUNT_1XMR};
Monero::PendingTransaction * tx = wallet_src->createTransactionMultDest(
destinations, PAYMENT_ID_EMPTY, amounts, 1,
Monero::PendingTransaction::Priority_Medium, 0, std::set<uint32_t>{});
std::cerr << "Transaction status: " << tx->status() << std::endl;
std::cerr << "Transaction fee: " << Monero::Wallet::displayAmount(tx->fee()) << std::endl;
std::cerr << "Transaction error: " << tx->errorString() << std::endl;
ASSERT_TRUE(tx->status() == Monero::PendingTransaction::Status_Ok);
ASSERT_TRUE(tx->commit());
history->refresh();
ASSERT_TRUE(count != history->count());
bool payment_id_in_history = false;
for (auto t: history->getAll()) {
ASSERT_TRUE(t != nullptr);
if (t->paymentId() == payment_id) {
payment_id_in_history = true;
}
}
ASSERT_TRUE(payment_id_in_history);
ASSERT_TRUE(wmgr->closeWallet(wallet_src));
}
@@ -917,14 +1083,13 @@ struct MyWalletListener : public Monero::WalletListener
TEST_F(WalletTest2, WalletCallBackRefreshedSync)
{
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(wallet_src_listener->refresh_triggered);
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->connected());
boost::chrono::seconds wait_for = boost::chrono::seconds(60*3);
boost::unique_lock<boost::mutex> lock (wallet_src_listener->mutex);
wallet_src_listener->cv_refresh.wait_for(lock, wait_for);
wallet_src_listener->reset();
ASSERT_TRUE(wallet_src->refresh());
ASSERT_TRUE(wallet_src_listener->refresh_triggered);
wmgr->closeWallet(wallet_src);
}
@@ -934,12 +1099,12 @@ TEST_F(WalletTest2, WalletCallBackRefreshedSync)
TEST_F(WalletTest2, WalletCallBackRefreshedAsync)
{
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
boost::chrono::seconds wait_for = boost::chrono::seconds(20);
boost::unique_lock<boost::mutex> lock (wallet_src_listener->mutex);
wallet_src->init(MAINNET_DAEMON_ADDRESS, 0);
init_wallet(wallet_src);
wallet_src->startRefresh();
std::cerr << "TEST: waiting on refresh lock...\n";
wallet_src_listener->cv_refresh.wait_for(lock, wait_for);
@@ -956,14 +1121,14 @@ TEST_F(WalletTest2, WalletCallBackRefreshedAsync)
TEST_F(WalletTest2, WalletCallbackSent)
{
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->refresh());
MyWalletListener * wallet_src_listener = new MyWalletListener(wallet_src);
uint64_t balance = wallet_src->balance(0);
std::cout << "** Balance: " << wallet_src->displayAmount(wallet_src->balance(0)) << std::endl;
Monero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
uint64_t amount = AMOUNT_1XMR * 5;
std::cout << "** Sending " << Monero::Wallet::displayAmount(amount) << " to " << wallet_dst->mainAddress();
@@ -978,7 +1143,8 @@ TEST_F(WalletTest2, WalletCallbackSent)
ASSERT_TRUE(tx->status() == Monero::PendingTransaction::Status_Ok);
ASSERT_TRUE(tx->commit());
boost::chrono::seconds wait_for = boost::chrono::seconds(60*3);
wallet_src->startRefresh();
boost::chrono::seconds wait_for = boost::chrono::seconds(20);
boost::unique_lock<boost::mutex> lock (wallet_src_listener->mutex);
std::cerr << "TEST: waiting on send lock...\n";
wallet_src_listener->cv_send.wait_for(lock, wait_for);
@@ -995,14 +1161,14 @@ TEST_F(WalletTest2, WalletCallbackSent)
TEST_F(WalletTest2, WalletCallbackReceived)
{
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(CURRENT_SRC_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->refresh());
std::cout << "** Balance src1: " << wallet_src->displayAmount(wallet_src->balance(0)) << std::endl;
Monero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
ASSERT_TRUE(wallet_dst->init(TESTNET_DAEMON_ADDRESS, 0));
Monero::Wallet * wallet_dst = wmgr->openWallet(CURRENT_DST_WALLET, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
ASSERT_TRUE(init_wallet(wallet_dst));
ASSERT_TRUE(wallet_dst->refresh());
uint64_t balance = wallet_dst->balance(0);
std::cout << "** Balance dst1: " << wallet_dst->displayAmount(wallet_dst->balance(0)) << std::endl;
@@ -1020,7 +1186,8 @@ TEST_F(WalletTest2, WalletCallbackReceived)
ASSERT_TRUE(tx->status() == Monero::PendingTransaction::Status_Ok);
ASSERT_TRUE(tx->commit());
boost::chrono::seconds wait_for = boost::chrono::seconds(60*4);
wallet_dst->startRefresh();
boost::chrono::seconds wait_for = boost::chrono::seconds(20);
boost::unique_lock<boost::mutex> lock (wallet_dst_listener->mutex);
std::cerr << "TEST: waiting on receive lock...\n";
wallet_dst_listener->cv_receive.wait_for(lock, wait_for);
@@ -1042,9 +1209,9 @@ TEST_F(WalletTest2, WalletCallbackReceived)
TEST_F(WalletTest2, WalletCallbackNewBlock)
{
Monero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET5_NAME, TESTNET_WALLET_PASS, Monero::NetworkType::TESTNET);
Monero::Wallet * wallet_src = wmgr->openWallet(TESTNET_WALLET5_NAME, TESTNET_WALLET_PASS, WALLET_NETWORK_TYPE);
// make sure testnet daemon is running
ASSERT_TRUE(wallet_src->init(TESTNET_DAEMON_ADDRESS, 0));
ASSERT_TRUE(init_wallet(wallet_src));
ASSERT_TRUE(wallet_src->refresh());
uint64_t bc1 = wallet_src->blockChainHeight();
std::cout << "** Block height: " << bc1 << std::endl;
@@ -1052,8 +1219,8 @@ TEST_F(WalletTest2, WalletCallbackNewBlock)
std::unique_ptr<MyWalletListener> wallet_listener (new MyWalletListener(wallet_src));
// wait max 4 min for new block
boost::chrono::seconds wait_for = boost::chrono::seconds(60*4);
wallet_src->startRefresh();
boost::chrono::seconds wait_for = boost::chrono::seconds(20);
boost::unique_lock<boost::mutex> lock (wallet_listener->mutex);
std::cerr << "TEST: waiting on newblock lock...\n";
wallet_listener->cv_newblock.wait_for(lock, wait_for);
@@ -1066,128 +1233,27 @@ TEST_F(WalletTest2, WalletCallbackNewBlock)
}
TEST_F(WalletManagerMainnetTest, CreateOpenAndRefreshWalletMainNetSync)
{
Monero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG, Monero::NetworkType::MAINNET);
std::unique_ptr<MyWalletListener> wallet_listener (new MyWalletListener(wallet));
wallet->init(MAINNET_DAEMON_ADDRESS, 0);
std::cerr << "TEST: waiting on refresh lock...\n";
//wallet_listener->cv_refresh.wait_for(lock, wait_for);
std::cerr << "TEST: refresh lock acquired...\n";
ASSERT_TRUE(wallet_listener->refresh_triggered);
ASSERT_TRUE(wallet->connected());
ASSERT_TRUE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight());
std::cerr << "TEST: closing wallet...\n";
wmgr->closeWallet(wallet);
}
TEST_F(WalletManagerMainnetTest, CreateAndRefreshWalletMainNetAsync)
{
// supposing 120 seconds should be enough for fast refresh
int SECONDS_TO_REFRESH = 120;
Monero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG, Monero::NetworkType::MAINNET);
std::unique_ptr<MyWalletListener> wallet_listener (new MyWalletListener(wallet));
boost::chrono::seconds wait_for = boost::chrono::seconds(SECONDS_TO_REFRESH);
boost::unique_lock<boost::mutex> lock (wallet_listener->mutex);
wallet->init(MAINNET_DAEMON_ADDRESS, 0);
wallet->startRefresh();
std::cerr << "TEST: waiting on refresh lock...\n";
wallet_listener->cv_refresh.wait_for(lock, wait_for);
std::cerr << "TEST: refresh lock acquired...\n";
ASSERT_TRUE(wallet->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet_listener->refresh_triggered);
ASSERT_TRUE(wallet->connected());
ASSERT_TRUE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight());
std::cerr << "TEST: closing wallet...\n";
wmgr->closeWallet(wallet);
}
TEST_F(WalletManagerMainnetTest, OpenAndRefreshWalletMainNetAsync)
{
// supposing 120 seconds should be enough for fast refresh
int SECONDS_TO_REFRESH = 120;
Monero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG, Monero::NetworkType::MAINNET);
wmgr->closeWallet(wallet);
wallet = wmgr->openWallet(WALLET_NAME_MAINNET, "", Monero::NetworkType::MAINNET);
std::unique_ptr<MyWalletListener> wallet_listener (new MyWalletListener(wallet));
boost::chrono::seconds wait_for = boost::chrono::seconds(SECONDS_TO_REFRESH);
boost::unique_lock<boost::mutex> lock (wallet_listener->mutex);
wallet->init(MAINNET_DAEMON_ADDRESS, 0);
wallet->startRefresh();
std::cerr << "TEST: waiting on refresh lock...\n";
wallet_listener->cv_refresh.wait_for(lock, wait_for);
std::cerr << "TEST: refresh lock acquired...\n";
ASSERT_TRUE(wallet->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet_listener->refresh_triggered);
ASSERT_TRUE(wallet->connected());
ASSERT_TRUE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight());
std::cerr << "TEST: closing wallet...\n";
wmgr->closeWallet(wallet);
}
TEST_F(WalletManagerMainnetTest, RecoverAndRefreshWalletMainNetAsync)
{
// supposing 120 seconds should be enough for fast refresh
int SECONDS_TO_REFRESH = 120;
Monero::Wallet * wallet = wmgr->createWallet(WALLET_NAME_MAINNET, "", WALLET_LANG, Monero::NetworkType::MAINNET);
std::string seed = wallet->seed();
std::string address = wallet->mainAddress();
wmgr->closeWallet(wallet);
// deleting wallet files
Utils::deleteWallet(WALLET_NAME_MAINNET);
// ..and recovering wallet from seed
wallet = wmgr->recoveryWallet(WALLET_NAME_MAINNET, seed, Monero::NetworkType::MAINNET);
ASSERT_TRUE(wallet->status() == Monero::Wallet::Status_Ok);
ASSERT_TRUE(wallet->mainAddress() == address);
std::unique_ptr<MyWalletListener> wallet_listener (new MyWalletListener(wallet));
boost::chrono::seconds wait_for = boost::chrono::seconds(SECONDS_TO_REFRESH);
boost::unique_lock<boost::mutex> lock (wallet_listener->mutex);
wallet->init(MAINNET_DAEMON_ADDRESS, 0);
wallet->startRefresh();
std::cerr << "TEST: waiting on refresh lock...\n";
// here we wait for 120 seconds and test if wallet doesn't syncrnonize blockchain completely,
// as it needs much more than 120 seconds for mainnet
wallet_listener->cv_refresh.wait_for(lock, wait_for);
ASSERT_TRUE(wallet->status() == Monero::Wallet::Status_Ok);
ASSERT_FALSE(wallet_listener->refresh_triggered);
ASSERT_TRUE(wallet->connected());
ASSERT_FALSE(wallet->blockChainHeight() == wallet->daemonBlockChainHeight());
std::cerr << "TEST: closing wallet...\n";
wmgr->closeWallet(wallet);
std::cerr << "TEST: wallet closed\n";
}
int main(int argc, char** argv)
{
TRY_ENTRY();
tools::on_startup();
// we can override default values for "TESTNET_DAEMON_ADDRESS" and "WALLETS_ROOT_DIR"
// The CTest wrapper runs these tests against a fresh fakechain daemon.
const char * testnet_daemon_addr = std::getenv("TESTNET_DAEMON_ADDRESS");
if (testnet_daemon_addr) {
TESTNET_DAEMON_ADDRESS = testnet_daemon_addr;
const char *daemon_addr = std::getenv("DAEMON_ADDRESS");
if (daemon_addr && daemon_addr[0])
{
DAEMON_ADDRESS = daemon_addr;
}
else
{
std::cerr << "DAEMON_ADDRESS must be set" << std::endl;
return 1;
}
const char * mainnet_daemon_addr = std::getenv("MAINNET_DAEMON_ADDRESS");
if (mainnet_daemon_addr) {
MAINNET_DAEMON_ADDRESS = mainnet_daemon_addr;
const char * ring_database_dir = std::getenv("LIBWALLET_API_TESTS_RINGDB_DIR");
if (ring_database_dir) {
RING_DATABASE_DIR = ring_database_dir;
}
@@ -1208,6 +1274,12 @@ int main(int argc, char** argv)
CURRENT_SRC_WALLET = TESTNET_WALLET5_NAME;
CURRENT_DST_WALLET = TESTNET_WALLET1_NAME;
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--generate-test-wallets") == 0)
return generate_test_wallets();
}
::testing::InitGoogleTest(&argc, argv);
Monero::WalletManagerFactory::setLogLevel(Monero::WalletManagerFactory::LogLevel_Max);
return RUN_ALL_TESTS();
@@ -1,24 +0,0 @@
# Running libwallet_api tests
## Environment for the tests
* Running monero node, linked to private/public testnet.
By default, tests expect daemon running at ```localhost:38081```,
can be overridden with environment variable ```TESTNET_DAEMON_ADDRESS=<your_daemon_address>```
[Manual](https://github.com/moneroexamples/private-testnet) explaining how to run private testnet.
* Directory with pre-generated wallets
(wallet_01.bin, wallet_02.bin,...,wallet_06.bin, some of these wallets might not be used in the tests currently).
By default, tests expect these wallets to be in ```/var/monero/testnet_pvt```.
Directory can be overridden with environment variable ```WALLETS_ROOT_DIR=<your_directory_with_wallets>```.
Directory and files should be writable for the user running tests.
## Generating test wallets
* ```create_wallets.sh``` - this script will create wallets (wallet_01.bin, wallet_02.bin,...,wallet_06.bin) in current directory.
when running first time, please uncomment line ```#create_wallet wallet_m``` to create miner wallet as well.
This wallet should be used for mining and all test wallets supposed to be seed from this miner wallet
* ```mining_start.sh``` and ```mining_stop.sh``` - helper scripts to start and stop mining on miner wallet
* ```send_funds.sh``` - script for seeding test wallets. Please run this script when you have enough money on miner wallet
@@ -1,18 +0,0 @@
#!/bin/bash
function create_wallet {
wallet_name=$1
echo 0 | monero-wallet-cli --testnet --trusted-daemon --daemon-address localhost:38081 --generate-new-wallet $wallet_name --password "" --restore-height=1
}
create_wallet wallet_01.bin
create_wallet wallet_02.bin
create_wallet wallet_03.bin
create_wallet wallet_04.bin
create_wallet wallet_05.bin
create_wallet wallet_06.bin
# create_wallet wallet_m
@@ -1,4 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log start_mining
@@ -1,4 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_miner.log stop_mining
@@ -1,5 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_01.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log
@@ -1,5 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_02.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_01.log
@@ -1,4 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_03.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_03.log
@@ -1,4 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_04.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_04.log
@@ -1,4 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_05.bin --password "" --testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_05.log
@@ -1,4 +0,0 @@
#!/bin/bash
rlwrap monero-wallet-cli --wallet-file wallet_m --password "" --testnet --trusted-daemon --daemon-address 127.0.0.1:38081 --log-file wallet_m.log
@@ -1,32 +0,0 @@
#!/bin/bash
function send_funds {
local amount=$1
local dest=$(cat "$2.address.txt")
monero-wallet-cli --wallet-file wallet_m --password "" \
--testnet --trusted-daemon --daemon-address localhost:38081 --log-file wallet_m.log \
--command transfer $dest $amount
}
function seed_wallets {
local amount=$1
send_funds $amount wallet_01.bin
send_funds $amount wallet_02.bin
send_funds $amount wallet_03.bin
send_funds $amount wallet_04.bin
send_funds $amount wallet_05.bin
send_funds $amount wallet_06.bin
}
seed_wallets 1
seed_wallets 2
seed_wallets 5
seed_wallets 10
seed_wallets 20
seed_wallets 50
seed_wallets 100